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:
commit
39f2657d11
71 changed files with 284 additions and 461 deletions
|
@ -3861,6 +3861,8 @@ Version 1.41.1 (2020-02-27)
|
||||||
* [Always check types of static items][69145]
|
* [Always check types of static items][69145]
|
||||||
* [Always check lifetime bounds of `Copy` impls][69145]
|
* [Always check lifetime bounds of `Copy` impls][69145]
|
||||||
* [Fix miscompilation in callers of `Layout::repeat`][69225]
|
* [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
|
[69225]: https://github.com/rust-lang/rust/issues/69225
|
||||||
[69145]: https://github.com/rust-lang/rust/pull/69145
|
[69145]: https://github.com/rust-lang/rust/pull/69145
|
||||||
|
@ -3953,7 +3955,7 @@ Misc
|
||||||
Compatibility Notes
|
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
|
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
|
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.
|
binaries for those platforms will no longer be distributed by the Rust project.
|
||||||
|
|
|
@ -118,15 +118,6 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
|
||||||
LocalMutationIsAllowed::Yes,
|
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 {
|
TerminatorKind::Call {
|
||||||
func,
|
func,
|
||||||
args,
|
args,
|
||||||
|
|
|
@ -743,15 +743,6 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
|
||||||
flow_state,
|
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 {
|
TerminatorKind::Call {
|
||||||
func,
|
func,
|
||||||
args,
|
args,
|
||||||
|
@ -866,7 +857,6 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
|
||||||
| TerminatorKind::Assert { .. }
|
| TerminatorKind::Assert { .. }
|
||||||
| TerminatorKind::Call { .. }
|
| TerminatorKind::Call { .. }
|
||||||
| TerminatorKind::Drop { .. }
|
| TerminatorKind::Drop { .. }
|
||||||
| TerminatorKind::DropAndReplace { .. }
|
|
||||||
| TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ }
|
| TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ }
|
||||||
| TerminatorKind::FalseUnwind { real_target: _, unwind: _ }
|
| TerminatorKind::FalseUnwind { real_target: _, unwind: _ }
|
||||||
| TerminatorKind::Goto { .. }
|
| TerminatorKind::Goto { .. }
|
||||||
|
|
|
@ -435,8 +435,7 @@ impl<'me, 'typeck, 'flow, 'tcx> LivenessResults<'me, 'typeck, 'flow, 'tcx> {
|
||||||
//
|
//
|
||||||
// What we *actually* generate is a store to a temporary
|
// What we *actually* generate is a store to a temporary
|
||||||
// for the call (`TMP = call()...`) and then a
|
// for the call (`TMP = call()...`) and then a
|
||||||
// `DropAndReplace` to swap that with `X`
|
// `Drop(X)` followed by `X = TMP` to swap that with `X`.
|
||||||
// (`DropAndReplace` has very particular semantics).
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1312,24 +1312,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
// no checks needed for these
|
// 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, .. } => {
|
TerminatorKind::SwitchInt { discr, .. } => {
|
||||||
self.check_operand(discr, term_location);
|
self.check_operand(discr, term_location);
|
||||||
|
|
||||||
|
@ -1629,7 +1611,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
TerminatorKind::Unreachable => {}
|
TerminatorKind::Unreachable => {}
|
||||||
TerminatorKind::Drop { target, unwind, .. }
|
TerminatorKind::Drop { target, unwind, .. }
|
||||||
| TerminatorKind::DropAndReplace { target, unwind, .. }
|
|
||||||
| TerminatorKind::Assert { target, cleanup: unwind, .. } => {
|
| TerminatorKind::Assert { target, cleanup: unwind, .. } => {
|
||||||
self.assert_iscleanup(body, block_data, target, is_cleanup);
|
self.assert_iscleanup(body, block_data, target, is_cleanup);
|
||||||
if let Some(unwind) = unwind {
|
if let Some(unwind) = unwind {
|
||||||
|
|
|
@ -71,9 +71,6 @@ impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tc
|
||||||
TerminatorKind::Call { destination, .. } => {
|
TerminatorKind::Call { destination, .. } => {
|
||||||
self.remove_never_initialized_mut_locals(*destination);
|
self.remove_never_initialized_mut_locals(*destination);
|
||||||
}
|
}
|
||||||
TerminatorKind::DropAndReplace { place, .. } => {
|
|
||||||
self.remove_never_initialized_mut_locals(*place);
|
|
||||||
}
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -499,7 +499,6 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
|
||||||
TerminatorKind::Yield { .. }
|
TerminatorKind::Yield { .. }
|
||||||
| TerminatorKind::FalseEdge { .. }
|
| TerminatorKind::FalseEdge { .. }
|
||||||
| TerminatorKind::FalseUnwind { .. }
|
| TerminatorKind::FalseUnwind { .. }
|
||||||
| TerminatorKind::DropAndReplace { .. }
|
|
||||||
| TerminatorKind::GeneratorDrop => {
|
| TerminatorKind::GeneratorDrop => {
|
||||||
bug!("shouldn't exist at codegen {:?}", bb_data.terminator());
|
bug!("shouldn't exist at codegen {:?}", bb_data.terminator());
|
||||||
}
|
}
|
||||||
|
|
|
@ -543,8 +543,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
|
||||||
| TerminatorKind::Unreachable
|
| TerminatorKind::Unreachable
|
||||||
| TerminatorKind::Drop { .. }
|
| TerminatorKind::Drop { .. }
|
||||||
| TerminatorKind::Assert { .. } => {}
|
| TerminatorKind::Assert { .. } => {}
|
||||||
TerminatorKind::DropAndReplace { .. }
|
TerminatorKind::Yield { .. }
|
||||||
| TerminatorKind::Yield { .. }
|
|
||||||
| TerminatorKind::GeneratorDrop
|
| TerminatorKind::GeneratorDrop
|
||||||
| TerminatorKind::FalseEdge { .. }
|
| TerminatorKind::FalseEdge { .. }
|
||||||
| TerminatorKind::FalseUnwind { .. } => unreachable!(),
|
| TerminatorKind::FalseUnwind { .. } => unreachable!(),
|
||||||
|
|
|
@ -295,7 +295,6 @@ pub fn cleanup_kinds(mir: &mir::Body<'_>) -> IndexVec<mir::BasicBlock, CleanupKi
|
||||||
TerminatorKind::Call { cleanup: unwind, .. }
|
TerminatorKind::Call { cleanup: unwind, .. }
|
||||||
| TerminatorKind::InlineAsm { cleanup: unwind, .. }
|
| TerminatorKind::InlineAsm { cleanup: unwind, .. }
|
||||||
| TerminatorKind::Assert { cleanup: unwind, .. }
|
| TerminatorKind::Assert { cleanup: unwind, .. }
|
||||||
| TerminatorKind::DropAndReplace { unwind, .. }
|
|
||||||
| TerminatorKind::Drop { unwind, .. } => {
|
| TerminatorKind::Drop { unwind, .. } => {
|
||||||
if let Some(unwind) = unwind {
|
if let Some(unwind) = unwind {
|
||||||
debug!(
|
debug!(
|
||||||
|
|
|
@ -1305,10 +1305,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
mergeable_succ(),
|
mergeable_succ(),
|
||||||
),
|
),
|
||||||
|
|
||||||
mir::TerminatorKind::DropAndReplace { .. } => {
|
|
||||||
bug!("undesugared DropAndReplace in codegen: {:?}", terminator);
|
|
||||||
}
|
|
||||||
|
|
||||||
mir::TerminatorKind::Call {
|
mir::TerminatorKind::Call {
|
||||||
ref func,
|
ref func,
|
||||||
ref args,
|
ref args,
|
||||||
|
|
|
@ -171,11 +171,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
Unreachable => throw_ub!(Unreachable),
|
Unreachable => throw_ub!(Unreachable),
|
||||||
|
|
||||||
// These should never occur for MIR we actually run.
|
// 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,
|
terminator.source_info.span,
|
||||||
"{:#?} should have been eliminated by MIR pass",
|
"{:#?} should have been eliminated by MIR pass",
|
||||||
terminator.kind
|
terminator.kind
|
||||||
|
|
|
@ -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
|
// Forbid all `Drop` terminators unless the place being dropped is a local with no
|
||||||
// projections that cannot be `NeedsNonConstDrop`.
|
// projections that cannot be `NeedsNonConstDrop`.
|
||||||
TerminatorKind::Drop { place: dropped_place, .. }
|
TerminatorKind::Drop { place: dropped_place, .. } => {
|
||||||
| TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
|
|
||||||
// If we are checking live drops after drop-elaboration, don't emit duplicate
|
// If we are checking live drops after drop-elaboration, don't emit duplicate
|
||||||
// errors here.
|
// errors here.
|
||||||
if super::post_drop_elaboration::checking_enabled(self.ccx) {
|
if super::post_drop_elaboration::checking_enabled(self.ccx) {
|
||||||
|
|
|
@ -80,8 +80,7 @@ impl<'tcx> Visitor<'tcx> for CheckLiveDrops<'_, 'tcx> {
|
||||||
trace!("visit_terminator: terminator={:?} location={:?}", terminator, location);
|
trace!("visit_terminator: terminator={:?} location={:?}", terminator, location);
|
||||||
|
|
||||||
match &terminator.kind {
|
match &terminator.kind {
|
||||||
mir::TerminatorKind::Drop { place: dropped_place, .. }
|
mir::TerminatorKind::Drop { place: dropped_place, .. } => {
|
||||||
| mir::TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
|
|
||||||
let dropped_ty = dropped_place.ty(self.body, self.tcx).ty;
|
let dropped_ty = dropped_place.ty(self.body, self.tcx).ty;
|
||||||
if !NeedsNonConstDrop::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
|
// Instead of throwing a bug, we just return here. This is because we have to
|
||||||
|
|
|
@ -222,23 +222,8 @@ where
|
||||||
// The effect of assignment to the return place in `TerminatorKind::Call` is not applied
|
// The effect of assignment to the return place in `TerminatorKind::Call` is not applied
|
||||||
// here; that occurs in `apply_call_return_effect`.
|
// 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.
|
// 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.
|
// 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);
|
self.super_terminator(terminator, location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -846,18 +846,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
||||||
self.check_edge(location, *unwind, EdgeKind::Unwind);
|
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, .. } => {
|
TerminatorKind::Call { func, args, destination, target, cleanup, .. } => {
|
||||||
let func_ty = func.ty(&self.body.local_decls, self.tcx);
|
let func_ty = func.ty(&self.body.local_decls, self.tcx);
|
||||||
match func_ty.kind() {
|
match func_ty.kind() {
|
||||||
|
|
|
@ -163,3 +163,10 @@ hir_analysis_pass_to_variadic_function = can't pass `{$ty}` to variadic function
|
||||||
.help = cast the value to `{$cast_ty}`
|
.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_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<...>`
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::check::intrinsicck::InlineAsmCtxt;
|
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::check_type_bounds;
|
||||||
use super::compare_impl_item::{compare_impl_method, compare_impl_ty};
|
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)
|
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.ty_adt_def().is_some_and(|adt_def| adt_def.is_manually_drop())
|
||||||
|| ty.is_copy_modulo_regions(tcx, param_env)
|
|| 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),
|
Some(Node::Field(field)) => (field.span, field.ty.span),
|
||||||
_ => unreachable!("mir field has to correspond to hir field"),
|
_ => unreachable!("mir field has to correspond to hir field"),
|
||||||
};
|
};
|
||||||
struct_span_err!(
|
tcx.sess.emit_err(errors::InvalidUnionField {
|
||||||
tcx.sess,
|
|
||||||
field_span,
|
field_span,
|
||||||
E0740,
|
sugg: errors::InvalidUnionFieldSuggestion {
|
||||||
"unions cannot contain fields that may need dropping"
|
lo: ty_span.shrink_to_lo(),
|
||||||
)
|
hi: ty_span.shrink_to_hi(),
|
||||||
.note(
|
},
|
||||||
"a type is guaranteed not to need dropping \
|
note: (),
|
||||||
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();
|
|
||||||
return false;
|
return false;
|
||||||
} else if field_ty.needs_drop(tcx, param_env) {
|
} 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.
|
// This should never happen. But we can get here e.g. in case of name resolution errors.
|
||||||
|
|
|
@ -5,7 +5,7 @@ use rustc_errors::{
|
||||||
error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic,
|
error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic,
|
||||||
MultiSpan,
|
MultiSpan,
|
||||||
};
|
};
|
||||||
use rustc_macros::Diagnostic;
|
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||||
use rustc_middle::ty::Ty;
|
use rustc_middle::ty::Ty;
|
||||||
use rustc_span::{symbol::Ident, Span, Symbol};
|
use rustc_span::{symbol::Ident, Span, Symbol};
|
||||||
|
|
||||||
|
@ -430,3 +430,23 @@ pub(crate) struct CastThinPointerToFatPointer<'tcx> {
|
||||||
pub expr_ty: Ty<'tcx>,
|
pub expr_ty: Ty<'tcx>,
|
||||||
pub cast_ty: String,
|
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,
|
||||||
|
}
|
||||||
|
|
|
@ -301,16 +301,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
span: Span,
|
span: Span,
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
substs: SubstsRef<'tcx>,
|
substs: SubstsRef<'tcx>,
|
||||||
) -> (ty::InstantiatedPredicates<'tcx>, Vec<Span>) {
|
) -> ty::InstantiatedPredicates<'tcx> {
|
||||||
let bounds = self.tcx.predicates_of(def_id);
|
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 = bounds.instantiate(self.tcx, substs);
|
||||||
let result = self.normalize(span, result);
|
let result = self.normalize(span, result);
|
||||||
debug!(
|
debug!("instantiate_bounds(bounds={:?}, substs={:?}) = {:?}", bounds, substs, result);
|
||||||
"instantiate_bounds(bounds={:?}, substs={:?}) = {:?}, {:?}",
|
result
|
||||||
bounds, substs, result, spans,
|
|
||||||
);
|
|
||||||
(result, spans)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(in super::super) fn normalize<T>(&self, span: Span, value: T) -> T
|
pub(in super::super) fn normalize<T>(&self, span: Span, value: T) -> T
|
||||||
|
@ -1389,7 +1385,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => 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(
|
for mut obligation in traits::predicates_for_generics(
|
||||||
|idx, predicate_span| {
|
|idx, predicate_span| {
|
||||||
|
|
|
@ -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() {
|
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);
|
debug!("canonical: type var found with vid {:?}", vid);
|
||||||
match self.infcx.probe_ty_var(vid) {
|
match self.infcx.probe_ty_var(vid) {
|
||||||
// `t` could be a float / int variable; canonicalize that instead.
|
// `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() {
|
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);
|
debug!("canonical: const var found with vid {:?}", vid);
|
||||||
match self.infcx.probe_const_var(vid) {
|
match self.infcx.probe_const_var(vid) {
|
||||||
Ok(c) => {
|
Ok(c) => {
|
||||||
|
|
|
@ -1359,6 +1359,10 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
self.inner.borrow_mut().type_variables().root_var(var)
|
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
|
/// Where possible, replaces type/const variables in
|
||||||
/// `value` with their final value. Note that region variables
|
/// `value` with their final value. Note that region variables
|
||||||
/// are unaffected. If a type/const variable has not been unified, it
|
/// are unaffected. If a type/const variable has not been unified, it
|
||||||
|
|
|
@ -265,7 +265,6 @@ pub fn terminator_kind_name(term: &Terminator<'_>) -> &'static str {
|
||||||
Return => "Return",
|
Return => "Return",
|
||||||
Unreachable => "Unreachable",
|
Unreachable => "Unreachable",
|
||||||
Drop { .. } => "Drop",
|
Drop { .. } => "Drop",
|
||||||
DropAndReplace { .. } => "DropAndReplace",
|
|
||||||
Call { .. } => "Call",
|
Call { .. } => "Call",
|
||||||
Assert { .. } => "Assert",
|
Assert { .. } => "Assert",
|
||||||
Yield { .. } => "Yield",
|
Yield { .. } => "Yield",
|
||||||
|
|
|
@ -133,7 +133,6 @@ pub enum AnalysisPhase {
|
||||||
pub enum RuntimePhase {
|
pub enum RuntimePhase {
|
||||||
/// In addition to the semantic changes, beginning with this phase, the following variants are
|
/// In addition to the semantic changes, beginning with this phase, the following variants are
|
||||||
/// disallowed:
|
/// disallowed:
|
||||||
/// * [`TerminatorKind::DropAndReplace`]
|
|
||||||
/// * [`TerminatorKind::Yield`]
|
/// * [`TerminatorKind::Yield`]
|
||||||
/// * [`TerminatorKind::GeneratorDrop`]
|
/// * [`TerminatorKind::GeneratorDrop`]
|
||||||
/// * [`Rvalue::Aggregate`] for any `AggregateKind` except `Array`
|
/// * [`Rvalue::Aggregate`] for any `AggregateKind` except `Array`
|
||||||
|
@ -596,43 +595,6 @@ pub enum TerminatorKind<'tcx> {
|
||||||
/// > consider indirect assignments.
|
/// > consider indirect assignments.
|
||||||
Drop { place: Place<'tcx>, target: BasicBlock, unwind: Option<BasicBlock> },
|
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
|
/// 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 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
|
/// The return place type must match the return type. The type of the `func` operand must be
|
||||||
|
|
|
@ -148,7 +148,6 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||||
| Call { target: None, cleanup: Some(t), .. }
|
| Call { target: None, cleanup: Some(t), .. }
|
||||||
| Call { target: Some(t), cleanup: None, .. }
|
| Call { target: Some(t), cleanup: None, .. }
|
||||||
| Yield { resume: t, drop: None, .. }
|
| Yield { resume: t, drop: None, .. }
|
||||||
| DropAndReplace { target: t, unwind: None, .. }
|
|
||||||
| Drop { target: t, unwind: None, .. }
|
| Drop { target: t, unwind: None, .. }
|
||||||
| Assert { target: t, cleanup: None, .. }
|
| Assert { target: t, cleanup: None, .. }
|
||||||
| FalseUnwind { real_target: t, unwind: None }
|
| FalseUnwind { real_target: t, unwind: None }
|
||||||
|
@ -158,7 +157,6 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||||
}
|
}
|
||||||
Call { target: Some(t), cleanup: Some(ref u), .. }
|
Call { target: Some(t), cleanup: Some(ref u), .. }
|
||||||
| Yield { resume: t, drop: Some(ref u), .. }
|
| Yield { resume: t, drop: Some(ref u), .. }
|
||||||
| DropAndReplace { target: t, unwind: Some(ref u), .. }
|
|
||||||
| Drop { target: t, unwind: Some(ref u), .. }
|
| Drop { target: t, unwind: Some(ref u), .. }
|
||||||
| Assert { target: t, cleanup: Some(ref u), .. }
|
| Assert { target: t, cleanup: Some(ref u), .. }
|
||||||
| FalseUnwind { real_target: t, unwind: 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: None, cleanup: Some(ref mut t), .. }
|
||||||
| Call { target: Some(ref mut t), cleanup: None, .. }
|
| Call { target: Some(ref mut t), cleanup: None, .. }
|
||||||
| Yield { resume: ref mut t, drop: None, .. }
|
| Yield { resume: ref mut t, drop: None, .. }
|
||||||
| DropAndReplace { target: ref mut t, unwind: None, .. }
|
|
||||||
| Drop { target: ref mut t, unwind: None, .. }
|
| Drop { target: ref mut t, unwind: None, .. }
|
||||||
| Assert { target: ref mut t, cleanup: None, .. }
|
| Assert { target: ref mut t, cleanup: None, .. }
|
||||||
| FalseUnwind { real_target: ref mut t, unwind: 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), .. }
|
Call { target: Some(ref mut t), cleanup: Some(ref mut u), .. }
|
||||||
| Yield { resume: ref mut t, drop: 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), .. }
|
| Drop { target: ref mut t, unwind: Some(ref mut u), .. }
|
||||||
| Assert { target: ref mut t, cleanup: 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) }
|
| FalseUnwind { real_target: ref mut t, unwind: Some(ref mut u) }
|
||||||
|
@ -225,7 +221,6 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||||
| TerminatorKind::FalseEdge { .. } => None,
|
| TerminatorKind::FalseEdge { .. } => None,
|
||||||
TerminatorKind::Call { cleanup: ref unwind, .. }
|
TerminatorKind::Call { cleanup: ref unwind, .. }
|
||||||
| TerminatorKind::Assert { cleanup: ref unwind, .. }
|
| TerminatorKind::Assert { cleanup: ref unwind, .. }
|
||||||
| TerminatorKind::DropAndReplace { ref unwind, .. }
|
|
||||||
| TerminatorKind::Drop { ref unwind, .. }
|
| TerminatorKind::Drop { ref unwind, .. }
|
||||||
| TerminatorKind::FalseUnwind { ref unwind, .. }
|
| TerminatorKind::FalseUnwind { ref unwind, .. }
|
||||||
| TerminatorKind::InlineAsm { cleanup: ref unwind, .. } => Some(unwind),
|
| TerminatorKind::InlineAsm { cleanup: ref unwind, .. } => Some(unwind),
|
||||||
|
@ -245,7 +240,6 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||||
| TerminatorKind::FalseEdge { .. } => None,
|
| TerminatorKind::FalseEdge { .. } => None,
|
||||||
TerminatorKind::Call { cleanup: ref mut unwind, .. }
|
TerminatorKind::Call { cleanup: ref mut unwind, .. }
|
||||||
| TerminatorKind::Assert { cleanup: ref mut unwind, .. }
|
| TerminatorKind::Assert { cleanup: ref mut unwind, .. }
|
||||||
| TerminatorKind::DropAndReplace { ref mut unwind, .. }
|
|
||||||
| TerminatorKind::Drop { ref mut unwind, .. }
|
| TerminatorKind::Drop { ref mut unwind, .. }
|
||||||
| TerminatorKind::FalseUnwind { ref mut unwind, .. }
|
| TerminatorKind::FalseUnwind { ref mut unwind, .. }
|
||||||
| TerminatorKind::InlineAsm { cleanup: ref mut unwind, .. } => Some(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),
|
Yield { value, resume_arg, .. } => write!(fmt, "{:?} = yield({:?})", resume_arg, value),
|
||||||
Unreachable => write!(fmt, "unreachable"),
|
Unreachable => write!(fmt, "unreachable"),
|
||||||
Drop { place, .. } => write!(fmt, "drop({:?})", place),
|
Drop { place, .. } => write!(fmt, "drop({:?})", place),
|
||||||
DropAndReplace { place, value, .. } => {
|
|
||||||
write!(fmt, "replace({:?} <- {:?})", place, value)
|
|
||||||
}
|
|
||||||
Call { func, args, destination, .. } => {
|
Call { func, args, destination, .. } => {
|
||||||
write!(fmt, "{:?} = ", destination)?;
|
write!(fmt, "{:?} = ", destination)?;
|
||||||
write!(fmt, "{:?}(", func)?;
|
write!(fmt, "{:?}(", func)?;
|
||||||
|
@ -403,10 +394,10 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||||
Call { target: None, cleanup: None, .. } => vec![],
|
Call { target: None, cleanup: None, .. } => vec![],
|
||||||
Yield { drop: Some(_), .. } => vec!["resume".into(), "drop".into()],
|
Yield { drop: Some(_), .. } => vec!["resume".into(), "drop".into()],
|
||||||
Yield { drop: None, .. } => vec!["resume".into()],
|
Yield { drop: None, .. } => vec!["resume".into()],
|
||||||
DropAndReplace { unwind: None, .. } | Drop { unwind: None, .. } => {
|
Drop { unwind: None, .. } => {
|
||||||
vec!["return".into()]
|
vec!["return".into()]
|
||||||
}
|
}
|
||||||
DropAndReplace { unwind: Some(_), .. } | Drop { unwind: Some(_), .. } => {
|
Drop { unwind: Some(_), .. } => {
|
||||||
vec!["return".into(), "unwind".into()]
|
vec!["return".into(), "unwind".into()]
|
||||||
}
|
}
|
||||||
Assert { cleanup: None, .. } => vec!["".into()],
|
Assert { cleanup: None, .. } => vec!["".into()],
|
||||||
|
|
|
@ -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 {
|
TerminatorKind::Call {
|
||||||
func,
|
func,
|
||||||
args,
|
args,
|
||||||
|
|
|
@ -59,14 +59,6 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
|
||||||
unwind: None,
|
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) => {
|
@call("mir_call", args) => {
|
||||||
let destination = self.parse_place(args[0])?;
|
let destination = self.parse_place(args[0])?;
|
||||||
let target = self.parse_block(args[1])?;
|
let target = self.parse_block(args[1])?;
|
||||||
|
|
|
@ -1072,7 +1072,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
TerminatorKind::Assert { .. }
|
TerminatorKind::Assert { .. }
|
||||||
| TerminatorKind::Call { .. }
|
| TerminatorKind::Call { .. }
|
||||||
| TerminatorKind::Drop { .. }
|
| TerminatorKind::Drop { .. }
|
||||||
| TerminatorKind::DropAndReplace { .. }
|
|
||||||
| TerminatorKind::FalseUnwind { .. }
|
| TerminatorKind::FalseUnwind { .. }
|
||||||
| TerminatorKind::InlineAsm { .. }
|
| TerminatorKind::InlineAsm { .. }
|
||||||
),
|
),
|
||||||
|
@ -1432,8 +1431,7 @@ impl<'tcx> DropTreeBuilder<'tcx> for Unwind {
|
||||||
*unwind = Some(to);
|
*unwind = Some(to);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TerminatorKind::DropAndReplace { unwind, .. }
|
TerminatorKind::FalseUnwind { unwind, .. }
|
||||||
| TerminatorKind::FalseUnwind { unwind, .. }
|
|
||||||
| TerminatorKind::Call { cleanup: unwind, .. }
|
| TerminatorKind::Call { cleanup: unwind, .. }
|
||||||
| TerminatorKind::Assert { cleanup: unwind, .. }
|
| TerminatorKind::Assert { cleanup: unwind, .. }
|
||||||
| TerminatorKind::InlineAsm { cleanup: unwind, .. } => {
|
| TerminatorKind::InlineAsm { cleanup: unwind, .. } => {
|
||||||
|
|
|
@ -128,7 +128,6 @@ impl<'mir, 'tcx> TriColorVisitor<BasicBlocks<'tcx>> for Search<'mir, 'tcx> {
|
||||||
TerminatorKind::Assert { .. }
|
TerminatorKind::Assert { .. }
|
||||||
| TerminatorKind::Call { .. }
|
| TerminatorKind::Call { .. }
|
||||||
| TerminatorKind::Drop { .. }
|
| TerminatorKind::Drop { .. }
|
||||||
| TerminatorKind::DropAndReplace { .. }
|
|
||||||
| TerminatorKind::FalseEdge { .. }
|
| TerminatorKind::FalseEdge { .. }
|
||||||
| TerminatorKind::FalseUnwind { .. }
|
| TerminatorKind::FalseUnwind { .. }
|
||||||
| TerminatorKind::Goto { .. }
|
| TerminatorKind::Goto { .. }
|
||||||
|
|
|
@ -480,7 +480,6 @@ impl Direction for Forward {
|
||||||
|
|
||||||
Assert { target, cleanup: unwind, expected: _, msg: _, cond: _ }
|
Assert { target, cleanup: unwind, expected: _, msg: _, cond: _ }
|
||||||
| Drop { target, unwind, place: _ }
|
| Drop { target, unwind, place: _ }
|
||||||
| DropAndReplace { target, unwind, value: _, place: _ }
|
|
||||||
| FalseUnwind { real_target: target, unwind } => {
|
| FalseUnwind { real_target: target, unwind } => {
|
||||||
if let Some(unwind) = unwind {
|
if let Some(unwind) = unwind {
|
||||||
propagate(unwind, exit_state);
|
propagate(unwind, exit_state);
|
||||||
|
|
|
@ -111,8 +111,7 @@ where
|
||||||
self.super_terminator(terminator, location);
|
self.super_terminator(terminator, location);
|
||||||
|
|
||||||
match terminator.kind {
|
match terminator.kind {
|
||||||
mir::TerminatorKind::Drop { place: dropped_place, .. }
|
mir::TerminatorKind::Drop { place: dropped_place, .. } => {
|
||||||
| mir::TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
|
|
||||||
// Drop terminators may call custom drop glue (`Drop::drop`), which takes `&mut
|
// 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
|
// 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
|
// reference into the surrounding environment through a raw pointer, thus creating
|
||||||
|
|
|
@ -202,7 +202,6 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
|
||||||
TerminatorKind::Abort
|
TerminatorKind::Abort
|
||||||
| TerminatorKind::Assert { .. }
|
| TerminatorKind::Assert { .. }
|
||||||
| TerminatorKind::Drop { .. }
|
| TerminatorKind::Drop { .. }
|
||||||
| TerminatorKind::DropAndReplace { .. }
|
|
||||||
| TerminatorKind::FalseEdge { .. }
|
| TerminatorKind::FalseEdge { .. }
|
||||||
| TerminatorKind::FalseUnwind { .. }
|
| TerminatorKind::FalseUnwind { .. }
|
||||||
| TerminatorKind::GeneratorDrop
|
| TerminatorKind::GeneratorDrop
|
||||||
|
@ -240,7 +239,6 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
|
||||||
| TerminatorKind::Abort
|
| TerminatorKind::Abort
|
||||||
| TerminatorKind::Assert { .. }
|
| TerminatorKind::Assert { .. }
|
||||||
| TerminatorKind::Drop { .. }
|
| TerminatorKind::Drop { .. }
|
||||||
| TerminatorKind::DropAndReplace { .. }
|
|
||||||
| TerminatorKind::FalseEdge { .. }
|
| TerminatorKind::FalseEdge { .. }
|
||||||
| TerminatorKind::FalseUnwind { .. }
|
| TerminatorKind::FalseUnwind { .. }
|
||||||
| TerminatorKind::GeneratorDrop
|
| TerminatorKind::GeneratorDrop
|
||||||
|
|
|
@ -392,11 +392,6 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
||||||
self.create_move_path(place);
|
self.create_move_path(place);
|
||||||
self.gather_init(place.as_ref(), InitKind::Deep);
|
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 {
|
TerminatorKind::Call {
|
||||||
ref func,
|
ref func,
|
||||||
ref args,
|
ref args,
|
||||||
|
|
|
@ -230,7 +230,7 @@ pub trait ValueAnalysis<'tcx> {
|
||||||
TerminatorKind::Drop { place, .. } => {
|
TerminatorKind::Drop { place, .. } => {
|
||||||
state.flood_with(place.as_ref(), self.map(), Self::Value::bottom());
|
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.
|
// They would have an effect, but are not allowed in this phase.
|
||||||
bug!("encountered disallowed terminator");
|
bug!("encountered disallowed terminator");
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,7 @@ impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls {
|
||||||
};
|
};
|
||||||
layout::fn_can_unwind(tcx, fn_def_id, sig.abi())
|
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
|
tcx.sess.opts.unstable_opts.panic_in_drop == PanicStrategy::Unwind
|
||||||
&& layout::fn_can_unwind(tcx, None, Abi::Rust)
|
&& layout::fn_can_unwind(tcx, None, Abi::Rust)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
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");
|
|
||||||
}
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
// `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.
|
// Not a block ending in a Call -> ignore.
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,6 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
|
||||||
| TerminatorKind::Drop { .. }
|
| TerminatorKind::Drop { .. }
|
||||||
| TerminatorKind::Yield { .. }
|
| TerminatorKind::Yield { .. }
|
||||||
| TerminatorKind::Assert { .. }
|
| TerminatorKind::Assert { .. }
|
||||||
| TerminatorKind::DropAndReplace { .. }
|
|
||||||
| TerminatorKind::GeneratorDrop
|
| TerminatorKind::GeneratorDrop
|
||||||
| TerminatorKind::Resume
|
| TerminatorKind::Resume
|
||||||
| TerminatorKind::Abort
|
| TerminatorKind::Abort
|
||||||
|
|
|
@ -1007,7 +1007,6 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
|
||||||
| TerminatorKind::Return
|
| TerminatorKind::Return
|
||||||
| TerminatorKind::Unreachable
|
| TerminatorKind::Unreachable
|
||||||
| TerminatorKind::Drop { .. }
|
| TerminatorKind::Drop { .. }
|
||||||
| TerminatorKind::DropAndReplace { .. }
|
|
||||||
| TerminatorKind::Yield { .. }
|
| TerminatorKind::Yield { .. }
|
||||||
| TerminatorKind::GeneratorDrop
|
| TerminatorKind::GeneratorDrop
|
||||||
| TerminatorKind::FalseEdge { .. }
|
| TerminatorKind::FalseEdge { .. }
|
||||||
|
|
|
@ -686,7 +686,6 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
|
||||||
| TerminatorKind::Return
|
| TerminatorKind::Return
|
||||||
| TerminatorKind::Unreachable
|
| TerminatorKind::Unreachable
|
||||||
| TerminatorKind::Drop { .. }
|
| TerminatorKind::Drop { .. }
|
||||||
| TerminatorKind::DropAndReplace { .. }
|
|
||||||
| TerminatorKind::Yield { .. }
|
| TerminatorKind::Yield { .. }
|
||||||
| TerminatorKind::GeneratorDrop
|
| TerminatorKind::GeneratorDrop
|
||||||
| TerminatorKind::FalseEdge { .. }
|
| TerminatorKind::FalseEdge { .. }
|
||||||
|
|
|
@ -822,7 +822,6 @@ pub(super) fn term_type(kind: &TerminatorKind<'_>) -> &'static str {
|
||||||
TerminatorKind::Return => "Return",
|
TerminatorKind::Return => "Return",
|
||||||
TerminatorKind::Unreachable => "Unreachable",
|
TerminatorKind::Unreachable => "Unreachable",
|
||||||
TerminatorKind::Drop { .. } => "Drop",
|
TerminatorKind::Drop { .. } => "Drop",
|
||||||
TerminatorKind::DropAndReplace { .. } => "DropAndReplace",
|
|
||||||
TerminatorKind::Call { .. } => "Call",
|
TerminatorKind::Call { .. } => "Call",
|
||||||
TerminatorKind::Assert { .. } => "Assert",
|
TerminatorKind::Assert { .. } => "Assert",
|
||||||
TerminatorKind::Yield { .. } => "Yield",
|
TerminatorKind::Yield { .. } => "Yield",
|
||||||
|
|
|
@ -156,7 +156,6 @@ impl CoverageGraph {
|
||||||
| TerminatorKind::Resume
|
| TerminatorKind::Resume
|
||||||
| TerminatorKind::Unreachable
|
| TerminatorKind::Unreachable
|
||||||
| TerminatorKind::Drop { .. }
|
| TerminatorKind::Drop { .. }
|
||||||
| TerminatorKind::DropAndReplace { .. }
|
|
||||||
| TerminatorKind::Call { .. }
|
| TerminatorKind::Call { .. }
|
||||||
| TerminatorKind::GeneratorDrop
|
| TerminatorKind::GeneratorDrop
|
||||||
| TerminatorKind::Assert { .. }
|
| TerminatorKind::Assert { .. }
|
||||||
|
|
|
@ -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::Unreachable // Unreachable blocks are not connected to the MIR CFG
|
||||||
| TerminatorKind::Assert { .. }
|
| TerminatorKind::Assert { .. }
|
||||||
| TerminatorKind::Drop { .. }
|
| TerminatorKind::Drop { .. }
|
||||||
| TerminatorKind::DropAndReplace { .. }
|
|
||||||
| TerminatorKind::SwitchInt { .. }
|
| TerminatorKind::SwitchInt { .. }
|
||||||
// For `FalseEdge`, only the `real` branch is taken, so it is similar to a `Goto`.
|
// For `FalseEdge`, only the `real` branch is taken, so it is similar to a `Goto`.
|
||||||
| TerminatorKind::FalseEdge { .. }
|
| TerminatorKind::FalseEdge { .. }
|
||||||
|
|
|
@ -86,7 +86,6 @@ impl<'tcx> MockBlocks<'tcx> {
|
||||||
TerminatorKind::Assert { ref mut target, .. }
|
TerminatorKind::Assert { ref mut target, .. }
|
||||||
| TerminatorKind::Call { target: Some(ref mut target), .. }
|
| TerminatorKind::Call { target: Some(ref mut target), .. }
|
||||||
| TerminatorKind::Drop { ref mut target, .. }
|
| TerminatorKind::Drop { ref mut target, .. }
|
||||||
| TerminatorKind::DropAndReplace { ref mut target, .. }
|
|
||||||
| TerminatorKind::FalseEdge { real_target: ref mut target, .. }
|
| TerminatorKind::FalseEdge { real_target: ref mut target, .. }
|
||||||
| TerminatorKind::FalseUnwind { real_target: ref mut target, .. }
|
| TerminatorKind::FalseUnwind { real_target: ref mut target, .. }
|
||||||
| TerminatorKind::Goto { ref mut target }
|
| TerminatorKind::Goto { ref mut target }
|
||||||
|
@ -184,7 +183,6 @@ fn debug_basic_blocks(mir_body: &Body<'_>) -> String {
|
||||||
TerminatorKind::Assert { target, .. }
|
TerminatorKind::Assert { target, .. }
|
||||||
| TerminatorKind::Call { target: Some(target), .. }
|
| TerminatorKind::Call { target: Some(target), .. }
|
||||||
| TerminatorKind::Drop { target, .. }
|
| TerminatorKind::Drop { target, .. }
|
||||||
| TerminatorKind::DropAndReplace { target, .. }
|
|
||||||
| TerminatorKind::FalseEdge { real_target: target, .. }
|
| TerminatorKind::FalseEdge { real_target: target, .. }
|
||||||
| TerminatorKind::FalseUnwind { real_target: target, .. }
|
| TerminatorKind::FalseUnwind { real_target: target, .. }
|
||||||
| TerminatorKind::Goto { target }
|
| TerminatorKind::Goto { target }
|
||||||
|
|
|
@ -650,8 +650,7 @@ impl WriteInfo {
|
||||||
TerminatorKind::Drop { .. } => {
|
TerminatorKind::Drop { .. } => {
|
||||||
// `Drop`s create a `&mut` and so are not considered
|
// `Drop`s create a `&mut` and so are not considered
|
||||||
}
|
}
|
||||||
TerminatorKind::DropAndReplace { .. }
|
TerminatorKind::Yield { .. }
|
||||||
| TerminatorKind::Yield { .. }
|
|
||||||
| TerminatorKind::GeneratorDrop
|
| TerminatorKind::GeneratorDrop
|
||||||
| TerminatorKind::FalseEdge { .. }
|
| TerminatorKind::FalseEdge { .. }
|
||||||
| TerminatorKind::FalseUnwind { .. } => {
|
| TerminatorKind::FalseUnwind { .. } => {
|
||||||
|
|
|
@ -18,15 +18,14 @@ use rustc_span::{DesugaringKind, Span};
|
||||||
use rustc_target::abi::VariantIdx;
|
use rustc_target::abi::VariantIdx;
|
||||||
use std::fmt;
|
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,
|
/// 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.
|
/// 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.
|
/// 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
|
/// 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.
|
/// 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
|
/// 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.
|
/// "drop shim" for the type of the dropped place.
|
||||||
///
|
///
|
||||||
|
@ -121,8 +120,7 @@ fn remove_dead_unwinds<'tcx>(
|
||||||
.into_results_cursor(body);
|
.into_results_cursor(body);
|
||||||
for (bb, bb_data) in body.basic_blocks.iter_enumerated() {
|
for (bb, bb_data) in body.basic_blocks.iter_enumerated() {
|
||||||
let place = match bb_data.terminator().kind {
|
let place = match bb_data.terminator().kind {
|
||||||
TerminatorKind::Drop { ref place, unwind: Some(_), .. }
|
TerminatorKind::Drop { ref place, unwind: Some(_), .. } => {
|
||||||
| TerminatorKind::DropAndReplace { ref place, unwind: Some(_), .. } => {
|
|
||||||
und.derefer(place.as_ref(), body).unwrap_or(*place)
|
und.derefer(place.as_ref(), body).unwrap_or(*place)
|
||||||
}
|
}
|
||||||
_ => continue,
|
_ => continue,
|
||||||
|
@ -343,8 +341,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
||||||
}
|
}
|
||||||
let terminator = data.terminator();
|
let terminator = data.terminator();
|
||||||
let place = match terminator.kind {
|
let place = match terminator.kind {
|
||||||
TerminatorKind::Drop { ref place, .. }
|
TerminatorKind::Drop { ref place, .. } => {
|
||||||
| TerminatorKind::DropAndReplace { ref place, .. } => {
|
|
||||||
self.un_derefer.derefer(place.as_ref(), self.body).unwrap_or(*place)
|
self.un_derefer.derefer(place.as_ref(), self.body).unwrap_or(*place)
|
||||||
}
|
}
|
||||||
_ => continue,
|
_ => 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,
|
_ => 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> {
|
fn constant_bool(&self, span: Span, val: bool) -> Rvalue<'tcx> {
|
||||||
Rvalue::Use(Operand::Constant(Box::new(Constant {
|
Rvalue::Use(Operand::Constant(Box::new(Constant {
|
||||||
span,
|
span,
|
||||||
|
@ -609,22 +514,12 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
||||||
debug!("drop_flags_for_locs({:?})", data);
|
debug!("drop_flags_for_locs({:?})", data);
|
||||||
for i in 0..(data.statements.len() + 1) {
|
for i in 0..(data.statements.len() + 1) {
|
||||||
debug!("drop_flag_for_locs: stmt {}", i);
|
debug!("drop_flag_for_locs: stmt {}", i);
|
||||||
let mut allow_initializations = true;
|
|
||||||
if i == data.statements.len() {
|
if i == data.statements.len() {
|
||||||
match data.terminator().kind {
|
match data.terminator().kind {
|
||||||
TerminatorKind::Drop { .. } => {
|
TerminatorKind::Drop { .. } => {
|
||||||
// drop elaboration should handle that by itself
|
// drop elaboration should handle that by itself
|
||||||
continue;
|
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 => {
|
TerminatorKind::Resume => {
|
||||||
// It is possible for `Resume` to be patched
|
// It is possible for `Resume` to be patched
|
||||||
// (in particular it can be patched to be replaced with
|
// (in particular it can be patched to be replaced with
|
||||||
|
@ -641,11 +536,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
||||||
self.body,
|
self.body,
|
||||||
self.env,
|
self.env,
|
||||||
loc,
|
loc,
|
||||||
|path, ds| {
|
|path, ds| self.set_drop_flag(loc, path, ds),
|
||||||
if ds == DropFlagState::Absent || allow_initializations {
|
|
||||||
self.set_drop_flag(loc, path, ds)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1199,7 +1199,6 @@ fn can_unwind<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> bool {
|
||||||
|
|
||||||
// These may unwind.
|
// These may unwind.
|
||||||
TerminatorKind::Drop { .. }
|
TerminatorKind::Drop { .. }
|
||||||
| TerminatorKind::DropAndReplace { .. }
|
|
||||||
| TerminatorKind::Call { .. }
|
| TerminatorKind::Call { .. }
|
||||||
| TerminatorKind::InlineAsm { .. }
|
| TerminatorKind::InlineAsm { .. }
|
||||||
| TerminatorKind::Assert { .. } => return true,
|
| TerminatorKind::Assert { .. } => return true,
|
||||||
|
@ -1691,7 +1690,6 @@ impl<'tcx> Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> {
|
||||||
| TerminatorKind::Return
|
| TerminatorKind::Return
|
||||||
| TerminatorKind::Unreachable
|
| TerminatorKind::Unreachable
|
||||||
| TerminatorKind::Drop { .. }
|
| TerminatorKind::Drop { .. }
|
||||||
| TerminatorKind::DropAndReplace { .. }
|
|
||||||
| TerminatorKind::Assert { .. }
|
| TerminatorKind::Assert { .. }
|
||||||
| TerminatorKind::GeneratorDrop
|
| TerminatorKind::GeneratorDrop
|
||||||
| TerminatorKind::FalseEdge { .. }
|
| TerminatorKind::FalseEdge { .. }
|
||||||
|
|
|
@ -453,9 +453,7 @@ impl<'tcx> Inliner<'tcx> {
|
||||||
checker.visit_basic_block_data(bb, blk);
|
checker.visit_basic_block_data(bb, blk);
|
||||||
|
|
||||||
let term = blk.terminator();
|
let term = blk.terminator();
|
||||||
if let TerminatorKind::Drop { ref place, target, unwind }
|
if let TerminatorKind::Drop { ref place, target, unwind } = term.kind {
|
||||||
| TerminatorKind::DropAndReplace { ref place, target, unwind, .. } = term.kind
|
|
||||||
{
|
|
||||||
work_list.push(target);
|
work_list.push(target);
|
||||||
|
|
||||||
// If the place doesn't actually need dropping, treat it like a regular goto.
|
// 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) {
|
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
match terminator.kind {
|
match terminator.kind {
|
||||||
TerminatorKind::Drop { ref place, unwind, .. }
|
TerminatorKind::Drop { ref place, unwind, .. } => {
|
||||||
| TerminatorKind::DropAndReplace { ref place, unwind, .. } => {
|
|
||||||
// If the place doesn't actually need dropping, treat it like a regular goto.
|
// 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);
|
let ty = self.instance.subst_mir(tcx, &place.ty(self.callee_body, tcx).ty);
|
||||||
if ty.needs_drop(tcx, self.param_env) {
|
if ty.needs_drop(tcx, self.param_env) {
|
||||||
|
@ -1120,8 +1117,7 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> {
|
||||||
*tgt = self.map_block(*tgt);
|
*tgt = self.map_block(*tgt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TerminatorKind::Drop { ref mut target, ref mut unwind, .. }
|
TerminatorKind::Drop { ref mut target, ref mut unwind, .. } => {
|
||||||
| TerminatorKind::DropAndReplace { ref mut target, ref mut unwind, .. } => {
|
|
||||||
*target = self.map_block(*target);
|
*target = self.map_block(*target);
|
||||||
*unwind = self.map_unwind(*unwind);
|
*unwind = self.map_unwind(*unwind);
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,6 @@ impl RemoveNoopLandingPads {
|
||||||
| TerminatorKind::Unreachable
|
| TerminatorKind::Unreachable
|
||||||
| TerminatorKind::Call { .. }
|
| TerminatorKind::Call { .. }
|
||||||
| TerminatorKind::Assert { .. }
|
| TerminatorKind::Assert { .. }
|
||||||
| TerminatorKind::DropAndReplace { .. }
|
|
||||||
| TerminatorKind::Drop { .. }
|
| TerminatorKind::Drop { .. }
|
||||||
| TerminatorKind::InlineAsm { .. } => false,
|
| TerminatorKind::InlineAsm { .. } => false,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use rustc_index::bit_set::ChunkedBitSet;
|
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::subst::SubstsRef;
|
||||||
use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, VariantDef};
|
use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, VariantDef};
|
||||||
use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
|
use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
|
||||||
|
@ -8,7 +8,7 @@ use rustc_mir_dataflow::{self, move_path_children_matching, Analysis, MoveDataPa
|
||||||
|
|
||||||
use crate::MirPass;
|
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.
|
/// that point.
|
||||||
///
|
///
|
||||||
/// This is redundant with drop elaboration, but we need to do it prior to const-checking, and
|
/// 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![];
|
let mut to_remove = vec![];
|
||||||
for (bb, block) in body.basic_blocks.iter_enumerated() {
|
for (bb, block) in body.basic_blocks.iter_enumerated() {
|
||||||
let terminator = block.terminator();
|
let terminator = block.terminator();
|
||||||
let (TerminatorKind::Drop { place, .. } | TerminatorKind::DropAndReplace { place, .. })
|
let TerminatorKind::Drop { place, .. } = &terminator.kind
|
||||||
= &terminator.kind
|
|
||||||
else { continue };
|
else { continue };
|
||||||
|
|
||||||
maybe_inits.seek_before_primary_effect(body.terminator_loc(bb));
|
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 {
|
for bb in to_remove {
|
||||||
let block = &mut body.basic_blocks_mut()[bb];
|
let block = &mut body.basic_blocks_mut()[bb];
|
||||||
|
|
||||||
let (TerminatorKind::Drop { target, .. } | TerminatorKind::DropAndReplace { target, .. })
|
let TerminatorKind::Drop { target, .. }
|
||||||
= &block.terminator().kind
|
= &block.terminator().kind
|
||||||
else { unreachable!() };
|
else { unreachable!() };
|
||||||
|
|
||||||
// Replace block terminator with `Goto`.
|
// Replace block terminator with `Goto`.
|
||||||
let target = *target;
|
block.terminator_mut().kind = TerminatorKind::Goto { 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)))),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,7 +108,6 @@ pub fn separate_const_switch(body: &mut Body<'_>) -> usize {
|
||||||
// The following terminators are not allowed
|
// The following terminators are not allowed
|
||||||
TerminatorKind::Resume
|
TerminatorKind::Resume
|
||||||
| TerminatorKind::Drop { .. }
|
| TerminatorKind::Drop { .. }
|
||||||
| TerminatorKind::DropAndReplace { .. }
|
|
||||||
| TerminatorKind::Call { .. }
|
| TerminatorKind::Call { .. }
|
||||||
| TerminatorKind::Assert { .. }
|
| TerminatorKind::Assert { .. }
|
||||||
| TerminatorKind::FalseUnwind { .. }
|
| TerminatorKind::FalseUnwind { .. }
|
||||||
|
@ -170,7 +169,6 @@ pub fn separate_const_switch(body: &mut Body<'_>) -> usize {
|
||||||
| TerminatorKind::Unreachable
|
| TerminatorKind::Unreachable
|
||||||
| TerminatorKind::GeneratorDrop
|
| TerminatorKind::GeneratorDrop
|
||||||
| TerminatorKind::Assert { .. }
|
| TerminatorKind::Assert { .. }
|
||||||
| TerminatorKind::DropAndReplace { .. }
|
|
||||||
| TerminatorKind::FalseUnwind { .. }
|
| TerminatorKind::FalseUnwind { .. }
|
||||||
| TerminatorKind::Drop { .. }
|
| TerminatorKind::Drop { .. }
|
||||||
| TerminatorKind::Call { .. }
|
| TerminatorKind::Call { .. }
|
||||||
|
|
|
@ -808,8 +808,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
|
||||||
let callee_ty = self.monomorphize(callee_ty);
|
let callee_ty = self.monomorphize(callee_ty);
|
||||||
visit_fn_use(self.tcx, callee_ty, true, source, &mut self.output)
|
visit_fn_use(self.tcx, callee_ty, true, source, &mut self.output)
|
||||||
}
|
}
|
||||||
mir::TerminatorKind::Drop { ref place, .. }
|
mir::TerminatorKind::Drop { ref place, .. } => {
|
||||||
| mir::TerminatorKind::DropAndReplace { ref place, .. } => {
|
|
||||||
let ty = place.ty(self.body, self.tcx).ty;
|
let ty = place.ty(self.body, self.tcx).ty;
|
||||||
let ty = self.monomorphize(ty);
|
let ty = self.monomorphize(ty);
|
||||||
visit_drop_use(self.tcx, ty, true, source, self.output);
|
visit_drop_use(self.tcx, ty, true, source, self.output);
|
||||||
|
|
|
@ -261,12 +261,23 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
|
||||||
self.interner().mk_re_late_bound(self.binder_index, br)
|
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() {
|
let kind = match *t.kind() {
|
||||||
ty::Infer(ty::TyVar(vid)) => match self.infcx.probe_ty_var(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.infcx.probe_ty_var(vid) {
|
||||||
Ok(t) => return self.fold_ty(t),
|
Ok(t) => return self.fold_ty(t),
|
||||||
Err(ui) => CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)),
|
Err(ui) => CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)),
|
||||||
},
|
}
|
||||||
|
}
|
||||||
ty::Infer(ty::IntVar(_)) => {
|
ty::Infer(ty::IntVar(_)) => {
|
||||||
let nt = self.infcx.shallow_resolve(t);
|
let nt = self.infcx.shallow_resolve(t);
|
||||||
if nt != t {
|
if nt != t {
|
||||||
|
@ -338,13 +349,23 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
|
||||||
self.interner().mk_bound(self.binder_index, bt)
|
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() {
|
let kind = match c.kind() {
|
||||||
ty::ConstKind::Infer(ty::InferConst::Var(vid)) => match self.infcx.probe_const_var(vid)
|
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),
|
Ok(c) => return self.fold_const(c),
|
||||||
Err(universe) => CanonicalVarKind::Const(universe, c.ty()),
|
Err(universe) => CanonicalVarKind::Const(universe, c.ty()),
|
||||||
},
|
}
|
||||||
|
}
|
||||||
ty::ConstKind::Infer(ty::InferConst::Fresh(_)) => {
|
ty::ConstKind::Infer(ty::InferConst::Fresh(_)) => {
|
||||||
bug!("fresh var during canonicalization: {c:?}")
|
bug!("fresh var during canonicalization: {c:?}")
|
||||||
}
|
}
|
||||||
|
|
|
@ -238,6 +238,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
||||||
&& has_changed
|
&& has_changed
|
||||||
&& !self.in_projection_eq_hack
|
&& !self.in_projection_eq_hack
|
||||||
&& !self.search_graph.in_cycle()
|
&& !self.search_graph.in_cycle()
|
||||||
|
&& false
|
||||||
{
|
{
|
||||||
let (_orig_values, canonical_goal) = self.canonicalize_goal(goal);
|
let (_orig_values, canonical_goal) = self.canonicalize_goal(goal);
|
||||||
let canonical_response =
|
let canonical_response =
|
||||||
|
|
|
@ -155,10 +155,12 @@ fn pred_known_to_hold_modulo_regions<'tcx>(
|
||||||
predicate: pred.to_predicate(infcx.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);
|
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
|
// Because of inference "guessing", selection can sometimes claim
|
||||||
// to succeed while the success requires a guess. To ensure
|
// to succeed while the success requires a guess. To ensure
|
||||||
// this function's result remains infallible, we must confirm
|
// this function's result remains infallible, we must confirm
|
||||||
|
@ -179,7 +181,7 @@ fn pred_known_to_hold_modulo_regions<'tcx>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -227,7 +227,7 @@
|
||||||
//! are no resume and abort terminators, and terminators that might unwind do not have any way to
|
//! are no resume and abort terminators, and terminators that might unwind do not have any way to
|
||||||
//! indicate the unwind block.
|
//! 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`
|
//! - `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
|
//! - The exception is the last arm, which must be `_ => basic_block` and corresponds to the
|
||||||
//! otherwise branch.
|
//! otherwise branch.
|
||||||
|
@ -259,7 +259,6 @@ define!("mir_return", fn Return() -> BasicBlock);
|
||||||
define!("mir_goto", fn Goto(destination: BasicBlock) -> BasicBlock);
|
define!("mir_goto", fn Goto(destination: BasicBlock) -> BasicBlock);
|
||||||
define!("mir_unreachable", fn Unreachable() -> BasicBlock);
|
define!("mir_unreachable", fn Unreachable() -> BasicBlock);
|
||||||
define!("mir_drop", fn Drop<T>(place: T, goto: 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_call", fn Call<T>(place: T, goto: BasicBlock, call: T));
|
||||||
define!("mir_storage_live", fn StorageLive<T>(local: T));
|
define!("mir_storage_live", fn StorageLive<T>(local: T));
|
||||||
define!("mir_storage_dead", fn StorageDead<T>(local: T));
|
define!("mir_storage_dead", fn StorageDead<T>(local: T));
|
||||||
|
|
|
@ -1721,6 +1721,15 @@ impl<'a> Builder<'a> {
|
||||||
|
|
||||||
cargo.env("RUSTC_VERBOSE", self.verbosity.to_string());
|
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 {
|
if source_type == SourceType::InTree {
|
||||||
let mut lint_flags = Vec::new();
|
let mut lint_flags = Vec::new();
|
||||||
// When extending this list, add the new lints to the RUSTFLAGS of the
|
// When extending this list, add the new lints to the RUSTFLAGS of the
|
||||||
|
|
|
@ -299,10 +299,6 @@ fn check_terminator<'tcx>(
|
||||||
| TerminatorKind::Unreachable => Ok(()),
|
| TerminatorKind::Unreachable => Ok(()),
|
||||||
|
|
||||||
TerminatorKind::Drop { place, .. } => check_place(tcx, *place, span, body),
|
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),
|
TerminatorKind::SwitchInt { discr, targets: _ } => check_operand(tcx, discr, span, body),
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ function isNumeric(s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseOptions(args) {
|
function parseOptions(args) {
|
||||||
var opts = {
|
const opts = {
|
||||||
"doc_folder": "",
|
"doc_folder": "",
|
||||||
"tests_folder": "",
|
"tests_folder": "",
|
||||||
"files": [],
|
"files": [],
|
||||||
|
@ -42,7 +42,7 @@ function parseOptions(args) {
|
||||||
"executable_path": null,
|
"executable_path": null,
|
||||||
"no_sandbox": false,
|
"no_sandbox": false,
|
||||||
};
|
};
|
||||||
var correspondances = {
|
const correspondances = {
|
||||||
"--doc-folder": "doc_folder",
|
"--doc-folder": "doc_folder",
|
||||||
"--tests-folder": "tests_folder",
|
"--tests-folder": "tests_folder",
|
||||||
"--debug": "debug",
|
"--debug": "debug",
|
||||||
|
@ -52,39 +52,41 @@ function parseOptions(args) {
|
||||||
"--no-sandbox": "no_sandbox",
|
"--no-sandbox": "no_sandbox",
|
||||||
};
|
};
|
||||||
|
|
||||||
for (var i = 0; i < args.length; ++i) {
|
for (let i = 0; i < args.length; ++i) {
|
||||||
if (args[i] === "--doc-folder"
|
const arg = args[i];
|
||||||
|| args[i] === "--tests-folder"
|
if (arg === "--doc-folder"
|
||||||
|| args[i] === "--file"
|
|| arg === "--tests-folder"
|
||||||
|| args[i] === "--jobs"
|
|| arg === "--file"
|
||||||
|| args[i] === "--executable-path") {
|
|| arg === "--jobs"
|
||||||
|
|| arg === "--executable-path") {
|
||||||
i += 1;
|
i += 1;
|
||||||
if (i >= args.length) {
|
if (i >= args.length) {
|
||||||
console.log("Missing argument after `" + args[i - 1] + "` option.");
|
console.log("Missing argument after `" + arg + "` option.");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (args[i - 1] === "--jobs") {
|
const arg_value = args[i];
|
||||||
if (!isNumeric(args[i])) {
|
if (arg === "--jobs") {
|
||||||
|
if (!isNumeric(arg_value)) {
|
||||||
console.log(
|
console.log(
|
||||||
"`--jobs` option expects a positive number, found `" + args[i] + "`");
|
"`--jobs` option expects a positive number, found `" + arg_value + "`");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
opts["jobs"] = parseInt(args[i]);
|
opts["jobs"] = parseInt(arg_value);
|
||||||
} else if (args[i - 1] !== "--file") {
|
} else if (arg !== "--file") {
|
||||||
opts[correspondances[args[i - 1]]] = args[i];
|
opts[correspondances[arg]] = arg_value;
|
||||||
} else {
|
} else {
|
||||||
opts["files"].push(args[i]);
|
opts["files"].push(arg_value);
|
||||||
}
|
}
|
||||||
} else if (args[i] === "--help") {
|
} else if (arg === "--help") {
|
||||||
showHelp();
|
showHelp();
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
} else if (args[i] === "--no-sandbox") {
|
} else if (arg === "--no-sandbox") {
|
||||||
console.log("`--no-sandbox` is being used. Be very careful!");
|
console.log("`--no-sandbox` is being used. Be very careful!");
|
||||||
opts[correspondances[args[i]]] = true;
|
opts[correspondances[arg]] = true;
|
||||||
} else if (correspondances[args[i]]) {
|
} else if (correspondances[arg]) {
|
||||||
opts[correspondances[args[i]]] = true;
|
opts[correspondances[arg]] = true;
|
||||||
} else {
|
} else {
|
||||||
console.log("Unknown option `" + args[i] + "`.");
|
console.log("Unknown option `" + arg + "`.");
|
||||||
console.log("Use `--help` to see the list of options");
|
console.log("Use `--help` to see the list of options");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -186,7 +188,7 @@ function createEmptyResults() {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function main(argv) {
|
async function main(argv) {
|
||||||
let opts = parseOptions(argv.slice(2));
|
const opts = parseOptions(argv.slice(2));
|
||||||
if (opts === null) {
|
if (opts === null) {
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
let mut _0: (); // return place in scope 0 at $DIR/terminators.rs:+0:59: +0:59
|
||||||
|
|
||||||
bb0: {
|
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: {
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,10 +48,11 @@ impl<'a> Drop for WriteOnDrop<'a> {
|
||||||
fn drop_first<'a>(a: WriteOnDrop<'a>, b: WriteOnDrop<'a>) {
|
fn drop_first<'a>(a: WriteOnDrop<'a>, b: WriteOnDrop<'a>) {
|
||||||
mir!(
|
mir!(
|
||||||
{
|
{
|
||||||
DropAndReplace(a, Move(b), retblock)
|
Drop(a, retblock)
|
||||||
}
|
}
|
||||||
|
|
||||||
retblock = {
|
retblock = {
|
||||||
|
a = Move(b);
|
||||||
Return()
|
Return()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -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`.
|
||||||
|
}
|
6
tests/ui/traits/new-solver/deduce-ty-from-object.rs
Normal file
6
tests/ui/traits/new-solver/deduce-ty-from-object.rs
Normal 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());
|
||||||
|
}
|
|
@ -21,15 +21,15 @@ union U24<T> { // OK
|
||||||
}
|
}
|
||||||
|
|
||||||
union U3 {
|
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
|
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> {
|
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
|
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
|
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
|
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
|
union U6 { // OK
|
||||||
|
|
|
@ -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
|
--> $DIR/field_checks.rs:24:5
|
||||||
|
|
|
|
||||||
LL | a: String,
|
LL | a: String,
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
|
= note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
|
||||||
help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
|
help: wrap the field type in `ManuallyDrop<...>`
|
||||||
|
|
|
|
||||||
LL | a: std::mem::ManuallyDrop<String>,
|
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
|
--> $DIR/field_checks.rs:28:5
|
||||||
|
|
|
|
||||||
LL | a: std::cell::RefCell<i32>,
|
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
|
= note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
|
||||||
help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
|
help: wrap the field type in `ManuallyDrop<...>`
|
||||||
|
|
|
|
||||||
LL | a: std::mem::ManuallyDrop<std::cell::RefCell<i32>>,
|
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
|
--> $DIR/field_checks.rs:32:5
|
||||||
|
|
|
|
||||||
LL | a: T,
|
LL | a: T,
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
|
|
||||||
= note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
|
= note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
|
||||||
help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
|
help: wrap the field type in `ManuallyDrop<...>`
|
||||||
|
|
|
|
||||||
LL | a: std::mem::ManuallyDrop<T>,
|
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
|
--> $DIR/field_checks.rs:44:5
|
||||||
|
|
|
|
||||||
LL | nest: U5,
|
LL | nest: U5,
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
|
= note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
|
||||||
help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
|
help: wrap the field type in `ManuallyDrop<...>`
|
||||||
|
|
|
|
||||||
LL | nest: std::mem::ManuallyDrop<U5>,
|
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
|
--> $DIR/field_checks.rs:48:5
|
||||||
|
|
|
|
||||||
LL | nest: [U5; 0],
|
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
|
= note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
|
||||||
help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
|
help: wrap the field type in `ManuallyDrop<...>`
|
||||||
|
|
|
|
||||||
LL | nest: std::mem::ManuallyDrop<[U5; 0]>,
|
LL | nest: std::mem::ManuallyDrop<[U5; 0]>,
|
||||||
| +++++++++++++++++++++++ +
|
| +++++++++++++++++++++++ +
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
union Test {
|
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
|
b: B
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
--> $DIR/issue-41073.rs:2:5
|
||||||
|
|
|
|
||||||
LL | a: A,
|
LL | a: A,
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
|
|
||||||
= note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
|
= note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
|
||||||
help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
|
help: wrap the field type in `ManuallyDrop<...>`
|
||||||
|
|
|
|
||||||
LL | a: std::mem::ManuallyDrop<A>,
|
LL | a: std::mem::ManuallyDrop<A>,
|
||||||
| +++++++++++++++++++++++ +
|
| +++++++++++++++++++++++ +
|
||||||
|
|
|
@ -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
|
--> $DIR/union-with-drop-fields.rs:11:5
|
||||||
|
|
|
|
||||||
LL | a: String,
|
LL | a: String,
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
|
= note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
|
||||||
help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
|
help: wrap the field type in `ManuallyDrop<...>`
|
||||||
|
|
|
|
||||||
LL | a: std::mem::ManuallyDrop<String>,
|
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
|
--> $DIR/union-with-drop-fields.rs:19:5
|
||||||
|
|
|
|
||||||
LL | a: S,
|
LL | a: S,
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
|
|
||||||
= note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
|
= note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
|
||||||
help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
|
help: wrap the field type in `ManuallyDrop<...>`
|
||||||
|
|
|
|
||||||
LL | a: std::mem::ManuallyDrop<S>,
|
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
|
--> $DIR/union-with-drop-fields.rs:24:5
|
||||||
|
|
|
|
||||||
LL | a: T,
|
LL | a: T,
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
|
|
||||||
= note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
|
= note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
|
||||||
help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
|
help: wrap the field type in `ManuallyDrop<...>`
|
||||||
|
|
|
|
||||||
LL | a: std::mem::ManuallyDrop<T>,
|
LL | a: std::mem::ManuallyDrop<T>,
|
||||||
| +++++++++++++++++++++++ +
|
| +++++++++++++++++++++++ +
|
||||||
|
|
|
@ -8,7 +8,7 @@ union U {
|
||||||
}
|
}
|
||||||
|
|
||||||
union W {
|
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
|
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
|
// `S` doesn't implement `Drop` trait, but still has non-trivial destructor
|
||||||
union Y {
|
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
|
// We don't know if `T` is trivially-destructable or not until trans
|
||||||
union J<T> {
|
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> {
|
union H<T: Copy> {
|
||||||
|
|
|
@ -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
|
--> $DIR/union-with-drop-fields.rs:11:5
|
||||||
|
|
|
|
||||||
LL | a: String,
|
LL | a: String,
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
|
= note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
|
||||||
help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
|
help: wrap the field type in `ManuallyDrop<...>`
|
||||||
|
|
|
|
||||||
LL | a: std::mem::ManuallyDrop<String>,
|
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
|
--> $DIR/union-with-drop-fields.rs:19:5
|
||||||
|
|
|
|
||||||
LL | a: S,
|
LL | a: S,
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
|
|
||||||
= note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
|
= note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
|
||||||
help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
|
help: wrap the field type in `ManuallyDrop<...>`
|
||||||
|
|
|
|
||||||
LL | a: std::mem::ManuallyDrop<S>,
|
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
|
--> $DIR/union-with-drop-fields.rs:24:5
|
||||||
|
|
|
|
||||||
LL | a: T,
|
LL | a: T,
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
|
|
||||||
= note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
|
= note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
|
||||||
help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
|
help: wrap the field type in `ManuallyDrop<...>`
|
||||||
|
|
|
|
||||||
LL | a: std::mem::ManuallyDrop<T>,
|
LL | a: std::mem::ManuallyDrop<T>,
|
||||||
| +++++++++++++++++++++++ +
|
| +++++++++++++++++++++++ +
|
||||||
|
|
8
tests/ui/union/unresolved-field-isnt-copy.rs
Normal file
8
tests/ui/union/unresolved-field-isnt-copy.rs
Normal 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() {}
|
9
tests/ui/union/unresolved-field-isnt-copy.stderr
Normal file
9
tests/ui/union/unresolved-field-isnt-copy.stderr
Normal 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`.
|
Loading…
Add table
Add a link
Reference in a new issue