mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 08:44:35 +00:00
Auto merge of #124295 - fmease:rollup-i3apkc6, r=fmease
Rollup of 7 pull requests Successful merges: - #120929 (Wrap dyn type with parentheses in suggestion) - #122591 (Suggest using type args directly instead of equality constraint) - #122598 (deref patterns: lower deref patterns to MIR) - #123048 (alloc::Layout: explicitly document size invariant on the type level) - #123993 (Do `check_coroutine_obligations` once per typeck root) - #124218 (Allow nesting subdiagnostics in #[derive(Subdiagnostic)]) - #124285 (Mark ``@RUSTC_BUILTIN`` search path usage as unstable) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
c2f2db79ca
@ -44,7 +44,7 @@ impl Subdiagnostic for InvalidAbiReason {
|
|||||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
self,
|
self,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
_: F,
|
_: &F,
|
||||||
) {
|
) {
|
||||||
#[allow(rustc::untranslatable_diagnostic)]
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
diag.note(self.0);
|
diag.note(self.0);
|
||||||
|
@ -382,7 +382,7 @@ impl Subdiagnostic for EmptyLabelManySpans {
|
|||||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
self,
|
self,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
_: F,
|
_: &F,
|
||||||
) {
|
) {
|
||||||
diag.span_labels(self.0, "");
|
diag.span_labels(self.0, "");
|
||||||
}
|
}
|
||||||
@ -751,7 +751,7 @@ impl Subdiagnostic for StableFeature {
|
|||||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
self,
|
self,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
_: F,
|
_: &F,
|
||||||
) {
|
) {
|
||||||
diag.arg("name", self.name);
|
diag.arg("name", self.name);
|
||||||
diag.arg("since", self.since);
|
diag.arg("since", self.since);
|
||||||
|
@ -69,7 +69,8 @@ impl<'tcx> fmt::Display for BorrowData<'tcx> {
|
|||||||
fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
let kind = match self.kind {
|
let kind = match self.kind {
|
||||||
mir::BorrowKind::Shared => "",
|
mir::BorrowKind::Shared => "",
|
||||||
mir::BorrowKind::Fake => "fake ",
|
mir::BorrowKind::Fake(mir::FakeBorrowKind::Deep) => "fake ",
|
||||||
|
mir::BorrowKind::Fake(mir::FakeBorrowKind::Shallow) => "fake shallow ",
|
||||||
mir::BorrowKind::Mut { kind: mir::MutBorrowKind::ClosureCapture } => "uniq ",
|
mir::BorrowKind::Mut { kind: mir::MutBorrowKind::ClosureCapture } => "uniq ",
|
||||||
// FIXME: differentiate `TwoPhaseBorrow`
|
// FIXME: differentiate `TwoPhaseBorrow`
|
||||||
mir::BorrowKind::Mut {
|
mir::BorrowKind::Mut {
|
||||||
|
@ -17,9 +17,9 @@ use rustc_middle::hir::nested_filter::OnlyBodies;
|
|||||||
use rustc_middle::mir::tcx::PlaceTy;
|
use rustc_middle::mir::tcx::PlaceTy;
|
||||||
use rustc_middle::mir::{
|
use rustc_middle::mir::{
|
||||||
self, AggregateKind, BindingForm, BorrowKind, CallSource, ClearCrossCrate, ConstraintCategory,
|
self, AggregateKind, BindingForm, BorrowKind, CallSource, ClearCrossCrate, ConstraintCategory,
|
||||||
FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, MutBorrowKind, Operand, Place,
|
FakeBorrowKind, FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, MutBorrowKind,
|
||||||
PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
|
Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator,
|
||||||
VarBindingForm,
|
TerminatorKind, VarBindingForm,
|
||||||
};
|
};
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, suggest_constraining_type_params, PredicateKind, ToPredicate, Ty, TyCtxt,
|
self, suggest_constraining_type_params, PredicateKind, ToPredicate, Ty, TyCtxt,
|
||||||
@ -1486,7 +1486,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
let first_borrow_desc;
|
let first_borrow_desc;
|
||||||
let mut err = match (gen_borrow_kind, issued_borrow.kind) {
|
let mut err = match (gen_borrow_kind, issued_borrow.kind) {
|
||||||
(
|
(
|
||||||
BorrowKind::Shared,
|
BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep),
|
||||||
BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow },
|
BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow },
|
||||||
) => {
|
) => {
|
||||||
first_borrow_desc = "mutable ";
|
first_borrow_desc = "mutable ";
|
||||||
@ -1504,7 +1504,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
}
|
}
|
||||||
(
|
(
|
||||||
BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow },
|
BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow },
|
||||||
BorrowKind::Shared,
|
BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep),
|
||||||
) => {
|
) => {
|
||||||
first_borrow_desc = "immutable ";
|
first_borrow_desc = "immutable ";
|
||||||
let mut err = self.cannot_reborrow_already_borrowed(
|
let mut err = self.cannot_reborrow_already_borrowed(
|
||||||
@ -1566,7 +1566,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
self.cannot_uniquely_borrow_by_two_closures(span, &desc_place, issued_span, None)
|
self.cannot_uniquely_borrow_by_two_closures(span, &desc_place, issued_span, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
(BorrowKind::Mut { .. }, BorrowKind::Fake) => {
|
(BorrowKind::Mut { .. }, BorrowKind::Fake(FakeBorrowKind::Shallow)) => {
|
||||||
if let Some(immutable_section_description) =
|
if let Some(immutable_section_description) =
|
||||||
self.classify_immutable_section(issued_borrow.assigned_place)
|
self.classify_immutable_section(issued_borrow.assigned_place)
|
||||||
{
|
{
|
||||||
@ -1629,7 +1629,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
(BorrowKind::Shared, BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }) => {
|
(
|
||||||
|
BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep),
|
||||||
|
BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture },
|
||||||
|
) => {
|
||||||
first_borrow_desc = "first ";
|
first_borrow_desc = "first ";
|
||||||
self.cannot_reborrow_already_uniquely_borrowed(
|
self.cannot_reborrow_already_uniquely_borrowed(
|
||||||
span,
|
span,
|
||||||
@ -1659,8 +1662,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
(BorrowKind::Shared, BorrowKind::Shared | BorrowKind::Fake)
|
(
|
||||||
| (BorrowKind::Fake, BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake) => {
|
BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep),
|
||||||
|
BorrowKind::Shared | BorrowKind::Fake(_),
|
||||||
|
)
|
||||||
|
| (
|
||||||
|
BorrowKind::Fake(FakeBorrowKind::Shallow),
|
||||||
|
BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake(_),
|
||||||
|
) => {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -3572,7 +3581,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
let loan_span = loan_spans.args_or_use();
|
let loan_span = loan_spans.args_or_use();
|
||||||
|
|
||||||
let descr_place = self.describe_any_place(place.as_ref());
|
let descr_place = self.describe_any_place(place.as_ref());
|
||||||
if loan.kind == BorrowKind::Fake {
|
if let BorrowKind::Fake(_) = loan.kind {
|
||||||
if let Some(section) = self.classify_immutable_section(loan.assigned_place) {
|
if let Some(section) = self.classify_immutable_section(loan.assigned_place) {
|
||||||
let mut err = self.cannot_mutate_in_immutable_section(
|
let mut err = self.cannot_mutate_in_immutable_section(
|
||||||
span,
|
span,
|
||||||
|
@ -654,7 +654,7 @@ impl UseSpans<'_> {
|
|||||||
match kind {
|
match kind {
|
||||||
Some(kd) => match kd {
|
Some(kd) => match kd {
|
||||||
rustc_middle::mir::BorrowKind::Shared
|
rustc_middle::mir::BorrowKind::Shared
|
||||||
| rustc_middle::mir::BorrowKind::Fake => {
|
| rustc_middle::mir::BorrowKind::Fake(_) => {
|
||||||
CaptureVarKind::Immut { kind_span: capture_kind_span }
|
CaptureVarKind::Immut { kind_span: capture_kind_span }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1056,18 +1056,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
Control::Continue
|
Control::Continue
|
||||||
}
|
}
|
||||||
|
|
||||||
(Read(_), BorrowKind::Shared | BorrowKind::Fake)
|
(Read(_), BorrowKind::Shared | BorrowKind::Fake(_))
|
||||||
| (Read(ReadKind::Borrow(BorrowKind::Fake)), BorrowKind::Mut { .. }) => {
|
| (
|
||||||
Control::Continue
|
Read(ReadKind::Borrow(BorrowKind::Fake(FakeBorrowKind::Shallow))),
|
||||||
}
|
BorrowKind::Mut { .. },
|
||||||
|
) => Control::Continue,
|
||||||
|
|
||||||
(Reservation(_), BorrowKind::Fake | BorrowKind::Shared) => {
|
(Reservation(_), BorrowKind::Fake(_) | BorrowKind::Shared) => {
|
||||||
// This used to be a future compatibility warning (to be
|
// This used to be a future compatibility warning (to be
|
||||||
// disallowed on NLL). See rust-lang/rust#56254
|
// disallowed on NLL). See rust-lang/rust#56254
|
||||||
Control::Continue
|
Control::Continue
|
||||||
}
|
}
|
||||||
|
|
||||||
(Write(WriteKind::Move), BorrowKind::Fake) => {
|
(Write(WriteKind::Move), BorrowKind::Fake(FakeBorrowKind::Shallow)) => {
|
||||||
// Handled by initialization checks.
|
// Handled by initialization checks.
|
||||||
Control::Continue
|
Control::Continue
|
||||||
}
|
}
|
||||||
@ -1175,10 +1176,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
match rvalue {
|
match rvalue {
|
||||||
&Rvalue::Ref(_ /*rgn*/, bk, place) => {
|
&Rvalue::Ref(_ /*rgn*/, bk, place) => {
|
||||||
let access_kind = match bk {
|
let access_kind = match bk {
|
||||||
BorrowKind::Fake => {
|
BorrowKind::Fake(FakeBorrowKind::Shallow) => {
|
||||||
(Shallow(Some(ArtificialField::FakeBorrow)), Read(ReadKind::Borrow(bk)))
|
(Shallow(Some(ArtificialField::FakeBorrow)), Read(ReadKind::Borrow(bk)))
|
||||||
}
|
}
|
||||||
BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))),
|
BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep) => {
|
||||||
|
(Deep, Read(ReadKind::Borrow(bk)))
|
||||||
|
}
|
||||||
BorrowKind::Mut { .. } => {
|
BorrowKind::Mut { .. } => {
|
||||||
let wk = WriteKind::MutableBorrow(bk);
|
let wk = WriteKind::MutableBorrow(bk);
|
||||||
if allow_two_phase_borrow(bk) {
|
if allow_two_phase_borrow(bk) {
|
||||||
@ -1197,7 +1200,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
flow_state,
|
flow_state,
|
||||||
);
|
);
|
||||||
|
|
||||||
let action = if bk == BorrowKind::Fake {
|
let action = if bk == BorrowKind::Fake(FakeBorrowKind::Shallow) {
|
||||||
InitializationRequiringAction::MatchOn
|
InitializationRequiringAction::MatchOn
|
||||||
} else {
|
} else {
|
||||||
InitializationRequiringAction::Borrow
|
InitializationRequiringAction::Borrow
|
||||||
@ -1557,7 +1560,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
|
|
||||||
// only mutable borrows should be 2-phase
|
// only mutable borrows should be 2-phase
|
||||||
assert!(match borrow.kind {
|
assert!(match borrow.kind {
|
||||||
BorrowKind::Shared | BorrowKind::Fake => false,
|
BorrowKind::Shared | BorrowKind::Fake(_) => false,
|
||||||
BorrowKind::Mut { .. } => true,
|
BorrowKind::Mut { .. } => true,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -2122,14 +2125,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
| WriteKind::Replace
|
| WriteKind::Replace
|
||||||
| WriteKind::StorageDeadOrDrop
|
| WriteKind::StorageDeadOrDrop
|
||||||
| WriteKind::MutableBorrow(BorrowKind::Shared)
|
| WriteKind::MutableBorrow(BorrowKind::Shared)
|
||||||
| WriteKind::MutableBorrow(BorrowKind::Fake),
|
| WriteKind::MutableBorrow(BorrowKind::Fake(_)),
|
||||||
)
|
)
|
||||||
| Write(
|
| Write(
|
||||||
WriteKind::Move
|
WriteKind::Move
|
||||||
| WriteKind::Replace
|
| WriteKind::Replace
|
||||||
| WriteKind::StorageDeadOrDrop
|
| WriteKind::StorageDeadOrDrop
|
||||||
| WriteKind::MutableBorrow(BorrowKind::Shared)
|
| WriteKind::MutableBorrow(BorrowKind::Shared)
|
||||||
| WriteKind::MutableBorrow(BorrowKind::Fake),
|
| WriteKind::MutableBorrow(BorrowKind::Fake(_)),
|
||||||
) => {
|
) => {
|
||||||
if self.is_mutable(place.as_ref(), is_local_mutation_allowed).is_err()
|
if self.is_mutable(place.as_ref(), is_local_mutation_allowed).is_err()
|
||||||
&& !self.has_buffered_diags()
|
&& !self.has_buffered_diags()
|
||||||
@ -2153,7 +2156,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Read(
|
Read(
|
||||||
ReadKind::Borrow(BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake)
|
ReadKind::Borrow(BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake(_))
|
||||||
| ReadKind::Copy,
|
| ReadKind::Copy,
|
||||||
) => {
|
) => {
|
||||||
// Access authorized
|
// Access authorized
|
||||||
|
@ -55,7 +55,7 @@ use crate::Overlap;
|
|||||||
use crate::{AccessDepth, Deep, Shallow};
|
use crate::{AccessDepth, Deep, Shallow};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_middle::mir::{
|
use rustc_middle::mir::{
|
||||||
Body, BorrowKind, MutBorrowKind, Place, PlaceElem, PlaceRef, ProjectionElem,
|
Body, BorrowKind, FakeBorrowKind, MutBorrowKind, Place, PlaceElem, PlaceRef, ProjectionElem,
|
||||||
};
|
};
|
||||||
use rustc_middle::ty::{self, TyCtxt};
|
use rustc_middle::ty::{self, TyCtxt};
|
||||||
use std::cmp::max;
|
use std::cmp::max;
|
||||||
@ -271,10 +271,10 @@ fn place_components_conflict<'tcx>(
|
|||||||
// If the second example, where we did, then we still know
|
// If the second example, where we did, then we still know
|
||||||
// that the borrow can access a *part* of our place that
|
// that the borrow can access a *part* of our place that
|
||||||
// our access cares about, so we still have a conflict.
|
// our access cares about, so we still have a conflict.
|
||||||
if borrow_kind == BorrowKind::Fake
|
if borrow_kind == BorrowKind::Fake(FakeBorrowKind::Shallow)
|
||||||
&& borrow_place.projection.len() < access_place.projection.len()
|
&& borrow_place.projection.len() < access_place.projection.len()
|
||||||
{
|
{
|
||||||
debug!("borrow_conflicts_with_place: fake borrow");
|
debug!("borrow_conflicts_with_place: shallow borrow");
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
debug!("borrow_conflicts_with_place: full borrow, CONFLICT");
|
debug!("borrow_conflicts_with_place: full borrow, CONFLICT");
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
use rustc_data_structures::graph::dominators::Dominators;
|
use rustc_data_structures::graph::dominators::Dominators;
|
||||||
use rustc_middle::mir::visit::Visitor;
|
use rustc_middle::mir::visit::Visitor;
|
||||||
use rustc_middle::mir::{self, BasicBlock, Body, Location, NonDivergingIntrinsic, Place, Rvalue};
|
use rustc_middle::mir::{
|
||||||
|
self, BasicBlock, Body, FakeBorrowKind, Location, NonDivergingIntrinsic, Place, Rvalue,
|
||||||
|
};
|
||||||
use rustc_middle::mir::{BorrowKind, Mutability, Operand};
|
use rustc_middle::mir::{BorrowKind, Mutability, Operand};
|
||||||
use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind};
|
use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind};
|
||||||
use rustc_middle::mir::{Statement, StatementKind};
|
use rustc_middle::mir::{Statement, StatementKind};
|
||||||
@ -239,10 +241,12 @@ impl<'cx, 'tcx> LoanInvalidationsGenerator<'cx, 'tcx> {
|
|||||||
match rvalue {
|
match rvalue {
|
||||||
&Rvalue::Ref(_ /*rgn*/, bk, place) => {
|
&Rvalue::Ref(_ /*rgn*/, bk, place) => {
|
||||||
let access_kind = match bk {
|
let access_kind = match bk {
|
||||||
BorrowKind::Fake => {
|
BorrowKind::Fake(FakeBorrowKind::Shallow) => {
|
||||||
(Shallow(Some(ArtificialField::FakeBorrow)), Read(ReadKind::Borrow(bk)))
|
(Shallow(Some(ArtificialField::FakeBorrow)), Read(ReadKind::Borrow(bk)))
|
||||||
}
|
}
|
||||||
BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))),
|
BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep) => {
|
||||||
|
(Deep, Read(ReadKind::Borrow(bk)))
|
||||||
|
}
|
||||||
BorrowKind::Mut { .. } => {
|
BorrowKind::Mut { .. } => {
|
||||||
let wk = WriteKind::MutableBorrow(bk);
|
let wk = WriteKind::MutableBorrow(bk);
|
||||||
if allow_two_phase_borrow(bk) {
|
if allow_two_phase_borrow(bk) {
|
||||||
@ -357,8 +361,11 @@ impl<'cx, 'tcx> LoanInvalidationsGenerator<'cx, 'tcx> {
|
|||||||
// have already taken the reservation
|
// have already taken the reservation
|
||||||
}
|
}
|
||||||
|
|
||||||
(Read(_), BorrowKind::Fake | BorrowKind::Shared)
|
(Read(_), BorrowKind::Fake(_) | BorrowKind::Shared)
|
||||||
| (Read(ReadKind::Borrow(BorrowKind::Fake)), BorrowKind::Mut { .. }) => {
|
| (
|
||||||
|
Read(ReadKind::Borrow(BorrowKind::Fake(FakeBorrowKind::Shallow))),
|
||||||
|
BorrowKind::Mut { .. },
|
||||||
|
) => {
|
||||||
// Reads don't invalidate shared or shallow borrows
|
// Reads don't invalidate shared or shallow borrows
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -403,7 +410,7 @@ impl<'cx, 'tcx> LoanInvalidationsGenerator<'cx, 'tcx> {
|
|||||||
|
|
||||||
// only mutable borrows should be 2-phase
|
// only mutable borrows should be 2-phase
|
||||||
assert!(match borrow.kind {
|
assert!(match borrow.kind {
|
||||||
BorrowKind::Shared | BorrowKind::Fake => false,
|
BorrowKind::Shared | BorrowKind::Fake(_) => false,
|
||||||
BorrowKind::Mut { .. } => true,
|
BorrowKind::Mut { .. } => true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -601,7 +601,7 @@ impl Subdiagnostic for FormatUnusedArg {
|
|||||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
self,
|
self,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
f: F,
|
f: &F,
|
||||||
) {
|
) {
|
||||||
diag.arg("named", self.named);
|
diag.arg("named", self.named);
|
||||||
let msg = f(diag, crate::fluent_generated::builtin_macros_format_unused_arg.into());
|
let msg = f(diag, crate::fluent_generated::builtin_macros_format_unused_arg.into());
|
||||||
|
@ -414,7 +414,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||||||
BorrowKind::Shared => {
|
BorrowKind::Shared => {
|
||||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow)
|
PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow)
|
||||||
}
|
}
|
||||||
BorrowKind::Fake => {
|
BorrowKind::Fake(_) => {
|
||||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::FakeBorrow)
|
PlaceContext::NonMutatingUse(NonMutatingUseContext::FakeBorrow)
|
||||||
}
|
}
|
||||||
BorrowKind::Mut { .. } => {
|
BorrowKind::Mut { .. } => {
|
||||||
@ -487,7 +487,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Fake, place)
|
Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Fake(_), place)
|
||||||
| Rvalue::AddressOf(Mutability::Not, place) => {
|
| Rvalue::AddressOf(Mutability::Not, place) => {
|
||||||
let borrowed_place_has_mut_interior = qualifs::in_place::<HasMutInterior, _>(
|
let borrowed_place_has_mut_interior = qualifs::in_place::<HasMutInterior, _>(
|
||||||
self.ccx,
|
self.ccx,
|
||||||
|
@ -105,7 +105,7 @@ where
|
|||||||
fn ref_allows_mutation(&self, kind: mir::BorrowKind, place: mir::Place<'tcx>) -> bool {
|
fn ref_allows_mutation(&self, kind: mir::BorrowKind, place: mir::Place<'tcx>) -> bool {
|
||||||
match kind {
|
match kind {
|
||||||
mir::BorrowKind::Mut { .. } => true,
|
mir::BorrowKind::Mut { .. } => true,
|
||||||
mir::BorrowKind::Shared | mir::BorrowKind::Fake => {
|
mir::BorrowKind::Shared | mir::BorrowKind::Fake(_) => {
|
||||||
self.shared_borrow_allows_mutation(place)
|
self.shared_borrow_allows_mutation(place)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -965,7 +965,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Rvalue::Ref(_, BorrowKind::Fake, _) => {
|
Rvalue::Ref(_, BorrowKind::Fake(_), _) => {
|
||||||
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
|
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
|
||||||
self.fail(
|
self.fail(
|
||||||
location,
|
location,
|
||||||
|
@ -177,7 +177,7 @@ where
|
|||||||
{
|
{
|
||||||
/// Add a subdiagnostic to an existing diagnostic.
|
/// Add a subdiagnostic to an existing diagnostic.
|
||||||
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
|
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
|
||||||
self.add_to_diag_with(diag, |_, m| m);
|
self.add_to_diag_with(diag, &|_, m| m);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a subdiagnostic to an existing diagnostic where `f` is invoked on every message used
|
/// Add a subdiagnostic to an existing diagnostic where `f` is invoked on every message used
|
||||||
@ -185,7 +185,7 @@ where
|
|||||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
self,
|
self,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
f: F,
|
f: &F,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1197,7 +1197,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
|
|||||||
dcx: &crate::DiagCtxt,
|
dcx: &crate::DiagCtxt,
|
||||||
subdiagnostic: impl Subdiagnostic,
|
subdiagnostic: impl Subdiagnostic,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
subdiagnostic.add_to_diag_with(self, |diag, msg| {
|
subdiagnostic.add_to_diag_with(self, &|diag, msg| {
|
||||||
let args = diag.args.iter();
|
let args = diag.args.iter();
|
||||||
let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
|
let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
|
||||||
dcx.eagerly_translate(msg, args)
|
dcx.eagerly_translate(msg, args)
|
||||||
|
@ -227,6 +227,36 @@ impl IntoDiagArg for rustc_lint_defs::Level {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<Id> IntoDiagArg for hir::def::Res<Id> {
|
||||||
|
fn into_diag_arg(self) -> DiagArgValue {
|
||||||
|
DiagArgValue::Str(Cow::Borrowed(self.descr()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoDiagArg for DiagLocation {
|
||||||
|
fn into_diag_arg(self) -> DiagArgValue {
|
||||||
|
DiagArgValue::Str(Cow::from(self.to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoDiagArg for Backtrace {
|
||||||
|
fn into_diag_arg(self) -> DiagArgValue {
|
||||||
|
DiagArgValue::Str(Cow::from(self.to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoDiagArg for Level {
|
||||||
|
fn into_diag_arg(self) -> DiagArgValue {
|
||||||
|
DiagArgValue::Str(Cow::from(self.to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoDiagArg for type_ir::ClosureKind {
|
||||||
|
fn into_diag_arg(self) -> DiagArgValue {
|
||||||
|
DiagArgValue::Str(self.as_str().into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct DiagSymbolList(Vec<Symbol>);
|
pub struct DiagSymbolList(Vec<Symbol>);
|
||||||
|
|
||||||
@ -244,12 +274,6 @@ impl IntoDiagArg for DiagSymbolList {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Id> IntoDiagArg for hir::def::Res<Id> {
|
|
||||||
fn into_diag_arg(self) -> DiagArgValue {
|
|
||||||
DiagArgValue::Str(Cow::Borrowed(self.descr()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetDataLayoutErrors<'_> {
|
impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetDataLayoutErrors<'_> {
|
||||||
fn into_diag(self, dcx: &DiagCtxt, level: Level) -> Diag<'_, G> {
|
fn into_diag(self, dcx: &DiagCtxt, level: Level) -> Diag<'_, G> {
|
||||||
match self {
|
match self {
|
||||||
@ -302,7 +326,7 @@ impl Subdiagnostic for SingleLabelManySpans {
|
|||||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
self,
|
self,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
_: F,
|
_: &F,
|
||||||
) {
|
) {
|
||||||
diag.span_labels(self.spans, self.label);
|
diag.span_labels(self.spans, self.label);
|
||||||
}
|
}
|
||||||
@ -316,24 +340,6 @@ pub struct ExpectedLifetimeParameter {
|
|||||||
pub count: usize,
|
pub count: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoDiagArg for DiagLocation {
|
|
||||||
fn into_diag_arg(self) -> DiagArgValue {
|
|
||||||
DiagArgValue::Str(Cow::from(self.to_string()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IntoDiagArg for Backtrace {
|
|
||||||
fn into_diag_arg(self) -> DiagArgValue {
|
|
||||||
DiagArgValue::Str(Cow::from(self.to_string()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IntoDiagArg for Level {
|
|
||||||
fn into_diag_arg(self) -> DiagArgValue {
|
|
||||||
DiagArgValue::Str(Cow::from(self.to_string()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
#[suggestion(errors_indicate_anonymous_lifetime, code = "{suggestion}", style = "verbose")]
|
#[suggestion(errors_indicate_anonymous_lifetime, code = "{suggestion}", style = "verbose")]
|
||||||
pub struct IndicateAnonymousLifetime {
|
pub struct IndicateAnonymousLifetime {
|
||||||
@ -343,8 +349,10 @@ pub struct IndicateAnonymousLifetime {
|
|||||||
pub suggestion: String,
|
pub suggestion: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoDiagArg for type_ir::ClosureKind {
|
#[derive(Subdiagnostic)]
|
||||||
fn into_diag_arg(self) -> DiagArgValue {
|
pub struct ElidedLifetimeInPathSubdiag {
|
||||||
DiagArgValue::Str(self.as_str().into())
|
#[subdiagnostic]
|
||||||
}
|
pub expected: ExpectedLifetimeParameter,
|
||||||
|
#[subdiagnostic]
|
||||||
|
pub indicate: Option<IndicateAnonymousLifetime>,
|
||||||
}
|
}
|
||||||
|
@ -40,8 +40,8 @@ pub use diagnostic::{
|
|||||||
SubdiagMessageOp, Subdiagnostic,
|
SubdiagMessageOp, Subdiagnostic,
|
||||||
};
|
};
|
||||||
pub use diagnostic_impls::{
|
pub use diagnostic_impls::{
|
||||||
DiagArgFromDisplay, DiagSymbolList, ExpectedLifetimeParameter, IndicateAnonymousLifetime,
|
DiagArgFromDisplay, DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter,
|
||||||
SingleLabelManySpans,
|
IndicateAnonymousLifetime, SingleLabelManySpans,
|
||||||
};
|
};
|
||||||
pub use emitter::ColorConfig;
|
pub use emitter::ColorConfig;
|
||||||
pub use rustc_error_messages::{
|
pub use rustc_error_messages::{
|
||||||
@ -1911,27 +1911,24 @@ impl Level {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(eddyb) this doesn't belong here AFAICT, should be moved to callsite.
|
// FIXME(eddyb) this doesn't belong here AFAICT, should be moved to callsite.
|
||||||
pub fn add_elided_lifetime_in_path_suggestion<G: EmissionGuarantee>(
|
pub fn elided_lifetime_in_path_suggestion(
|
||||||
source_map: &SourceMap,
|
source_map: &SourceMap,
|
||||||
diag: &mut Diag<'_, G>,
|
|
||||||
n: usize,
|
n: usize,
|
||||||
path_span: Span,
|
path_span: Span,
|
||||||
incl_angl_brckt: bool,
|
incl_angl_brckt: bool,
|
||||||
insertion_span: Span,
|
insertion_span: Span,
|
||||||
) {
|
) -> ElidedLifetimeInPathSubdiag {
|
||||||
diag.subdiagnostic(diag.dcx, ExpectedLifetimeParameter { span: path_span, count: n });
|
let expected = ExpectedLifetimeParameter { span: path_span, count: n };
|
||||||
if !source_map.is_span_accessible(insertion_span) {
|
// Do not try to suggest anything if generated by a proc-macro.
|
||||||
// Do not try to suggest anything if generated by a proc-macro.
|
let indicate = source_map.is_span_accessible(insertion_span).then(|| {
|
||||||
return;
|
let anon_lts = vec!["'_"; n].join(", ");
|
||||||
}
|
let suggestion =
|
||||||
let anon_lts = vec!["'_"; n].join(", ");
|
if incl_angl_brckt { format!("<{anon_lts}>") } else { format!("{anon_lts}, ") };
|
||||||
let suggestion =
|
|
||||||
if incl_angl_brckt { format!("<{anon_lts}>") } else { format!("{anon_lts}, ") };
|
|
||||||
|
|
||||||
diag.subdiagnostic(
|
IndicateAnonymousLifetime { span: insertion_span.shrink_to_hi(), count: n, suggestion }
|
||||||
diag.dcx,
|
});
|
||||||
IndicateAnonymousLifetime { span: insertion_span.shrink_to_hi(), count: n, suggestion },
|
|
||||||
);
|
ElidedLifetimeInPathSubdiag { expected, indicate }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn report_ambiguity_error<'a, G: EmissionGuarantee>(
|
pub fn report_ambiguity_error<'a, G: EmissionGuarantee>(
|
||||||
|
@ -644,13 +644,49 @@ impl<'hir> Generics<'hir> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bounds_span_for_suggestions(&self, param_def_id: LocalDefId) -> Option<Span> {
|
/// Returns a suggestable empty span right after the "final" bound of the generic parameter.
|
||||||
|
///
|
||||||
|
/// If that bound needs to be wrapped in parentheses to avoid ambiguity with
|
||||||
|
/// subsequent bounds, it also returns an empty span for an open parenthesis
|
||||||
|
/// as the second component.
|
||||||
|
///
|
||||||
|
/// E.g., adding `+ 'static` after `Fn() -> dyn Future<Output = ()>` or
|
||||||
|
/// `Fn() -> &'static dyn Debug` requires parentheses:
|
||||||
|
/// `Fn() -> (dyn Future<Output = ()>) + 'static` and
|
||||||
|
/// `Fn() -> &'static (dyn Debug) + 'static`, respectively.
|
||||||
|
pub fn bounds_span_for_suggestions(
|
||||||
|
&self,
|
||||||
|
param_def_id: LocalDefId,
|
||||||
|
) -> Option<(Span, Option<Span>)> {
|
||||||
self.bounds_for_param(param_def_id).flat_map(|bp| bp.bounds.iter().rev()).find_map(
|
self.bounds_for_param(param_def_id).flat_map(|bp| bp.bounds.iter().rev()).find_map(
|
||||||
|bound| {
|
|bound| {
|
||||||
// We include bounds that come from a `#[derive(_)]` but point at the user's code,
|
let span_for_parentheses = if let Some(trait_ref) = bound.trait_ref()
|
||||||
// as we use this method to get a span appropriate for suggestions.
|
&& let [.., segment] = trait_ref.path.segments
|
||||||
let bs = bound.span();
|
&& segment.args().parenthesized == GenericArgsParentheses::ParenSugar
|
||||||
bs.can_be_used_for_suggestions().then(|| bs.shrink_to_hi())
|
&& let [binding] = segment.args().bindings
|
||||||
|
&& let TypeBindingKind::Equality { term: Term::Ty(ret_ty) } = binding.kind
|
||||||
|
&& let ret_ty = ret_ty.peel_refs()
|
||||||
|
&& let TyKind::TraitObject(
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
TraitObjectSyntax::Dyn | TraitObjectSyntax::DynStar,
|
||||||
|
) = ret_ty.kind
|
||||||
|
&& ret_ty.span.can_be_used_for_suggestions()
|
||||||
|
{
|
||||||
|
Some(ret_ty.span)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
span_for_parentheses.map_or_else(
|
||||||
|
|| {
|
||||||
|
// We include bounds that come from a `#[derive(_)]` but point at the user's code,
|
||||||
|
// as we use this method to get a span appropriate for suggestions.
|
||||||
|
let bs = bound.span();
|
||||||
|
bs.can_be_used_for_suggestions().then(|| (bs.shrink_to_hi(), None))
|
||||||
|
},
|
||||||
|
|span| Some((span.shrink_to_hi(), Some(span.shrink_to_lo()))),
|
||||||
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -10,11 +10,10 @@ use rustc_hir as hir;
|
|||||||
use rustc_hir::def::{CtorKind, DefKind};
|
use rustc_hir::def::{CtorKind, DefKind};
|
||||||
use rustc_hir::Node;
|
use rustc_hir::Node;
|
||||||
use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
|
use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
|
||||||
use rustc_infer::traits::{Obligation, TraitEngineExt as _};
|
use rustc_infer::traits::Obligation;
|
||||||
use rustc_lint_defs::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
|
use rustc_lint_defs::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
|
||||||
use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
|
use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
|
||||||
use rustc_middle::middle::stability::EvalResult;
|
use rustc_middle::middle::stability::EvalResult;
|
||||||
use rustc_middle::traits::ObligationCauseCode;
|
|
||||||
use rustc_middle::ty::fold::BottomUpFolder;
|
use rustc_middle::ty::fold::BottomUpFolder;
|
||||||
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
|
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
|
||||||
use rustc_middle::ty::util::{Discr, InspectCoroutineFields, IntTypeExt};
|
use rustc_middle::ty::util::{Discr, InspectCoroutineFields, IntTypeExt};
|
||||||
@ -24,10 +23,10 @@ use rustc_middle::ty::{
|
|||||||
};
|
};
|
||||||
use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS};
|
use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS};
|
||||||
use rustc_target::abi::FieldIdx;
|
use rustc_target::abi::FieldIdx;
|
||||||
|
use rustc_trait_selection::traits;
|
||||||
use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedDirective;
|
use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedDirective;
|
||||||
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
|
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
|
||||||
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
|
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
|
||||||
use rustc_trait_selection::traits::{self, TraitEngine, TraitEngineExt as _};
|
|
||||||
use rustc_type_ir::fold::TypeFoldable;
|
use rustc_type_ir::fold::TypeFoldable;
|
||||||
|
|
||||||
use std::cell::LazyCell;
|
use std::cell::LazyCell;
|
||||||
@ -1715,55 +1714,31 @@ fn opaque_type_cycle_error(
|
|||||||
err.emit()
|
err.emit()
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(@lcnr): This should not be computed per coroutine, but instead once for
|
|
||||||
// each typeck root.
|
|
||||||
pub(super) fn check_coroutine_obligations(
|
pub(super) fn check_coroutine_obligations(
|
||||||
tcx: TyCtxt<'_>,
|
tcx: TyCtxt<'_>,
|
||||||
def_id: LocalDefId,
|
def_id: LocalDefId,
|
||||||
) -> Result<(), ErrorGuaranteed> {
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
debug_assert!(tcx.is_coroutine(def_id.to_def_id()));
|
debug_assert!(!tcx.is_typeck_child(def_id.to_def_id()));
|
||||||
|
|
||||||
let typeck = tcx.typeck(def_id);
|
let typeck_results = tcx.typeck(def_id);
|
||||||
let param_env = tcx.param_env(typeck.hir_owner.def_id);
|
let param_env = tcx.param_env(def_id);
|
||||||
|
|
||||||
let coroutine_interior_predicates = &typeck.coroutine_interior_predicates[&def_id];
|
debug!(?typeck_results.coroutine_stalled_predicates);
|
||||||
debug!(?coroutine_interior_predicates);
|
|
||||||
|
|
||||||
let infcx = tcx
|
let infcx = tcx
|
||||||
.infer_ctxt()
|
.infer_ctxt()
|
||||||
// typeck writeback gives us predicates with their regions erased.
|
// typeck writeback gives us predicates with their regions erased.
|
||||||
// As borrowck already has checked lifetimes, we do not need to do it again.
|
// As borrowck already has checked lifetimes, we do not need to do it again.
|
||||||
.ignoring_regions()
|
.ignoring_regions()
|
||||||
// Bind opaque types to type checking root, as they should have been checked by borrowck,
|
.with_opaque_type_inference(def_id)
|
||||||
// but may show up in some cases, like when (root) obligations are stalled in the new solver.
|
|
||||||
.with_opaque_type_inference(typeck.hir_owner.def_id)
|
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let mut fulfillment_cx = <dyn TraitEngine<'_>>::new(&infcx);
|
let ocx = ObligationCtxt::new(&infcx);
|
||||||
for (predicate, cause) in coroutine_interior_predicates {
|
for (predicate, cause) in &typeck_results.coroutine_stalled_predicates {
|
||||||
let obligation = Obligation::new(tcx, cause.clone(), param_env, *predicate);
|
ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, *predicate));
|
||||||
fulfillment_cx.register_predicate_obligation(&infcx, obligation);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tcx.features().unsized_locals || tcx.features().unsized_fn_params)
|
let errors = ocx.select_all_or_error();
|
||||||
&& let Some(coroutine) = tcx.mir_coroutine_witnesses(def_id)
|
|
||||||
{
|
|
||||||
for field_ty in coroutine.field_tys.iter() {
|
|
||||||
fulfillment_cx.register_bound(
|
|
||||||
&infcx,
|
|
||||||
param_env,
|
|
||||||
field_ty.ty,
|
|
||||||
tcx.require_lang_item(hir::LangItem::Sized, Some(field_ty.source_info.span)),
|
|
||||||
ObligationCause::new(
|
|
||||||
field_ty.source_info.span,
|
|
||||||
def_id,
|
|
||||||
ObligationCauseCode::SizedCoroutineInterior(def_id),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let errors = fulfillment_cx.select_all_or_error(&infcx);
|
|
||||||
debug!(?errors);
|
debug!(?errors);
|
||||||
if !errors.is_empty() {
|
if !errors.is_empty() {
|
||||||
return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
|
return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
|
||||||
|
@ -17,6 +17,7 @@ use rustc_hir::def::{DefKind, Res};
|
|||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_infer::traits::FulfillmentError;
|
use rustc_infer::traits::FulfillmentError;
|
||||||
use rustc_middle::query::Key;
|
use rustc_middle::query::Key;
|
||||||
|
use rustc_middle::ty::GenericParamDefKind;
|
||||||
use rustc_middle::ty::{self, suggest_constraining_type_param};
|
use rustc_middle::ty::{self, suggest_constraining_type_param};
|
||||||
use rustc_middle::ty::{AdtDef, Ty, TyCtxt, TypeVisitableExt};
|
use rustc_middle::ty::{AdtDef, Ty, TyCtxt, TypeVisitableExt};
|
||||||
use rustc_middle::ty::{Binder, TraitRef};
|
use rustc_middle::ty::{Binder, TraitRef};
|
||||||
@ -1200,12 +1201,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||||||
/// Emits an error regarding forbidden type binding associations
|
/// Emits an error regarding forbidden type binding associations
|
||||||
pub fn prohibit_assoc_item_binding(
|
pub fn prohibit_assoc_item_binding(
|
||||||
tcx: TyCtxt<'_>,
|
tcx: TyCtxt<'_>,
|
||||||
span: Span,
|
binding: &hir::TypeBinding<'_>,
|
||||||
segment: Option<(&hir::PathSegment<'_>, Span)>,
|
segment: Option<(DefId, &hir::PathSegment<'_>, Span)>,
|
||||||
) -> ErrorGuaranteed {
|
) -> ErrorGuaranteed {
|
||||||
tcx.dcx().emit_err(AssocTypeBindingNotAllowed {
|
let mut err = tcx.dcx().create_err(AssocTypeBindingNotAllowed {
|
||||||
span,
|
span: binding.span,
|
||||||
fn_trait_expansion: if let Some((segment, span)) = segment
|
fn_trait_expansion: if let Some((_, segment, span)) = segment
|
||||||
&& segment.args().parenthesized == hir::GenericArgsParentheses::ParenSugar
|
&& segment.args().parenthesized == hir::GenericArgsParentheses::ParenSugar
|
||||||
{
|
{
|
||||||
Some(ParenthesizedFnTraitExpansion {
|
Some(ParenthesizedFnTraitExpansion {
|
||||||
@ -1215,7 +1216,109 @@ pub fn prohibit_assoc_item_binding(
|
|||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
|
// Emit a suggestion to turn the assoc item binding into a generic arg
|
||||||
|
// if the relevant item has a generic param whose name matches the binding name;
|
||||||
|
// otherwise suggest the removal of the binding.
|
||||||
|
if let Some((def_id, segment, _)) = segment
|
||||||
|
&& segment.args().parenthesized == hir::GenericArgsParentheses::No
|
||||||
|
&& let hir::TypeBindingKind::Equality { term } = binding.kind
|
||||||
|
{
|
||||||
|
// Suggests removal of the offending binding
|
||||||
|
let suggest_removal = |e: &mut Diag<'_>| {
|
||||||
|
let bindings = segment.args().bindings;
|
||||||
|
let args = segment.args().args;
|
||||||
|
let binding_span = binding.span;
|
||||||
|
|
||||||
|
// Compute the span to remove based on the position
|
||||||
|
// of the binding. We do that as follows:
|
||||||
|
// 1. Find the index of the binding in the list of bindings
|
||||||
|
// 2. Locate the spans preceding and following the binding.
|
||||||
|
// If it's the first binding the preceding span would be
|
||||||
|
// that of the last arg
|
||||||
|
// 3. Using this information work out whether the span
|
||||||
|
// to remove will start from the end of the preceding span,
|
||||||
|
// the start of the next span or will simply be the
|
||||||
|
// span encomassing everything within the generics brackets
|
||||||
|
|
||||||
|
let Some(binding_index) = bindings.iter().position(|b| b.hir_id == binding.hir_id)
|
||||||
|
else {
|
||||||
|
bug!("a type binding exists but its HIR ID not found in generics");
|
||||||
|
};
|
||||||
|
|
||||||
|
let preceding_span = if binding_index > 0 {
|
||||||
|
Some(bindings[binding_index - 1].span)
|
||||||
|
} else {
|
||||||
|
args.last().map(|a| a.span())
|
||||||
|
};
|
||||||
|
|
||||||
|
let next_span = if binding_index < bindings.len() - 1 {
|
||||||
|
Some(bindings[binding_index + 1].span)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let removal_span = match (preceding_span, next_span) {
|
||||||
|
(Some(prec), _) => binding_span.with_lo(prec.hi()),
|
||||||
|
(None, Some(next)) => binding_span.with_hi(next.lo()),
|
||||||
|
(None, None) => {
|
||||||
|
let Some(generics_span) = segment.args().span_ext() else {
|
||||||
|
bug!("a type binding exists but generic span is empty");
|
||||||
|
};
|
||||||
|
|
||||||
|
generics_span
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Now emit the suggestion
|
||||||
|
if let Ok(suggestion) = tcx.sess.source_map().span_to_snippet(removal_span) {
|
||||||
|
e.span_suggestion_verbose(
|
||||||
|
removal_span,
|
||||||
|
"consider removing this type binding",
|
||||||
|
suggestion,
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Suggest replacing the associated item binding with a generic argument.
|
||||||
|
// i.e., replacing `<..., T = A, ...>` with `<..., A, ...>`.
|
||||||
|
let suggest_direct_use = |e: &mut Diag<'_>, sp: Span| {
|
||||||
|
if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(sp) {
|
||||||
|
e.span_suggestion_verbose(
|
||||||
|
binding.span,
|
||||||
|
format!("to use `{snippet}` as a generic argument specify it directly"),
|
||||||
|
snippet,
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check if the type has a generic param with the
|
||||||
|
// same name as the assoc type name in type binding
|
||||||
|
let generics = tcx.generics_of(def_id);
|
||||||
|
let matching_param =
|
||||||
|
generics.params.iter().find(|p| p.name.as_str() == binding.ident.as_str());
|
||||||
|
|
||||||
|
// Now emit the appropriate suggestion
|
||||||
|
if let Some(matching_param) = matching_param {
|
||||||
|
match (&matching_param.kind, term) {
|
||||||
|
(GenericParamDefKind::Type { .. }, hir::Term::Ty(ty)) => {
|
||||||
|
suggest_direct_use(&mut err, ty.span);
|
||||||
|
}
|
||||||
|
(GenericParamDefKind::Const { .. }, hir::Term::Const(c)) => {
|
||||||
|
let span = tcx.hir().span(c.hir_id);
|
||||||
|
suggest_direct_use(&mut err, span);
|
||||||
|
}
|
||||||
|
_ => suggest_removal(&mut err),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
suggest_removal(&mut err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err.emit()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn fn_trait_to_string(
|
pub(crate) fn fn_trait_to_string(
|
||||||
|
@ -454,7 +454,7 @@ pub(crate) fn check_generic_arg_count(
|
|||||||
if gen_pos != GenericArgPosition::Type
|
if gen_pos != GenericArgPosition::Type
|
||||||
&& let Some(b) = gen_args.bindings.first()
|
&& let Some(b) = gen_args.bindings.first()
|
||||||
{
|
{
|
||||||
prohibit_assoc_item_binding(tcx, b.span, None);
|
prohibit_assoc_item_binding(tcx, b, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
let explicit_late_bound =
|
let explicit_late_bound =
|
||||||
|
@ -323,7 +323,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||||||
ty::BoundConstness::NotConst,
|
ty::BoundConstness::NotConst,
|
||||||
);
|
);
|
||||||
if let Some(b) = item_segment.args().bindings.first() {
|
if let Some(b) = item_segment.args().bindings.first() {
|
||||||
prohibit_assoc_item_binding(self.tcx(), b.span, Some((item_segment, span)));
|
prohibit_assoc_item_binding(self.tcx(), b, Some((def_id, item_segment, span)));
|
||||||
}
|
}
|
||||||
args
|
args
|
||||||
}
|
}
|
||||||
@ -620,7 +620,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||||||
ty::BoundConstness::NotConst,
|
ty::BoundConstness::NotConst,
|
||||||
);
|
);
|
||||||
if let Some(b) = item_segment.args().bindings.first() {
|
if let Some(b) = item_segment.args().bindings.first() {
|
||||||
prohibit_assoc_item_binding(self.tcx(), b.span, Some((item_segment, span)));
|
prohibit_assoc_item_binding(self.tcx(), b, Some((item_def_id, item_segment, span)));
|
||||||
}
|
}
|
||||||
args
|
args
|
||||||
}
|
}
|
||||||
@ -765,7 +765,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||||||
constness,
|
constness,
|
||||||
);
|
);
|
||||||
if let Some(b) = trait_segment.args().bindings.first() {
|
if let Some(b) = trait_segment.args().bindings.first() {
|
||||||
prohibit_assoc_item_binding(self.tcx(), b.span, Some((trait_segment, span)));
|
prohibit_assoc_item_binding(self.tcx(), b, Some((trait_def_id, trait_segment, span)));
|
||||||
}
|
}
|
||||||
ty::TraitRef::new(self.tcx(), trait_def_id, generic_args)
|
ty::TraitRef::new(self.tcx(), trait_def_id, generic_args)
|
||||||
}
|
}
|
||||||
@ -1544,7 +1544,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||||||
for segment in segments {
|
for segment in segments {
|
||||||
// Only emit the first error to avoid overloading the user with error messages.
|
// Only emit the first error to avoid overloading the user with error messages.
|
||||||
if let Some(b) = segment.args().bindings.first() {
|
if let Some(b) = segment.args().bindings.first() {
|
||||||
return Err(prohibit_assoc_item_binding(self.tcx(), b.span, None));
|
return Err(prohibit_assoc_item_binding(self.tcx(), b, None));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,7 +191,7 @@ impl Subdiagnostic for TypeMismatchFruTypo {
|
|||||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
self,
|
self,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
_f: F,
|
_f: &F,
|
||||||
) {
|
) {
|
||||||
diag.arg("expr", self.expr.as_deref().unwrap_or("NONE"));
|
diag.arg("expr", self.expr.as_deref().unwrap_or("NONE"));
|
||||||
|
|
||||||
@ -370,7 +370,7 @@ impl Subdiagnostic for RemoveSemiForCoerce {
|
|||||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
self,
|
self,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
_f: F,
|
_f: &F,
|
||||||
) {
|
) {
|
||||||
let mut multispan: MultiSpan = self.semi.into();
|
let mut multispan: MultiSpan = self.semi.into();
|
||||||
multispan.push_span_label(self.expr, fluent::hir_typeck_remove_semi_for_coerce_expr);
|
multispan.push_span_label(self.expr, fluent::hir_typeck_remove_semi_for_coerce_expr);
|
||||||
@ -546,7 +546,7 @@ impl rustc_errors::Subdiagnostic for CastUnknownPointerSub {
|
|||||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
self,
|
self,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
f: F,
|
f: &F,
|
||||||
) {
|
) {
|
||||||
match self {
|
match self {
|
||||||
CastUnknownPointerSub::To(span) => {
|
CastUnknownPointerSub::To(span) => {
|
||||||
|
@ -750,6 +750,15 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if let PatKind::Deref(subpattern) = pat.kind {
|
||||||
|
// A deref pattern is a bit special: the binding mode of its inner bindings
|
||||||
|
// determines whether to borrow *at the level of the deref pattern* rather than
|
||||||
|
// borrowing the bound place (since that inner place is inside the temporary that
|
||||||
|
// stores the result of calling `deref()`/`deref_mut()` so can't be captured).
|
||||||
|
let mutable = mc.typeck_results.pat_has_ref_mut_binding(subpattern);
|
||||||
|
let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
|
||||||
|
let bk = ty::BorrowKind::from_mutbl(mutability);
|
||||||
|
delegate.borrow(place, discr_place.hir_id, bk);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
@ -588,12 +588,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
obligations
|
obligations
|
||||||
.extend(self.fulfillment_cx.borrow_mut().drain_unstalled_obligations(&self.infcx));
|
.extend(self.fulfillment_cx.borrow_mut().drain_unstalled_obligations(&self.infcx));
|
||||||
|
|
||||||
let obligations = obligations.into_iter().map(|o| (o.predicate, o.cause)).collect();
|
let obligations = obligations.into_iter().map(|o| (o.predicate, o.cause));
|
||||||
debug!(?obligations);
|
self.typeck_results.borrow_mut().coroutine_stalled_predicates.extend(obligations);
|
||||||
self.typeck_results
|
|
||||||
.borrow_mut()
|
|
||||||
.coroutine_interior_predicates
|
|
||||||
.insert(expr_def_id, obligations);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ use rustc_hir::{
|
|||||||
};
|
};
|
||||||
use rustc_hir_analysis::collect::suggest_impl_trait;
|
use rustc_hir_analysis::collect::suggest_impl_trait;
|
||||||
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
|
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
|
||||||
use rustc_infer::traits::{self};
|
use rustc_infer::traits;
|
||||||
use rustc_middle::lint::in_external_macro;
|
use rustc_middle::lint::in_external_macro;
|
||||||
use rustc_middle::middle::stability::EvalResult;
|
use rustc_middle::middle::stability::EvalResult;
|
||||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||||
|
@ -711,13 +711,23 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
|
|||||||
self.cat_pattern_(place_with_id, subpat, op)?;
|
self.cat_pattern_(place_with_id, subpat, op)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
PatKind::Box(subpat) | PatKind::Ref(subpat, _) | PatKind::Deref(subpat) => {
|
PatKind::Box(subpat) | PatKind::Ref(subpat, _) => {
|
||||||
// box p1, &p1, &mut p1. we can ignore the mutability of
|
// box p1, &p1, &mut p1. we can ignore the mutability of
|
||||||
// PatKind::Ref since that information is already contained
|
// PatKind::Ref since that information is already contained
|
||||||
// in the type.
|
// in the type.
|
||||||
let subplace = self.cat_deref(pat, place_with_id)?;
|
let subplace = self.cat_deref(pat, place_with_id)?;
|
||||||
self.cat_pattern_(subplace, subpat, op)?;
|
self.cat_pattern_(subplace, subpat, op)?;
|
||||||
}
|
}
|
||||||
|
PatKind::Deref(subpat) => {
|
||||||
|
let mutable = self.typeck_results.pat_has_ref_mut_binding(subpat);
|
||||||
|
let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
|
||||||
|
let re_erased = self.tcx().lifetimes.re_erased;
|
||||||
|
let ty = self.pat_ty_adjusted(subpat)?;
|
||||||
|
let ty = Ty::new_ref(self.tcx(), re_erased, ty, mutability);
|
||||||
|
// A deref pattern generates a temporary.
|
||||||
|
let place = self.cat_rvalue(pat.hir_id, ty);
|
||||||
|
self.cat_pattern_(place, subpat, op)?;
|
||||||
|
}
|
||||||
|
|
||||||
PatKind::Slice(before, ref slice, after) => {
|
PatKind::Slice(before, ref slice, after) => {
|
||||||
let Some(element_ty) = place_with_id.place.ty().builtin_index() else {
|
let Some(element_ty) = place_with_id.place.ty().builtin_index() else {
|
||||||
|
@ -3291,14 +3291,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
param.name.ident(),
|
param.name.ident(),
|
||||||
));
|
));
|
||||||
let bounds_span = hir_generics.bounds_span_for_suggestions(def_id);
|
let bounds_span = hir_generics.bounds_span_for_suggestions(def_id);
|
||||||
if rcvr_ty.is_ref() && param.is_impl_trait() && bounds_span.is_some() {
|
if rcvr_ty.is_ref()
|
||||||
|
&& param.is_impl_trait()
|
||||||
|
&& let Some((bounds_span, _)) = bounds_span
|
||||||
|
{
|
||||||
err.multipart_suggestions(
|
err.multipart_suggestions(
|
||||||
msg,
|
msg,
|
||||||
candidates.iter().map(|t| {
|
candidates.iter().map(|t| {
|
||||||
vec![
|
vec![
|
||||||
(param.span.shrink_to_lo(), "(".to_string()),
|
(param.span.shrink_to_lo(), "(".to_string()),
|
||||||
(
|
(
|
||||||
bounds_span.unwrap(),
|
bounds_span,
|
||||||
format!(" + {})", self.tcx.def_path_str(t.def_id)),
|
format!(" + {})", self.tcx.def_path_str(t.def_id)),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
@ -3308,32 +3311,46 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (sp, introducer) = if let Some(span) = bounds_span {
|
let (sp, introducer, open_paren_sp) =
|
||||||
(span, Introducer::Plus)
|
if let Some((span, open_paren_sp)) = bounds_span {
|
||||||
} else if let Some(colon_span) = param.colon_span {
|
(span, Introducer::Plus, open_paren_sp)
|
||||||
(colon_span.shrink_to_hi(), Introducer::Nothing)
|
} else if let Some(colon_span) = param.colon_span {
|
||||||
} else if param.is_impl_trait() {
|
(colon_span.shrink_to_hi(), Introducer::Nothing, None)
|
||||||
(param.span.shrink_to_hi(), Introducer::Plus)
|
} else if param.is_impl_trait() {
|
||||||
} else {
|
(param.span.shrink_to_hi(), Introducer::Plus, None)
|
||||||
(param.span.shrink_to_hi(), Introducer::Colon)
|
} else {
|
||||||
};
|
(param.span.shrink_to_hi(), Introducer::Colon, None)
|
||||||
|
};
|
||||||
|
|
||||||
err.span_suggestions(
|
let all_suggs = candidates.iter().map(|cand| {
|
||||||
sp,
|
let suggestion = format!(
|
||||||
|
"{} {}",
|
||||||
|
match introducer {
|
||||||
|
Introducer::Plus => " +",
|
||||||
|
Introducer::Colon => ":",
|
||||||
|
Introducer::Nothing => "",
|
||||||
|
},
|
||||||
|
self.tcx.def_path_str(cand.def_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut suggs = vec![];
|
||||||
|
|
||||||
|
if let Some(open_paren_sp) = open_paren_sp {
|
||||||
|
suggs.push((open_paren_sp, "(".to_string()));
|
||||||
|
suggs.push((sp, format!("){suggestion}")));
|
||||||
|
} else {
|
||||||
|
suggs.push((sp, suggestion));
|
||||||
|
}
|
||||||
|
|
||||||
|
suggs
|
||||||
|
});
|
||||||
|
|
||||||
|
err.multipart_suggestions(
|
||||||
msg,
|
msg,
|
||||||
candidates.iter().map(|t| {
|
all_suggs,
|
||||||
format!(
|
|
||||||
"{} {}",
|
|
||||||
match introducer {
|
|
||||||
Introducer::Plus => " +",
|
|
||||||
Introducer::Colon => ":",
|
|
||||||
Introducer::Nothing => "",
|
|
||||||
},
|
|
||||||
self.tcx.def_path_str(t.def_id)
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Node::Item(hir::Item {
|
Node::Item(hir::Item {
|
||||||
|
@ -551,15 +551,10 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||||||
fn visit_coroutine_interior(&mut self) {
|
fn visit_coroutine_interior(&mut self) {
|
||||||
let fcx_typeck_results = self.fcx.typeck_results.borrow();
|
let fcx_typeck_results = self.fcx.typeck_results.borrow();
|
||||||
assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
|
assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
|
||||||
self.tcx().with_stable_hashing_context(move |ref hcx| {
|
for (predicate, cause) in &fcx_typeck_results.coroutine_stalled_predicates {
|
||||||
for (&expr_def_id, predicates) in
|
let (predicate, cause) = self.resolve((*predicate, cause.clone()), &cause.span);
|
||||||
fcx_typeck_results.coroutine_interior_predicates.to_sorted(hcx, false).into_iter()
|
self.typeck_results.coroutine_stalled_predicates.insert((predicate, cause));
|
||||||
{
|
}
|
||||||
let predicates =
|
|
||||||
self.resolve(predicates.clone(), &self.fcx.tcx.def_span(expr_def_id));
|
|
||||||
self.typeck_results.coroutine_interior_predicates.insert(expr_def_id, predicates);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip(self), level = "debug")]
|
#[instrument(skip(self), level = "debug")]
|
||||||
|
@ -239,7 +239,7 @@ impl Subdiagnostic for RegionOriginNote<'_> {
|
|||||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
self,
|
self,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
_f: F,
|
_f: &F,
|
||||||
) {
|
) {
|
||||||
let mut label_or_note = |span, msg: DiagMessage| {
|
let mut label_or_note = |span, msg: DiagMessage| {
|
||||||
let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count();
|
let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count();
|
||||||
@ -304,7 +304,7 @@ impl Subdiagnostic for LifetimeMismatchLabels {
|
|||||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
self,
|
self,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
_f: F,
|
_f: &F,
|
||||||
) {
|
) {
|
||||||
match self {
|
match self {
|
||||||
LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => {
|
LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => {
|
||||||
@ -352,7 +352,7 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
|
|||||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
self,
|
self,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
_f: F,
|
_f: &F,
|
||||||
) {
|
) {
|
||||||
let mut mk_suggestion = || {
|
let mut mk_suggestion = || {
|
||||||
let (
|
let (
|
||||||
@ -454,7 +454,7 @@ impl Subdiagnostic for IntroducesStaticBecauseUnmetLifetimeReq {
|
|||||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
mut self,
|
mut self,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
_f: F,
|
_f: &F,
|
||||||
) {
|
) {
|
||||||
self.unmet_requirements
|
self.unmet_requirements
|
||||||
.push_span_label(self.binding_span, fluent::infer_msl_introduces_static);
|
.push_span_label(self.binding_span, fluent::infer_msl_introduces_static);
|
||||||
@ -773,7 +773,7 @@ impl Subdiagnostic for ConsiderBorrowingParamHelp {
|
|||||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
self,
|
self,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
f: F,
|
f: &F,
|
||||||
) {
|
) {
|
||||||
let mut type_param_span: MultiSpan = self.spans.clone().into();
|
let mut type_param_span: MultiSpan = self.spans.clone().into();
|
||||||
for &span in &self.spans {
|
for &span in &self.spans {
|
||||||
@ -818,7 +818,7 @@ impl Subdiagnostic for DynTraitConstraintSuggestion {
|
|||||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
self,
|
self,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
f: F,
|
f: &F,
|
||||||
) {
|
) {
|
||||||
let mut multi_span: MultiSpan = vec![self.span].into();
|
let mut multi_span: MultiSpan = vec![self.span].into();
|
||||||
multi_span.push_span_label(self.span, fluent::infer_dtcs_has_lifetime_req_label);
|
multi_span.push_span_label(self.span, fluent::infer_dtcs_has_lifetime_req_label);
|
||||||
@ -865,7 +865,7 @@ impl Subdiagnostic for ReqIntroducedLocations {
|
|||||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
mut self,
|
mut self,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
f: F,
|
f: &F,
|
||||||
) {
|
) {
|
||||||
for sp in self.spans {
|
for sp in self.spans {
|
||||||
self.span.push_span_label(sp, fluent::infer_ril_introduced_here);
|
self.span.push_span_label(sp, fluent::infer_ril_introduced_here);
|
||||||
@ -888,7 +888,7 @@ impl Subdiagnostic for MoreTargeted {
|
|||||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
self,
|
self,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
_f: F,
|
_f: &F,
|
||||||
) {
|
) {
|
||||||
diag.code(E0772);
|
diag.code(E0772);
|
||||||
diag.primary_message(fluent::infer_more_targeted);
|
diag.primary_message(fluent::infer_more_targeted);
|
||||||
@ -1293,7 +1293,7 @@ impl Subdiagnostic for SuggestTuplePatternMany {
|
|||||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
self,
|
self,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
f: F,
|
f: &F,
|
||||||
) {
|
) {
|
||||||
diag.arg("path", self.path);
|
diag.arg("path", self.path);
|
||||||
let message = f(diag, crate::fluent_generated::infer_stp_wrap_many.into());
|
let message = f(diag, crate::fluent_generated::infer_stp_wrap_many.into());
|
||||||
|
@ -163,7 +163,7 @@ impl Subdiagnostic for RegionExplanation<'_> {
|
|||||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
self,
|
self,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
f: F,
|
f: &F,
|
||||||
) {
|
) {
|
||||||
diag.arg("pref_kind", self.prefix);
|
diag.arg("pref_kind", self.prefix);
|
||||||
diag.arg("suff_kind", self.suffix);
|
diag.arg("suff_kind", self.suffix);
|
||||||
|
@ -2369,7 +2369,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
generic_param_scope = self.tcx.local_parent(generic_param_scope);
|
generic_param_scope = self.tcx.local_parent(generic_param_scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
// type_param_sugg_span is (span, has_bounds)
|
// type_param_sugg_span is (span, has_bounds, needs_parentheses)
|
||||||
let (type_scope, type_param_sugg_span) = match bound_kind {
|
let (type_scope, type_param_sugg_span) = match bound_kind {
|
||||||
GenericKind::Param(param) => {
|
GenericKind::Param(param) => {
|
||||||
let generics = self.tcx.generics_of(generic_param_scope);
|
let generics = self.tcx.generics_of(generic_param_scope);
|
||||||
@ -2380,10 +2380,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
// instead we suggest `T: 'a + 'b` in that case.
|
// instead we suggest `T: 'a + 'b` in that case.
|
||||||
let hir_generics = self.tcx.hir().get_generics(scope).unwrap();
|
let hir_generics = self.tcx.hir().get_generics(scope).unwrap();
|
||||||
let sugg_span = match hir_generics.bounds_span_for_suggestions(def_id) {
|
let sugg_span = match hir_generics.bounds_span_for_suggestions(def_id) {
|
||||||
Some(span) => Some((span, true)),
|
Some((span, open_paren_sp)) => Some((span, true, open_paren_sp)),
|
||||||
// If `param` corresponds to `Self`, no usable suggestion span.
|
// If `param` corresponds to `Self`, no usable suggestion span.
|
||||||
None if generics.has_self && param.index == 0 => None,
|
None if generics.has_self && param.index == 0 => None,
|
||||||
None => Some((self.tcx.def_span(def_id).shrink_to_hi(), false)),
|
None => Some((self.tcx.def_span(def_id).shrink_to_hi(), false, None)),
|
||||||
};
|
};
|
||||||
(scope, sugg_span)
|
(scope, sugg_span)
|
||||||
}
|
}
|
||||||
@ -2406,12 +2406,18 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
let mut suggs = vec![];
|
let mut suggs = vec![];
|
||||||
let lt_name = self.suggest_name_region(sub, &mut suggs);
|
let lt_name = self.suggest_name_region(sub, &mut suggs);
|
||||||
|
|
||||||
if let Some((sp, has_lifetimes)) = type_param_sugg_span
|
if let Some((sp, has_lifetimes, open_paren_sp)) = type_param_sugg_span
|
||||||
&& suggestion_scope == type_scope
|
&& suggestion_scope == type_scope
|
||||||
{
|
{
|
||||||
let suggestion =
|
let suggestion =
|
||||||
if has_lifetimes { format!(" + {lt_name}") } else { format!(": {lt_name}") };
|
if has_lifetimes { format!(" + {lt_name}") } else { format!(": {lt_name}") };
|
||||||
suggs.push((sp, suggestion))
|
|
||||||
|
if let Some(open_paren_sp) = open_paren_sp {
|
||||||
|
suggs.push((open_paren_sp, "(".to_string()));
|
||||||
|
suggs.push((sp, format!("){suggestion}")));
|
||||||
|
} else {
|
||||||
|
suggs.push((sp, suggestion))
|
||||||
|
}
|
||||||
} else if let GenericKind::Alias(ref p) = bound_kind
|
} else if let GenericKind::Alias(ref p) = bound_kind
|
||||||
&& let ty::Projection = p.kind(self.tcx)
|
&& let ty::Projection = p.kind(self.tcx)
|
||||||
&& let DefKind::AssocTy = self.tcx.def_kind(p.def_id)
|
&& let DefKind::AssocTy = self.tcx.def_kind(p.def_id)
|
||||||
|
@ -759,7 +759,9 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
|
|||||||
tcx.hir().par_body_owners(|def_id| {
|
tcx.hir().par_body_owners(|def_id| {
|
||||||
if tcx.is_coroutine(def_id.to_def_id()) {
|
if tcx.is_coroutine(def_id.to_def_id()) {
|
||||||
tcx.ensure().mir_coroutine_witnesses(def_id);
|
tcx.ensure().mir_coroutine_witnesses(def_id);
|
||||||
tcx.ensure().check_coroutine_obligations(def_id);
|
tcx.ensure().check_coroutine_obligations(
|
||||||
|
tcx.typeck_root_def_id(def_id.to_def_id()).expect_local(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
sess.time("layout_testing", || layout_test::test_layout(tcx));
|
sess.time("layout_testing", || layout_test::test_layout(tcx));
|
||||||
|
@ -321,6 +321,7 @@ fn test_search_paths_tracking_hash_different_order() {
|
|||||||
&opts.target_triple,
|
&opts.target_triple,
|
||||||
&early_dcx,
|
&early_dcx,
|
||||||
search_path,
|
search_path,
|
||||||
|
false,
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#![allow(rustc::untranslatable_diagnostic)]
|
#![allow(rustc::untranslatable_diagnostic)]
|
||||||
|
|
||||||
use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS;
|
use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS;
|
||||||
use rustc_errors::{add_elided_lifetime_in_path_suggestion, Diag};
|
use rustc_errors::{elided_lifetime_in_path_suggestion, Diag};
|
||||||
use rustc_errors::{Applicability, SuggestionStyle};
|
use rustc_errors::{Applicability, SuggestionStyle};
|
||||||
use rustc_middle::middle::stability;
|
use rustc_middle::middle::stability;
|
||||||
use rustc_session::lint::BuiltinLintDiag;
|
use rustc_session::lint::BuiltinLintDiag;
|
||||||
@ -74,13 +74,15 @@ pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Di
|
|||||||
diag.span_note(span_def, "the macro is defined here");
|
diag.span_note(span_def, "the macro is defined here");
|
||||||
}
|
}
|
||||||
BuiltinLintDiag::ElidedLifetimesInPaths(n, path_span, incl_angl_brckt, insertion_span) => {
|
BuiltinLintDiag::ElidedLifetimesInPaths(n, path_span, incl_angl_brckt, insertion_span) => {
|
||||||
add_elided_lifetime_in_path_suggestion(
|
diag.subdiagnostic(
|
||||||
sess.source_map(),
|
sess.dcx(),
|
||||||
diag,
|
elided_lifetime_in_path_suggestion(
|
||||||
n,
|
sess.source_map(),
|
||||||
path_span,
|
n,
|
||||||
incl_angl_brckt,
|
path_span,
|
||||||
insertion_span,
|
incl_angl_brckt,
|
||||||
|
insertion_span,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
BuiltinLintDiag::UnknownCrateTypes(span, note, sugg) => {
|
BuiltinLintDiag::UnknownCrateTypes(span, note, sugg) => {
|
||||||
|
@ -27,7 +27,7 @@ impl Subdiagnostic for OverruledAttributeSub {
|
|||||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
self,
|
self,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
_f: F,
|
_f: &F,
|
||||||
) {
|
) {
|
||||||
match self {
|
match self {
|
||||||
OverruledAttributeSub::DefaultSource { id } => {
|
OverruledAttributeSub::DefaultSource { id } => {
|
||||||
|
@ -274,7 +274,7 @@ impl<'a, 'b> Subdiagnostic for SuggestChangingAssocTypes<'a, 'b> {
|
|||||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
self,
|
self,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
_f: F,
|
_f: &F,
|
||||||
) {
|
) {
|
||||||
// Access to associates types should use `<T as Bound>::Assoc`, which does not need a
|
// Access to associates types should use `<T as Bound>::Assoc`, which does not need a
|
||||||
// bound. Let's see if this type does that.
|
// bound. Let's see if this type does that.
|
||||||
@ -330,7 +330,7 @@ impl Subdiagnostic for BuiltinTypeAliasGenericBoundsSuggestion {
|
|||||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
self,
|
self,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
_f: F,
|
_f: &F,
|
||||||
) {
|
) {
|
||||||
diag.multipart_suggestion(
|
diag.multipart_suggestion(
|
||||||
fluent::lint_suggestion,
|
fluent::lint_suggestion,
|
||||||
@ -451,7 +451,7 @@ impl Subdiagnostic for BuiltinUnpermittedTypeInitSub {
|
|||||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
self,
|
self,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
_f: F,
|
_f: &F,
|
||||||
) {
|
) {
|
||||||
let mut err = self.err;
|
let mut err = self.err;
|
||||||
loop {
|
loop {
|
||||||
@ -506,7 +506,7 @@ impl Subdiagnostic for BuiltinClashingExternSub<'_> {
|
|||||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
self,
|
self,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
_f: F,
|
_f: &F,
|
||||||
) {
|
) {
|
||||||
let mut expected_str = DiagStyledString::new();
|
let mut expected_str = DiagStyledString::new();
|
||||||
expected_str.push(self.expected.fn_sig(self.tcx).to_string(), false);
|
expected_str.push(self.expected.fn_sig(self.tcx).to_string(), false);
|
||||||
@ -788,7 +788,7 @@ impl Subdiagnostic for HiddenUnicodeCodepointsDiagLabels {
|
|||||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
self,
|
self,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
_f: F,
|
_f: &F,
|
||||||
) {
|
) {
|
||||||
for (c, span) in self.spans {
|
for (c, span) in self.spans {
|
||||||
diag.span_label(span, format!("{c:?}"));
|
diag.span_label(span, format!("{c:?}"));
|
||||||
@ -806,7 +806,7 @@ impl Subdiagnostic for HiddenUnicodeCodepointsDiagSub {
|
|||||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
self,
|
self,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
_f: F,
|
_f: &F,
|
||||||
) {
|
) {
|
||||||
match self {
|
match self {
|
||||||
HiddenUnicodeCodepointsDiagSub::Escape { spans } => {
|
HiddenUnicodeCodepointsDiagSub::Escape { spans } => {
|
||||||
@ -954,7 +954,7 @@ impl Subdiagnostic for NonBindingLetSub {
|
|||||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
self,
|
self,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
_f: F,
|
_f: &F,
|
||||||
) {
|
) {
|
||||||
let can_suggest_binding = self.drop_fn_start_end.is_some() || !self.is_assign_desugar;
|
let can_suggest_binding = self.drop_fn_start_end.is_some() || !self.is_assign_desugar;
|
||||||
|
|
||||||
@ -1240,7 +1240,7 @@ impl Subdiagnostic for NonSnakeCaseDiagSub {
|
|||||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
self,
|
self,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
_f: F,
|
_f: &F,
|
||||||
) {
|
) {
|
||||||
match self {
|
match self {
|
||||||
NonSnakeCaseDiagSub::Label { span } => {
|
NonSnakeCaseDiagSub::Label { span } => {
|
||||||
@ -1482,7 +1482,7 @@ impl Subdiagnostic for OverflowingBinHexSign {
|
|||||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
self,
|
self,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
_f: F,
|
_f: &F,
|
||||||
) {
|
) {
|
||||||
match self {
|
match self {
|
||||||
OverflowingBinHexSign::Positive => {
|
OverflowingBinHexSign::Positive => {
|
||||||
|
@ -71,6 +71,7 @@ impl SubdiagnosticDerive {
|
|||||||
span_field: None,
|
span_field: None,
|
||||||
applicability: None,
|
applicability: None,
|
||||||
has_suggestion_parts: false,
|
has_suggestion_parts: false,
|
||||||
|
has_subdiagnostic: false,
|
||||||
is_enum,
|
is_enum,
|
||||||
};
|
};
|
||||||
builder.into_tokens().unwrap_or_else(|v| v.to_compile_error())
|
builder.into_tokens().unwrap_or_else(|v| v.to_compile_error())
|
||||||
@ -90,7 +91,7 @@ impl SubdiagnosticDerive {
|
|||||||
fn add_to_diag_with<__G, __F>(
|
fn add_to_diag_with<__G, __F>(
|
||||||
self,
|
self,
|
||||||
#diag: &mut rustc_errors::Diag<'_, __G>,
|
#diag: &mut rustc_errors::Diag<'_, __G>,
|
||||||
#f: __F
|
#f: &__F
|
||||||
) where
|
) where
|
||||||
__G: rustc_errors::EmissionGuarantee,
|
__G: rustc_errors::EmissionGuarantee,
|
||||||
__F: rustc_errors::SubdiagMessageOp<__G>,
|
__F: rustc_errors::SubdiagMessageOp<__G>,
|
||||||
@ -133,6 +134,10 @@ struct SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
|||||||
/// during finalization if still `false`.
|
/// during finalization if still `false`.
|
||||||
has_suggestion_parts: bool,
|
has_suggestion_parts: bool,
|
||||||
|
|
||||||
|
/// Set to true when a `#[subdiagnostic]` field is encountered, used to suppress the error
|
||||||
|
/// emitted when no subdiagnostic kinds are specified on the variant itself.
|
||||||
|
has_subdiagnostic: bool,
|
||||||
|
|
||||||
/// Set to true when this variant is an enum variant rather than just the body of a struct.
|
/// Set to true when this variant is an enum variant rather than just the body of a struct.
|
||||||
is_enum: bool,
|
is_enum: bool,
|
||||||
}
|
}
|
||||||
@ -373,6 +378,13 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
|||||||
|
|
||||||
Ok(quote! {})
|
Ok(quote! {})
|
||||||
}
|
}
|
||||||
|
"subdiagnostic" => {
|
||||||
|
let f = &self.parent.f;
|
||||||
|
let diag = &self.parent.diag;
|
||||||
|
let binding = &info.binding;
|
||||||
|
self.has_subdiagnostic = true;
|
||||||
|
Ok(quote! { #binding.add_to_diag_with(#diag, #f); })
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let mut span_attrs = vec![];
|
let mut span_attrs = vec![];
|
||||||
if kind_stats.has_multipart_suggestion {
|
if kind_stats.has_multipart_suggestion {
|
||||||
@ -480,18 +492,6 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
|||||||
|
|
||||||
pub(crate) fn into_tokens(&mut self) -> Result<TokenStream, DiagnosticDeriveError> {
|
pub(crate) fn into_tokens(&mut self) -> Result<TokenStream, DiagnosticDeriveError> {
|
||||||
let kind_slugs = self.identify_kind()?;
|
let kind_slugs = self.identify_kind()?;
|
||||||
if kind_slugs.is_empty() {
|
|
||||||
if self.is_enum {
|
|
||||||
// It's okay for a variant to not be a subdiagnostic at all..
|
|
||||||
return Ok(quote! {});
|
|
||||||
} else {
|
|
||||||
// ..but structs should always be _something_.
|
|
||||||
throw_span_err!(
|
|
||||||
self.variant.ast().ident.span().unwrap(),
|
|
||||||
"subdiagnostic kind not specified"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let kind_stats: KindsStatistics =
|
let kind_stats: KindsStatistics =
|
||||||
kind_slugs.iter().map(|(kind, _slug, _no_span)| kind).collect();
|
kind_slugs.iter().map(|(kind, _slug, _no_span)| kind).collect();
|
||||||
@ -510,6 +510,19 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
|||||||
.map(|binding| self.generate_field_attr_code(binding, kind_stats))
|
.map(|binding| self.generate_field_attr_code(binding, kind_stats))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
if kind_slugs.is_empty() {
|
||||||
|
if self.is_enum {
|
||||||
|
// It's okay for a variant to not be a subdiagnostic at all..
|
||||||
|
return Ok(quote! {});
|
||||||
|
} else if !self.has_subdiagnostic {
|
||||||
|
// ..but structs should always be _something_.
|
||||||
|
throw_span_err!(
|
||||||
|
self.variant.ast().ident.span().unwrap(),
|
||||||
|
"subdiagnostic kind not specified"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let span_field = self.span_field.value_ref();
|
let span_field = self.span_field.value_ref();
|
||||||
|
|
||||||
let diag = &self.parent.diag;
|
let diag = &self.parent.diag;
|
||||||
|
@ -144,6 +144,7 @@ decl_derive!(
|
|||||||
help,
|
help,
|
||||||
note,
|
note,
|
||||||
warning,
|
warning,
|
||||||
|
subdiagnostic,
|
||||||
suggestion,
|
suggestion,
|
||||||
suggestion_short,
|
suggestion_short,
|
||||||
suggestion_hidden,
|
suggestion_hidden,
|
||||||
|
@ -985,7 +985,8 @@ impl<'tcx> Debug for Rvalue<'tcx> {
|
|||||||
Ref(region, borrow_kind, ref place) => {
|
Ref(region, borrow_kind, ref place) => {
|
||||||
let kind_str = match borrow_kind {
|
let kind_str = match borrow_kind {
|
||||||
BorrowKind::Shared => "",
|
BorrowKind::Shared => "",
|
||||||
BorrowKind::Fake => "fake ",
|
BorrowKind::Fake(FakeBorrowKind::Deep) => "fake ",
|
||||||
|
BorrowKind::Fake(FakeBorrowKind::Shallow) => "fake shallow ",
|
||||||
BorrowKind::Mut { .. } => "mut ",
|
BorrowKind::Mut { .. } => "mut ",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -236,6 +236,11 @@ impl<'tcx> PlaceRef<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn to_place(&self, tcx: TyCtxt<'tcx>) -> Place<'tcx> {
|
||||||
|
Place { local: self.local, projection: tcx.mk_place_elems(self.projection) }
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn last_projection(&self) -> Option<(PlaceRef<'tcx>, PlaceElem<'tcx>)> {
|
pub fn last_projection(&self) -> Option<(PlaceRef<'tcx>, PlaceElem<'tcx>)> {
|
||||||
if let &[ref proj_base @ .., elem] = self.projection {
|
if let &[ref proj_base @ .., elem] = self.projection {
|
||||||
@ -446,7 +451,7 @@ impl<'tcx> Rvalue<'tcx> {
|
|||||||
impl BorrowKind {
|
impl BorrowKind {
|
||||||
pub fn mutability(&self) -> Mutability {
|
pub fn mutability(&self) -> Mutability {
|
||||||
match *self {
|
match *self {
|
||||||
BorrowKind::Shared | BorrowKind::Fake => Mutability::Not,
|
BorrowKind::Shared | BorrowKind::Fake(_) => Mutability::Not,
|
||||||
BorrowKind::Mut { .. } => Mutability::Mut,
|
BorrowKind::Mut { .. } => Mutability::Mut,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -454,7 +459,7 @@ impl BorrowKind {
|
|||||||
pub fn allows_two_phase_borrow(&self) -> bool {
|
pub fn allows_two_phase_borrow(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
BorrowKind::Shared
|
BorrowKind::Shared
|
||||||
| BorrowKind::Fake
|
| BorrowKind::Fake(_)
|
||||||
| BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::ClosureCapture } => {
|
| BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::ClosureCapture } => {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
@ -165,13 +165,16 @@ pub enum BorrowKind {
|
|||||||
/// Data must be immutable and is aliasable.
|
/// Data must be immutable and is aliasable.
|
||||||
Shared,
|
Shared,
|
||||||
|
|
||||||
/// The immediately borrowed place must be immutable, but projections from
|
/// An immutable, aliasable borrow that is discarded after borrow-checking. Can behave either
|
||||||
/// it don't need to be. For example, a shallow borrow of `a.b` doesn't
|
/// like a normal shared borrow or like a special shallow borrow (see [`FakeBorrowKind`]).
|
||||||
/// conflict with a mutable borrow of `a.b.c`.
|
|
||||||
///
|
///
|
||||||
/// This is used when lowering matches: when matching on a place we want to
|
/// This is used when lowering index expressions and matches. This is used to prevent code like
|
||||||
/// ensure that place have the same value from the start of the match until
|
/// the following from compiling:
|
||||||
/// an arm is selected. This prevents this code from compiling:
|
/// ```compile_fail,E0510
|
||||||
|
/// let mut x: &[_] = &[[0, 1]];
|
||||||
|
/// let y: &[_] = &[];
|
||||||
|
/// let _ = x[0][{x = y; 1}];
|
||||||
|
/// ```
|
||||||
/// ```compile_fail,E0510
|
/// ```compile_fail,E0510
|
||||||
/// let mut x = &Some(0);
|
/// let mut x = &Some(0);
|
||||||
/// match *x {
|
/// match *x {
|
||||||
@ -180,11 +183,8 @@ pub enum BorrowKind {
|
|||||||
/// Some(_) => (),
|
/// Some(_) => (),
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
/// This can't be a shared borrow because mutably borrowing (*x as Some).0
|
|
||||||
/// should not prevent `if let None = x { ... }`, for example, because the
|
|
||||||
/// mutating `(*x as Some).0` can't affect the discriminant of `x`.
|
|
||||||
/// We can also report errors with this kind of borrow differently.
|
/// We can also report errors with this kind of borrow differently.
|
||||||
Fake,
|
Fake(FakeBorrowKind),
|
||||||
|
|
||||||
/// Data is mutable and not aliasable.
|
/// Data is mutable and not aliasable.
|
||||||
Mut { kind: MutBorrowKind },
|
Mut { kind: MutBorrowKind },
|
||||||
@ -240,6 +240,57 @@ pub enum MutBorrowKind {
|
|||||||
ClosureCapture,
|
ClosureCapture,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, TyEncodable, TyDecodable)]
|
||||||
|
#[derive(Hash, HashStable)]
|
||||||
|
pub enum FakeBorrowKind {
|
||||||
|
/// A shared shallow borrow. The immediately borrowed place must be immutable, but projections
|
||||||
|
/// from it don't need to be. For example, a shallow borrow of `a.b` doesn't conflict with a
|
||||||
|
/// mutable borrow of `a.b.c`.
|
||||||
|
///
|
||||||
|
/// This is used when lowering matches: when matching on a place we want to ensure that place
|
||||||
|
/// have the same value from the start of the match until an arm is selected. This prevents this
|
||||||
|
/// code from compiling:
|
||||||
|
/// ```compile_fail,E0510
|
||||||
|
/// let mut x = &Some(0);
|
||||||
|
/// match *x {
|
||||||
|
/// None => (),
|
||||||
|
/// Some(_) if { x = &None; false } => (),
|
||||||
|
/// Some(_) => (),
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
/// This can't be a shared borrow because mutably borrowing `(*x as Some).0` should not checking
|
||||||
|
/// the discriminant or accessing other variants, because the mutating `(*x as Some).0` can't
|
||||||
|
/// affect the discriminant of `x`. E.g. the following is allowed:
|
||||||
|
/// ```rust
|
||||||
|
/// let mut x = Some(0);
|
||||||
|
/// match x {
|
||||||
|
/// Some(_)
|
||||||
|
/// if {
|
||||||
|
/// if let Some(ref mut y) = x {
|
||||||
|
/// *y += 1;
|
||||||
|
/// };
|
||||||
|
/// true
|
||||||
|
/// } => {}
|
||||||
|
/// _ => {}
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
Shallow,
|
||||||
|
/// A shared (deep) borrow. Data must be immutable and is aliasable.
|
||||||
|
///
|
||||||
|
/// This is used when lowering deref patterns, where shallow borrows wouldn't prevent something
|
||||||
|
/// like:
|
||||||
|
// ```compile_fail
|
||||||
|
// let mut b = Box::new(false);
|
||||||
|
// match b {
|
||||||
|
// deref!(true) => {} // not reached because `*b == false`
|
||||||
|
// _ if { *b = true; false } => {} // not reached because the guard is `false`
|
||||||
|
// deref!(false) => {} // not reached because the guard changed it
|
||||||
|
// // UB because we reached the unreachable.
|
||||||
|
// }
|
||||||
|
// ```
|
||||||
|
Deep,
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// Statements
|
// Statements
|
||||||
|
|
||||||
|
@ -294,7 +294,7 @@ impl BorrowKind {
|
|||||||
|
|
||||||
// We have no type corresponding to a shallow borrow, so use
|
// We have no type corresponding to a shallow borrow, so use
|
||||||
// `&` as an approximation.
|
// `&` as an approximation.
|
||||||
BorrowKind::Fake => hir::Mutability::Not,
|
BorrowKind::Fake(_) => hir::Mutability::Not,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -655,7 +655,7 @@ macro_rules! make_mir_visitor {
|
|||||||
BorrowKind::Shared => PlaceContext::NonMutatingUse(
|
BorrowKind::Shared => PlaceContext::NonMutatingUse(
|
||||||
NonMutatingUseContext::SharedBorrow
|
NonMutatingUseContext::SharedBorrow
|
||||||
),
|
),
|
||||||
BorrowKind::Fake => PlaceContext::NonMutatingUse(
|
BorrowKind::Fake(_) => PlaceContext::NonMutatingUse(
|
||||||
NonMutatingUseContext::FakeBorrow
|
NonMutatingUseContext::FakeBorrow
|
||||||
),
|
),
|
||||||
BorrowKind::Mut { .. } =>
|
BorrowKind::Mut { .. } =>
|
||||||
@ -1284,6 +1284,8 @@ pub enum NonMutatingUseContext {
|
|||||||
/// Shared borrow.
|
/// Shared borrow.
|
||||||
SharedBorrow,
|
SharedBorrow,
|
||||||
/// A fake borrow.
|
/// A fake borrow.
|
||||||
|
/// FIXME: do we need to distinguish shallow and deep fake borrows? In fact, do we need to
|
||||||
|
/// distinguish fake and normal deep borrows?
|
||||||
FakeBorrow,
|
FakeBorrow,
|
||||||
/// AddressOf for *const pointer.
|
/// AddressOf for *const pointer.
|
||||||
AddressOf,
|
AddressOf,
|
||||||
|
@ -642,7 +642,7 @@ impl<'tcx> Pat<'tcx> {
|
|||||||
AscribeUserType { subpattern, .. }
|
AscribeUserType { subpattern, .. }
|
||||||
| Binding { subpattern: Some(subpattern), .. }
|
| Binding { subpattern: Some(subpattern), .. }
|
||||||
| Deref { subpattern }
|
| Deref { subpattern }
|
||||||
| DerefPattern { subpattern }
|
| DerefPattern { subpattern, .. }
|
||||||
| InlineConstant { subpattern, .. } => subpattern.walk_(it),
|
| InlineConstant { subpattern, .. } => subpattern.walk_(it),
|
||||||
Leaf { subpatterns } | Variant { subpatterns, .. } => {
|
Leaf { subpatterns } | Variant { subpatterns, .. } => {
|
||||||
subpatterns.iter().for_each(|field| field.pattern.walk_(it))
|
subpatterns.iter().for_each(|field| field.pattern.walk_(it))
|
||||||
@ -760,6 +760,7 @@ pub enum PatKind<'tcx> {
|
|||||||
/// Deref pattern, written `box P` for now.
|
/// Deref pattern, written `box P` for now.
|
||||||
DerefPattern {
|
DerefPattern {
|
||||||
subpattern: Box<Pat<'tcx>>,
|
subpattern: Box<Pat<'tcx>>,
|
||||||
|
mutability: hir::Mutability,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// One of the following:
|
/// One of the following:
|
||||||
@ -1166,7 +1167,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
|
|||||||
}
|
}
|
||||||
write!(f, "{subpattern}")
|
write!(f, "{subpattern}")
|
||||||
}
|
}
|
||||||
PatKind::DerefPattern { ref subpattern } => {
|
PatKind::DerefPattern { ref subpattern, .. } => {
|
||||||
write!(f, "deref!({subpattern})")
|
write!(f, "deref!({subpattern})")
|
||||||
}
|
}
|
||||||
PatKind::Constant { value } => write!(f, "{value}"),
|
PatKind::Constant { value } => write!(f, "{value}"),
|
||||||
|
@ -229,7 +229,7 @@ pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
|
|||||||
match &pat.kind {
|
match &pat.kind {
|
||||||
AscribeUserType { subpattern, ascription: _ }
|
AscribeUserType { subpattern, ascription: _ }
|
||||||
| Deref { subpattern }
|
| Deref { subpattern }
|
||||||
| DerefPattern { subpattern }
|
| DerefPattern { subpattern, .. }
|
||||||
| Binding { subpattern: Some(subpattern), .. } => visitor.visit_pat(subpattern),
|
| Binding { subpattern: Some(subpattern), .. } => visitor.visit_pat(subpattern),
|
||||||
Binding { .. } | Wild | Never | Error(_) => {}
|
Binding { .. } | Wild | Never | Error(_) => {}
|
||||||
Variant { subpatterns, adt_def: _, args: _, variant_index: _ } | Leaf { subpatterns } => {
|
Variant { subpatterns, adt_def: _, args: _, variant_index: _ } | Leaf { subpatterns } => {
|
||||||
|
@ -279,24 +279,29 @@ pub fn suggest_constraining_type_params<'a>(
|
|||||||
constraint.sort();
|
constraint.sort();
|
||||||
constraint.dedup();
|
constraint.dedup();
|
||||||
let constraint = constraint.join(" + ");
|
let constraint = constraint.join(" + ");
|
||||||
let mut suggest_restrict = |span, bound_list_non_empty| {
|
let mut suggest_restrict = |span, bound_list_non_empty, open_paren_sp| {
|
||||||
suggestions.push((
|
let suggestion = if span_to_replace.is_some() {
|
||||||
span,
|
constraint.clone()
|
||||||
if span_to_replace.is_some() {
|
} else if constraint.starts_with('<') {
|
||||||
constraint.clone()
|
constraint.to_string()
|
||||||
} else if constraint.starts_with('<') {
|
} else if bound_list_non_empty {
|
||||||
constraint.to_string()
|
format!(" + {constraint}")
|
||||||
} else if bound_list_non_empty {
|
} else {
|
||||||
format!(" + {constraint}")
|
format!(" {constraint}")
|
||||||
} else {
|
};
|
||||||
format!(" {constraint}")
|
|
||||||
},
|
use SuggestChangingConstraintsMessage::RestrictBoundFurther;
|
||||||
SuggestChangingConstraintsMessage::RestrictBoundFurther,
|
|
||||||
))
|
if let Some(open_paren_sp) = open_paren_sp {
|
||||||
|
suggestions.push((open_paren_sp, "(".to_string(), RestrictBoundFurther));
|
||||||
|
suggestions.push((span, format!("){suggestion}"), RestrictBoundFurther));
|
||||||
|
} else {
|
||||||
|
suggestions.push((span, suggestion, RestrictBoundFurther));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(span) = span_to_replace {
|
if let Some(span) = span_to_replace {
|
||||||
suggest_restrict(span, true);
|
suggest_restrict(span, true, None);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -327,8 +332,8 @@ pub fn suggest_constraining_type_params<'a>(
|
|||||||
// --
|
// --
|
||||||
// |
|
// |
|
||||||
// replace with: `T: Bar +`
|
// replace with: `T: Bar +`
|
||||||
if let Some(span) = generics.bounds_span_for_suggestions(param.def_id) {
|
if let Some((span, open_paren_sp)) = generics.bounds_span_for_suggestions(param.def_id) {
|
||||||
suggest_restrict(span, true);
|
suggest_restrict(span, true, open_paren_sp);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,10 +7,8 @@ use crate::{
|
|||||||
GenericArgs, GenericArgsRef, Ty, UserArgs,
|
GenericArgs, GenericArgsRef, Ty, UserArgs,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use rustc_data_structures::{
|
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||||
fx::FxIndexMap,
|
use rustc_data_structures::unord::{ExtendUnord, UnordItems, UnordSet};
|
||||||
unord::{ExtendUnord, UnordItems, UnordSet},
|
|
||||||
};
|
|
||||||
use rustc_errors::ErrorGuaranteed;
|
use rustc_errors::ErrorGuaranteed;
|
||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
self as hir,
|
self as hir,
|
||||||
@ -201,8 +199,7 @@ pub struct TypeckResults<'tcx> {
|
|||||||
|
|
||||||
/// Stores the predicates that apply on coroutine witness types.
|
/// Stores the predicates that apply on coroutine witness types.
|
||||||
/// formatting modified file tests/ui/coroutine/retain-resume-ref.rs
|
/// formatting modified file tests/ui/coroutine/retain-resume-ref.rs
|
||||||
pub coroutine_interior_predicates:
|
pub coroutine_stalled_predicates: FxIndexSet<(ty::Predicate<'tcx>, ObligationCause<'tcx>)>,
|
||||||
LocalDefIdMap<Vec<(ty::Predicate<'tcx>, ObligationCause<'tcx>)>>,
|
|
||||||
|
|
||||||
/// We sometimes treat byte string literals (which are of type `&[u8; N]`)
|
/// We sometimes treat byte string literals (which are of type `&[u8; N]`)
|
||||||
/// as `&[u8]`, depending on the pattern in which they are used.
|
/// as `&[u8]`, depending on the pattern in which they are used.
|
||||||
@ -243,7 +240,7 @@ impl<'tcx> TypeckResults<'tcx> {
|
|||||||
closure_min_captures: Default::default(),
|
closure_min_captures: Default::default(),
|
||||||
closure_fake_reads: Default::default(),
|
closure_fake_reads: Default::default(),
|
||||||
rvalue_scopes: Default::default(),
|
rvalue_scopes: Default::default(),
|
||||||
coroutine_interior_predicates: Default::default(),
|
coroutine_stalled_predicates: Default::default(),
|
||||||
treat_byte_string_as_slice: Default::default(),
|
treat_byte_string_as_slice: Default::default(),
|
||||||
closure_size_eval: Default::default(),
|
closure_size_eval: Default::default(),
|
||||||
offset_of_data: Default::default(),
|
offset_of_data: Default::default(),
|
||||||
@ -451,7 +448,7 @@ impl<'tcx> TypeckResults<'tcx> {
|
|||||||
/// This is computed from the typeck results since we want to make
|
/// This is computed from the typeck results since we want to make
|
||||||
/// sure to apply any match-ergonomics adjustments, which we cannot
|
/// sure to apply any match-ergonomics adjustments, which we cannot
|
||||||
/// determine from the HIR alone.
|
/// determine from the HIR alone.
|
||||||
pub fn pat_has_ref_mut_binding(&self, pat: &'tcx hir::Pat<'tcx>) -> bool {
|
pub fn pat_has_ref_mut_binding(&self, pat: &hir::Pat<'_>) -> bool {
|
||||||
let mut has_ref_mut = false;
|
let mut has_ref_mut = false;
|
||||||
pat.walk(|pat| {
|
pat.walk(|pat| {
|
||||||
if let hir::PatKind::Binding(_, id, _, _) = pat.kind
|
if let hir::PatKind::Binding(_, id, _, _) = pat.kind
|
||||||
|
@ -685,7 +685,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
fake_borrow_temp.into(),
|
fake_borrow_temp.into(),
|
||||||
Rvalue::Ref(
|
Rvalue::Ref(
|
||||||
tcx.lifetimes.re_erased,
|
tcx.lifetimes.re_erased,
|
||||||
BorrowKind::Fake,
|
BorrowKind::Fake(FakeBorrowKind::Shallow),
|
||||||
Place { local: base_place.local, projection },
|
Place { local: base_place.local, projection },
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -10,10 +10,7 @@ use crate::build::scope::DropKind;
|
|||||||
use crate::build::ForGuard::{self, OutsideGuard, RefWithinGuard};
|
use crate::build::ForGuard::{self, OutsideGuard, RefWithinGuard};
|
||||||
use crate::build::{BlockAnd, BlockAndExtension, Builder};
|
use crate::build::{BlockAnd, BlockAndExtension, Builder};
|
||||||
use crate::build::{GuardFrame, GuardFrameLocal, LocalsForNode};
|
use crate::build::{GuardFrame, GuardFrameLocal, LocalsForNode};
|
||||||
use rustc_data_structures::{
|
use rustc_data_structures::{fx::FxIndexMap, stack::ensure_sufficient_stack};
|
||||||
fx::{FxHashSet, FxIndexMap, FxIndexSet},
|
|
||||||
stack::ensure_sufficient_stack,
|
|
||||||
};
|
|
||||||
use rustc_hir::{BindingMode, ByRef};
|
use rustc_hir::{BindingMode, ByRef};
|
||||||
use rustc_middle::middle::region;
|
use rustc_middle::middle::region;
|
||||||
use rustc_middle::mir::{self, *};
|
use rustc_middle::mir::{self, *};
|
||||||
@ -211,7 +208,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
/// 2. Create the decision tree ([Builder::lower_match_tree]).
|
/// 2. Create the decision tree ([Builder::lower_match_tree]).
|
||||||
/// 3. Determine the fake borrows that are needed from the places that were
|
/// 3. Determine the fake borrows that are needed from the places that were
|
||||||
/// matched against and create the required temporaries for them
|
/// matched against and create the required temporaries for them
|
||||||
/// ([Builder::calculate_fake_borrows]).
|
/// ([util::collect_fake_borrows]).
|
||||||
/// 4. Create everything else: the guards and the arms ([Builder::lower_match_arms]).
|
/// 4. Create everything else: the guards and the arms ([Builder::lower_match_arms]).
|
||||||
///
|
///
|
||||||
/// ## False edges
|
/// ## False edges
|
||||||
@ -380,12 +377,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
match_start_span: Span,
|
match_start_span: Span,
|
||||||
match_has_guard: bool,
|
match_has_guard: bool,
|
||||||
candidates: &mut [&mut Candidate<'pat, 'tcx>],
|
candidates: &mut [&mut Candidate<'pat, 'tcx>],
|
||||||
) -> Vec<(Place<'tcx>, Local)> {
|
) -> Vec<(Place<'tcx>, Local, FakeBorrowKind)> {
|
||||||
// The set of places that we are creating fake borrows of. If there are
|
// The set of places that we are creating fake borrows of. If there are no match guards then
|
||||||
// no match guards then we don't need any fake borrows, so don't track
|
// we don't need any fake borrows, so don't track them.
|
||||||
// them.
|
let fake_borrows: Vec<(Place<'tcx>, Local, FakeBorrowKind)> = if match_has_guard {
|
||||||
let fake_borrows = match_has_guard
|
util::collect_fake_borrows(
|
||||||
.then(|| util::FakeBorrowCollector::collect_fake_borrows(self, candidates));
|
self,
|
||||||
|
candidates,
|
||||||
|
scrutinee_span,
|
||||||
|
scrutinee_place_builder.base(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
};
|
||||||
|
|
||||||
// See the doc comment on `match_candidates` for why we have an
|
// See the doc comment on `match_candidates` for why we have an
|
||||||
// otherwise block. Match checking will ensure this is actually
|
// otherwise block. Match checking will ensure this is actually
|
||||||
@ -439,11 +443,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ref borrows) = fake_borrows {
|
fake_borrows
|
||||||
self.calculate_fake_borrows(borrows, scrutinee_span)
|
|
||||||
} else {
|
|
||||||
Vec::new()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lower the bindings, guards and arm bodies of a `match` expression.
|
/// Lower the bindings, guards and arm bodies of a `match` expression.
|
||||||
@ -459,7 +459,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
scrutinee_span: Span,
|
scrutinee_span: Span,
|
||||||
arm_candidates: Vec<(&'_ Arm<'tcx>, Candidate<'_, 'tcx>)>,
|
arm_candidates: Vec<(&'_ Arm<'tcx>, Candidate<'_, 'tcx>)>,
|
||||||
outer_source_info: SourceInfo,
|
outer_source_info: SourceInfo,
|
||||||
fake_borrow_temps: Vec<(Place<'tcx>, Local)>,
|
fake_borrow_temps: Vec<(Place<'tcx>, Local, FakeBorrowKind)>,
|
||||||
) -> BlockAnd<()> {
|
) -> BlockAnd<()> {
|
||||||
let arm_end_blocks: Vec<_> = arm_candidates
|
let arm_end_blocks: Vec<_> = arm_candidates
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -543,7 +543,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
outer_source_info: SourceInfo,
|
outer_source_info: SourceInfo,
|
||||||
candidate: Candidate<'_, 'tcx>,
|
candidate: Candidate<'_, 'tcx>,
|
||||||
fake_borrow_temps: &[(Place<'tcx>, Local)],
|
fake_borrow_temps: &[(Place<'tcx>, Local, FakeBorrowKind)],
|
||||||
scrutinee_span: Span,
|
scrutinee_span: Span,
|
||||||
arm_match_scope: Option<(&Arm<'tcx>, region::Scope)>,
|
arm_match_scope: Option<(&Arm<'tcx>, region::Scope)>,
|
||||||
storages_alive: bool,
|
storages_alive: bool,
|
||||||
@ -940,7 +940,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
self.visit_primary_bindings(subpattern, pattern_user_ty.deref(), f);
|
self.visit_primary_bindings(subpattern, pattern_user_ty.deref(), f);
|
||||||
}
|
}
|
||||||
|
|
||||||
PatKind::DerefPattern { ref subpattern } => {
|
PatKind::DerefPattern { ref subpattern, .. } => {
|
||||||
self.visit_primary_bindings(subpattern, UserTypeProjections::none(), f);
|
self.visit_primary_bindings(subpattern, UserTypeProjections::none(), f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1165,6 +1165,7 @@ enum TestCase<'pat, 'tcx> {
|
|||||||
Constant { value: mir::Const<'tcx> },
|
Constant { value: mir::Const<'tcx> },
|
||||||
Range(&'pat PatRange<'tcx>),
|
Range(&'pat PatRange<'tcx>),
|
||||||
Slice { len: usize, variable_length: bool },
|
Slice { len: usize, variable_length: bool },
|
||||||
|
Deref { temp: Place<'tcx>, mutability: Mutability },
|
||||||
Or { pats: Box<[FlatPat<'pat, 'tcx>]> },
|
Or { pats: Box<[FlatPat<'pat, 'tcx>]> },
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1224,6 +1225,13 @@ enum TestKind<'tcx> {
|
|||||||
|
|
||||||
/// Test that the length of the slice is equal to `len`.
|
/// Test that the length of the slice is equal to `len`.
|
||||||
Len { len: u64, op: BinOp },
|
Len { len: u64, op: BinOp },
|
||||||
|
|
||||||
|
/// Call `Deref::deref[_mut]` on the value.
|
||||||
|
Deref {
|
||||||
|
/// Temporary to store the result of `deref()`/`deref_mut()`.
|
||||||
|
temp: Place<'tcx>,
|
||||||
|
mutability: Mutability,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A test to perform to determine which [`Candidate`] matches a value.
|
/// A test to perform to determine which [`Candidate`] matches a value.
|
||||||
@ -1905,81 +1913,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
target_blocks,
|
target_blocks,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determine the fake borrows that are needed from a set of places that
|
|
||||||
/// have to be stable across match guards.
|
|
||||||
///
|
|
||||||
/// Returns a list of places that need a fake borrow and the temporary
|
|
||||||
/// that's used to store the fake borrow.
|
|
||||||
///
|
|
||||||
/// Match exhaustiveness checking is not able to handle the case where the
|
|
||||||
/// place being matched on is mutated in the guards. We add "fake borrows"
|
|
||||||
/// to the guards that prevent any mutation of the place being matched.
|
|
||||||
/// There are a some subtleties:
|
|
||||||
///
|
|
||||||
/// 1. Borrowing `*x` doesn't prevent assigning to `x`. If `x` is a shared
|
|
||||||
/// reference, the borrow isn't even tracked. As such we have to add fake
|
|
||||||
/// borrows of any prefixes of a place
|
|
||||||
/// 2. We don't want `match x { _ => (), }` to conflict with mutable
|
|
||||||
/// borrows of `x`, so we only add fake borrows for places which are
|
|
||||||
/// bound or tested by the match.
|
|
||||||
/// 3. We don't want the fake borrows to conflict with `ref mut` bindings,
|
|
||||||
/// so we use a special BorrowKind for them.
|
|
||||||
/// 4. The fake borrows may be of places in inactive variants, so it would
|
|
||||||
/// be UB to generate code for them. They therefore have to be removed
|
|
||||||
/// by a MIR pass run after borrow checking.
|
|
||||||
fn calculate_fake_borrows<'b>(
|
|
||||||
&mut self,
|
|
||||||
fake_borrows: &'b FxIndexSet<Place<'tcx>>,
|
|
||||||
temp_span: Span,
|
|
||||||
) -> Vec<(Place<'tcx>, Local)> {
|
|
||||||
let tcx = self.tcx;
|
|
||||||
|
|
||||||
debug!("add_fake_borrows fake_borrows = {:?}", fake_borrows);
|
|
||||||
|
|
||||||
let mut all_fake_borrows = Vec::with_capacity(fake_borrows.len());
|
|
||||||
|
|
||||||
// Insert a Shallow borrow of the prefixes of any fake borrows.
|
|
||||||
for place in fake_borrows {
|
|
||||||
let mut cursor = place.projection.as_ref();
|
|
||||||
while let [proj_base @ .., elem] = cursor {
|
|
||||||
cursor = proj_base;
|
|
||||||
|
|
||||||
if let ProjectionElem::Deref = elem {
|
|
||||||
// Insert a shallow borrow after a deref. For other
|
|
||||||
// projections the borrow of prefix_cursor will
|
|
||||||
// conflict with any mutation of base.
|
|
||||||
all_fake_borrows.push(PlaceRef { local: place.local, projection: proj_base });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
all_fake_borrows.push(place.as_ref());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deduplicate
|
|
||||||
let mut dedup = FxHashSet::default();
|
|
||||||
all_fake_borrows.retain(|b| dedup.insert(*b));
|
|
||||||
|
|
||||||
debug!("add_fake_borrows all_fake_borrows = {:?}", all_fake_borrows);
|
|
||||||
|
|
||||||
all_fake_borrows
|
|
||||||
.into_iter()
|
|
||||||
.map(|matched_place_ref| {
|
|
||||||
let matched_place = Place {
|
|
||||||
local: matched_place_ref.local,
|
|
||||||
projection: tcx.mk_place_elems(matched_place_ref.projection),
|
|
||||||
};
|
|
||||||
let fake_borrow_deref_ty = matched_place.ty(&self.local_decls, tcx).ty;
|
|
||||||
let fake_borrow_ty =
|
|
||||||
Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, fake_borrow_deref_ty);
|
|
||||||
let mut fake_borrow_temp = LocalDecl::new(fake_borrow_ty, temp_span);
|
|
||||||
fake_borrow_temp.local_info = ClearCrossCrate::Set(Box::new(LocalInfo::FakeBorrow));
|
|
||||||
let fake_borrow_temp = self.local_decls.push(fake_borrow_temp);
|
|
||||||
|
|
||||||
(matched_place, fake_borrow_temp)
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
@ -2044,7 +1977,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
candidate: Candidate<'pat, 'tcx>,
|
candidate: Candidate<'pat, 'tcx>,
|
||||||
parent_data: &[PatternExtraData<'tcx>],
|
parent_data: &[PatternExtraData<'tcx>],
|
||||||
fake_borrows: &[(Place<'tcx>, Local)],
|
fake_borrows: &[(Place<'tcx>, Local, FakeBorrowKind)],
|
||||||
scrutinee_span: Span,
|
scrutinee_span: Span,
|
||||||
arm_match_scope: Option<(&Arm<'tcx>, region::Scope)>,
|
arm_match_scope: Option<(&Arm<'tcx>, region::Scope)>,
|
||||||
schedule_drops: bool,
|
schedule_drops: bool,
|
||||||
@ -2174,8 +2107,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
|
|
||||||
let re_erased = tcx.lifetimes.re_erased;
|
let re_erased = tcx.lifetimes.re_erased;
|
||||||
let scrutinee_source_info = self.source_info(scrutinee_span);
|
let scrutinee_source_info = self.source_info(scrutinee_span);
|
||||||
for &(place, temp) in fake_borrows {
|
for &(place, temp, kind) in fake_borrows {
|
||||||
let borrow = Rvalue::Ref(re_erased, BorrowKind::Fake, place);
|
let borrow = Rvalue::Ref(re_erased, BorrowKind::Fake(kind), place);
|
||||||
self.cfg.push_assign(block, scrutinee_source_info, Place::from(temp), borrow);
|
self.cfg.push_assign(block, scrutinee_source_info, Place::from(temp), borrow);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2198,7 +2131,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
let guard_frame = self.guard_context.pop().unwrap();
|
let guard_frame = self.guard_context.pop().unwrap();
|
||||||
debug!("Exiting guard building context with locals: {:?}", guard_frame);
|
debug!("Exiting guard building context with locals: {:?}", guard_frame);
|
||||||
|
|
||||||
for &(_, temp) in fake_borrows {
|
for &(_, temp, _) in fake_borrows {
|
||||||
let cause = FakeReadCause::ForMatchGuard;
|
let cause = FakeReadCause::ForMatchGuard;
|
||||||
self.cfg.push_fake_read(post_guard_block, guard_end, cause, Place::from(temp));
|
self.cfg.push_fake_read(post_guard_block, guard_end, cause, Place::from(temp));
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
TestKind::Len { len: len as u64, op }
|
TestKind::Len { len: len as u64, op }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TestCase::Deref { temp, mutability } => TestKind::Deref { temp, mutability },
|
||||||
|
|
||||||
TestCase::Or { .. } => bug!("or-patterns should have already been handled"),
|
TestCase::Or { .. } => bug!("or-patterns should have already been handled"),
|
||||||
|
|
||||||
TestCase::Irrefutable { .. } => span_bug!(
|
TestCase::Irrefutable { .. } => span_bug!(
|
||||||
@ -143,34 +145,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
let re_erased = tcx.lifetimes.re_erased;
|
let re_erased = tcx.lifetimes.re_erased;
|
||||||
let ref_string = self.temp(Ty::new_imm_ref(tcx, re_erased, ty), test.span);
|
|
||||||
let ref_str_ty = Ty::new_imm_ref(tcx, re_erased, tcx.types.str_);
|
let ref_str_ty = Ty::new_imm_ref(tcx, re_erased, tcx.types.str_);
|
||||||
let ref_str = self.temp(ref_str_ty, test.span);
|
let ref_str = self.temp(ref_str_ty, test.span);
|
||||||
let deref = tcx.require_lang_item(LangItem::Deref, None);
|
|
||||||
let method = trait_method(tcx, deref, sym::deref, [ty]);
|
|
||||||
let eq_block = self.cfg.start_new_block();
|
let eq_block = self.cfg.start_new_block();
|
||||||
self.cfg.push_assign(
|
// `let ref_str: &str = <String as Deref>::deref(&place);`
|
||||||
|
self.call_deref(
|
||||||
block,
|
block,
|
||||||
source_info,
|
eq_block,
|
||||||
ref_string,
|
place,
|
||||||
Rvalue::Ref(re_erased, BorrowKind::Shared, place),
|
Mutability::Not,
|
||||||
);
|
ty,
|
||||||
self.cfg.terminate(
|
ref_str,
|
||||||
block,
|
test.span,
|
||||||
source_info,
|
|
||||||
TerminatorKind::Call {
|
|
||||||
func: Operand::Constant(Box::new(ConstOperand {
|
|
||||||
span: test.span,
|
|
||||||
user_ty: None,
|
|
||||||
const_: method,
|
|
||||||
})),
|
|
||||||
args: vec![Spanned { node: Operand::Move(ref_string), span: DUMMY_SP }],
|
|
||||||
destination: ref_str,
|
|
||||||
target: Some(eq_block),
|
|
||||||
unwind: UnwindAction::Continue,
|
|
||||||
call_source: CallSource::Misc,
|
|
||||||
fn_span: source_info.span,
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
self.non_scalar_compare(
|
self.non_scalar_compare(
|
||||||
eq_block,
|
eq_block,
|
||||||
@ -270,9 +256,66 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
Operand::Move(expected),
|
Operand::Move(expected),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TestKind::Deref { temp, mutability } => {
|
||||||
|
let ty = place_ty.ty;
|
||||||
|
let target = target_block(TestBranch::Success);
|
||||||
|
self.call_deref(block, target, place, mutability, ty, temp, test.span);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Perform `let temp = <ty as Deref>::deref(&place)`.
|
||||||
|
/// or `let temp = <ty as DerefMut>::deref_mut(&mut place)`.
|
||||||
|
pub(super) fn call_deref(
|
||||||
|
&mut self,
|
||||||
|
block: BasicBlock,
|
||||||
|
target_block: BasicBlock,
|
||||||
|
place: Place<'tcx>,
|
||||||
|
mutability: Mutability,
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
temp: Place<'tcx>,
|
||||||
|
span: Span,
|
||||||
|
) {
|
||||||
|
let (trait_item, method) = match mutability {
|
||||||
|
Mutability::Not => (LangItem::Deref, sym::deref),
|
||||||
|
Mutability::Mut => (LangItem::DerefMut, sym::deref_mut),
|
||||||
|
};
|
||||||
|
let borrow_kind = super::util::ref_pat_borrow_kind(mutability);
|
||||||
|
let source_info = self.source_info(span);
|
||||||
|
let re_erased = self.tcx.lifetimes.re_erased;
|
||||||
|
let trait_item = self.tcx.require_lang_item(trait_item, None);
|
||||||
|
let method = trait_method(self.tcx, trait_item, method, [ty]);
|
||||||
|
let ref_src = self.temp(Ty::new_ref(self.tcx, re_erased, ty, mutability), span);
|
||||||
|
// `let ref_src = &src_place;`
|
||||||
|
// or `let ref_src = &mut src_place;`
|
||||||
|
self.cfg.push_assign(
|
||||||
|
block,
|
||||||
|
source_info,
|
||||||
|
ref_src,
|
||||||
|
Rvalue::Ref(re_erased, borrow_kind, place),
|
||||||
|
);
|
||||||
|
// `let temp = <Ty as Deref>::deref(ref_src);`
|
||||||
|
// or `let temp = <Ty as DerefMut>::deref_mut(ref_src);`
|
||||||
|
self.cfg.terminate(
|
||||||
|
block,
|
||||||
|
source_info,
|
||||||
|
TerminatorKind::Call {
|
||||||
|
func: Operand::Constant(Box::new(ConstOperand {
|
||||||
|
span,
|
||||||
|
user_ty: None,
|
||||||
|
const_: method,
|
||||||
|
})),
|
||||||
|
args: vec![Spanned { node: Operand::Move(ref_src), span }],
|
||||||
|
destination: temp,
|
||||||
|
target: Some(target_block),
|
||||||
|
unwind: UnwindAction::Continue,
|
||||||
|
call_source: CallSource::Misc,
|
||||||
|
fn_span: source_info.span,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// Compare using the provided built-in comparison operator
|
/// Compare using the provided built-in comparison operator
|
||||||
fn compare(
|
fn compare(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -660,13 +703,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(TestKind::Deref { temp: test_temp, .. }, TestCase::Deref { temp, .. })
|
||||||
|
if test_temp == temp =>
|
||||||
|
{
|
||||||
|
fully_matched = true;
|
||||||
|
Some(TestBranch::Success)
|
||||||
|
}
|
||||||
|
|
||||||
(
|
(
|
||||||
TestKind::Switch { .. }
|
TestKind::Switch { .. }
|
||||||
| TestKind::SwitchInt { .. }
|
| TestKind::SwitchInt { .. }
|
||||||
| TestKind::If
|
| TestKind::If
|
||||||
| TestKind::Len { .. }
|
| TestKind::Len { .. }
|
||||||
| TestKind::Range { .. }
|
| TestKind::Range { .. }
|
||||||
| TestKind::Eq { .. },
|
| TestKind::Eq { .. }
|
||||||
|
| TestKind::Deref { .. },
|
||||||
_,
|
_,
|
||||||
) => {
|
) => {
|
||||||
fully_matched = false;
|
fully_matched = false;
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
use crate::build::expr::as_place::{PlaceBase, PlaceBuilder};
|
use crate::build::expr::as_place::{PlaceBase, PlaceBuilder};
|
||||||
use crate::build::matches::{Binding, Candidate, FlatPat, MatchPair, TestCase};
|
use crate::build::matches::{Binding, Candidate, FlatPat, MatchPair, TestCase};
|
||||||
use crate::build::Builder;
|
use crate::build::Builder;
|
||||||
use rustc_data_structures::fx::FxIndexSet;
|
use rustc_data_structures::fx::FxIndexMap;
|
||||||
use rustc_infer::infer::type_variable::TypeVariableOrigin;
|
use rustc_infer::infer::type_variable::TypeVariableOrigin;
|
||||||
use rustc_middle::mir::*;
|
use rustc_middle::mir::*;
|
||||||
use rustc_middle::thir::{self, *};
|
use rustc_middle::thir::{self, *};
|
||||||
use rustc_middle::ty;
|
|
||||||
use rustc_middle::ty::TypeVisitableExt;
|
use rustc_middle::ty::TypeVisitableExt;
|
||||||
|
use rustc_middle::ty::{self, Ty};
|
||||||
|
use rustc_span::Span;
|
||||||
|
|
||||||
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
pub(crate) fn field_match_pairs<'pat>(
|
pub(crate) fn field_match_pairs<'pat>(
|
||||||
@ -249,10 +250,15 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
|
|||||||
default_irrefutable()
|
default_irrefutable()
|
||||||
}
|
}
|
||||||
|
|
||||||
PatKind::DerefPattern { .. } => {
|
PatKind::DerefPattern { ref subpattern, mutability } => {
|
||||||
// FIXME(deref_patterns)
|
// Create a new temporary for each deref pattern.
|
||||||
// Treat it like a wildcard for now.
|
// FIXME(deref_patterns): dedup temporaries to avoid multiple `deref()` calls?
|
||||||
default_irrefutable()
|
let temp = cx.temp(
|
||||||
|
Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, subpattern.ty, mutability),
|
||||||
|
pattern.span,
|
||||||
|
);
|
||||||
|
subpairs.push(MatchPair::new(PlaceBuilder::from(temp).deref(), subpattern, cx));
|
||||||
|
TestCase::Deref { temp, mutability }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -262,19 +268,103 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
|
|||||||
|
|
||||||
pub(super) struct FakeBorrowCollector<'a, 'b, 'tcx> {
|
pub(super) struct FakeBorrowCollector<'a, 'b, 'tcx> {
|
||||||
cx: &'a mut Builder<'b, 'tcx>,
|
cx: &'a mut Builder<'b, 'tcx>,
|
||||||
fake_borrows: FxIndexSet<Place<'tcx>>,
|
/// Base of the scrutinee place. Used to distinguish bindings inside the scrutinee place from
|
||||||
|
/// bindings inside deref patterns.
|
||||||
|
scrutinee_base: PlaceBase,
|
||||||
|
/// Store for each place the kind of borrow to take. In case of conflicts, we take the strongest
|
||||||
|
/// borrow (i.e. Deep > Shallow).
|
||||||
|
/// Invariant: for any place in `fake_borrows`, all the prefixes of this place that are
|
||||||
|
/// dereferences are also borrowed with the same of stronger borrow kind.
|
||||||
|
fake_borrows: FxIndexMap<Place<'tcx>, FakeBorrowKind>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determine the set of places that have to be stable across match guards.
|
||||||
|
///
|
||||||
|
/// Returns a list of places that need a fake borrow along with a local to store it.
|
||||||
|
///
|
||||||
|
/// Match exhaustiveness checking is not able to handle the case where the place being matched on is
|
||||||
|
/// mutated in the guards. We add "fake borrows" to the guards that prevent any mutation of the
|
||||||
|
/// place being matched. There are a some subtleties:
|
||||||
|
///
|
||||||
|
/// 1. Borrowing `*x` doesn't prevent assigning to `x`. If `x` is a shared reference, the borrow
|
||||||
|
/// isn't even tracked. As such we have to add fake borrows of any prefixes of a place.
|
||||||
|
/// 2. We don't want `match x { (Some(_), _) => (), .. }` to conflict with mutable borrows of `x.1`, so we
|
||||||
|
/// only add fake borrows for places which are bound or tested by the match.
|
||||||
|
/// 3. We don't want `match x { Some(_) => (), .. }` to conflict with mutable borrows of `(x as
|
||||||
|
/// Some).0`, so the borrows are a special shallow borrow that only affects the place and not its
|
||||||
|
/// projections.
|
||||||
|
/// ```rust
|
||||||
|
/// let mut x = (Some(0), true);
|
||||||
|
/// match x {
|
||||||
|
/// (Some(_), false) => {}
|
||||||
|
/// _ if { if let Some(ref mut y) = x.0 { *y += 1 }; true } => {}
|
||||||
|
/// _ => {}
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
/// 4. The fake borrows may be of places in inactive variants, e.g. here we need to fake borrow `x`
|
||||||
|
/// and `(x as Some).0`, but when we reach the guard `x` may not be `Some`.
|
||||||
|
/// ```rust
|
||||||
|
/// let mut x = (Some(Some(0)), true);
|
||||||
|
/// match x {
|
||||||
|
/// (Some(Some(_)), false) => {}
|
||||||
|
/// _ if { if let Some(Some(ref mut y)) = x.0 { *y += 1 }; true } => {}
|
||||||
|
/// _ => {}
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
/// So it would be UB to generate code for the fake borrows. They therefore have to be removed by
|
||||||
|
/// a MIR pass run after borrow checking.
|
||||||
|
pub(super) fn collect_fake_borrows<'tcx>(
|
||||||
|
cx: &mut Builder<'_, 'tcx>,
|
||||||
|
candidates: &[&mut Candidate<'_, 'tcx>],
|
||||||
|
temp_span: Span,
|
||||||
|
scrutinee_base: PlaceBase,
|
||||||
|
) -> Vec<(Place<'tcx>, Local, FakeBorrowKind)> {
|
||||||
|
let mut collector =
|
||||||
|
FakeBorrowCollector { cx, scrutinee_base, fake_borrows: FxIndexMap::default() };
|
||||||
|
for candidate in candidates.iter() {
|
||||||
|
collector.visit_candidate(candidate);
|
||||||
|
}
|
||||||
|
let fake_borrows = collector.fake_borrows;
|
||||||
|
debug!("add_fake_borrows fake_borrows = {:?}", fake_borrows);
|
||||||
|
let tcx = cx.tcx;
|
||||||
|
fake_borrows
|
||||||
|
.iter()
|
||||||
|
.map(|(matched_place, borrow_kind)| {
|
||||||
|
let fake_borrow_deref_ty = matched_place.ty(&cx.local_decls, tcx).ty;
|
||||||
|
let fake_borrow_ty =
|
||||||
|
Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, fake_borrow_deref_ty);
|
||||||
|
let mut fake_borrow_temp = LocalDecl::new(fake_borrow_ty, temp_span);
|
||||||
|
fake_borrow_temp.local_info = ClearCrossCrate::Set(Box::new(LocalInfo::FakeBorrow));
|
||||||
|
let fake_borrow_temp = cx.local_decls.push(fake_borrow_temp);
|
||||||
|
(*matched_place, fake_borrow_temp, *borrow_kind)
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> {
|
impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> {
|
||||||
pub(super) fn collect_fake_borrows(
|
// Fake borrow this place and its dereference prefixes.
|
||||||
cx: &'a mut Builder<'b, 'tcx>,
|
fn fake_borrow(&mut self, place: Place<'tcx>, kind: FakeBorrowKind) {
|
||||||
candidates: &[&mut Candidate<'_, 'tcx>],
|
if self.fake_borrows.get(&place).is_some_and(|k| *k >= kind) {
|
||||||
) -> FxIndexSet<Place<'tcx>> {
|
return;
|
||||||
let mut collector = Self { cx, fake_borrows: FxIndexSet::default() };
|
}
|
||||||
for candidate in candidates.iter() {
|
self.fake_borrows.insert(place, kind);
|
||||||
collector.visit_candidate(candidate);
|
// Also fake borrow the prefixes of any fake borrow.
|
||||||
|
self.fake_borrow_deref_prefixes(place, kind);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fake borrow the prefixes of this place that are dereferences.
|
||||||
|
fn fake_borrow_deref_prefixes(&mut self, place: Place<'tcx>, kind: FakeBorrowKind) {
|
||||||
|
for (place_ref, elem) in place.as_ref().iter_projections().rev() {
|
||||||
|
if let ProjectionElem::Deref = elem {
|
||||||
|
// Insert a shallow borrow after a deref. For other projections the borrow of
|
||||||
|
// `place_ref` will conflict with any mutation of `place.base`.
|
||||||
|
let place = place_ref.to_place(self.cx.tcx);
|
||||||
|
if self.fake_borrows.get(&place).is_some_and(|k| *k >= kind) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.fake_borrows.insert(place, kind);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
collector.fake_borrows
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_candidate(&mut self, candidate: &Candidate<'_, 'tcx>) {
|
fn visit_candidate(&mut self, candidate: &Candidate<'_, 'tcx>) {
|
||||||
@ -300,10 +390,27 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> {
|
|||||||
for flat_pat in pats.iter() {
|
for flat_pat in pats.iter() {
|
||||||
self.visit_flat_pat(flat_pat)
|
self.visit_flat_pat(flat_pat)
|
||||||
}
|
}
|
||||||
|
} else if matches!(match_pair.test_case, TestCase::Deref { .. }) {
|
||||||
|
// The subpairs of a deref pattern are all places relative to the deref temporary, so we
|
||||||
|
// don't fake borrow them. Problem is, if we only shallowly fake-borrowed
|
||||||
|
// `match_pair.place`, this would allow:
|
||||||
|
// ```
|
||||||
|
// let mut b = Box::new(false);
|
||||||
|
// match b {
|
||||||
|
// deref!(true) => {} // not reached because `*b == false`
|
||||||
|
// _ if { *b = true; false } => {} // not reached because the guard is `false`
|
||||||
|
// deref!(false) => {} // not reached because the guard changed it
|
||||||
|
// // UB because we reached the unreachable.
|
||||||
|
// }
|
||||||
|
// ```
|
||||||
|
// Hence we fake borrow using a deep borrow.
|
||||||
|
if let Some(place) = match_pair.place {
|
||||||
|
self.fake_borrow(place, FakeBorrowKind::Deep);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Insert a Shallow borrow of any place that is switched on.
|
// Insert a Shallow borrow of any place that is switched on.
|
||||||
if let Some(place) = match_pair.place {
|
if let Some(place) = match_pair.place {
|
||||||
self.fake_borrows.insert(place);
|
self.fake_borrow(place, FakeBorrowKind::Shallow);
|
||||||
}
|
}
|
||||||
|
|
||||||
for subpair in &match_pair.subpairs {
|
for subpair in &match_pair.subpairs {
|
||||||
@ -313,6 +420,14 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn visit_binding(&mut self, Binding { source, .. }: &Binding<'tcx>) {
|
fn visit_binding(&mut self, Binding { source, .. }: &Binding<'tcx>) {
|
||||||
|
if let PlaceBase::Local(l) = self.scrutinee_base
|
||||||
|
&& l != source.local
|
||||||
|
{
|
||||||
|
// The base of this place is a temporary created for deref patterns. We don't emit fake
|
||||||
|
// borrows for these as they are not initialized in all branches.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Insert a borrows of prefixes of places that are bound and are
|
// Insert a borrows of prefixes of places that are bound and are
|
||||||
// behind a dereference projection.
|
// behind a dereference projection.
|
||||||
//
|
//
|
||||||
@ -329,13 +444,13 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> {
|
|||||||
// y if { y == 1 && (x = &2) == () } => y,
|
// y if { y == 1 && (x = &2) == () } => y,
|
||||||
// _ => 3,
|
// _ => 3,
|
||||||
// }
|
// }
|
||||||
if let Some(i) = source.projection.iter().rposition(|elem| elem == ProjectionElem::Deref) {
|
//
|
||||||
let proj_base = &source.projection[..i];
|
// We don't just fake borrow the whole place because this is allowed:
|
||||||
self.fake_borrows.insert(Place {
|
// match u {
|
||||||
local: source.local,
|
// _ if { u = true; false } => (),
|
||||||
projection: self.cx.tcx.mk_place_elems(proj_base),
|
// x => (),
|
||||||
});
|
// }
|
||||||
}
|
self.fake_borrow_deref_prefixes(*source, FakeBorrowKind::Shallow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -513,7 +513,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
|||||||
visit::walk_expr(&mut visitor, expr);
|
visit::walk_expr(&mut visitor, expr);
|
||||||
if visitor.found {
|
if visitor.found {
|
||||||
match borrow_kind {
|
match borrow_kind {
|
||||||
BorrowKind::Fake | BorrowKind::Shared
|
BorrowKind::Fake(_) | BorrowKind::Shared
|
||||||
if !self.thir[arg].ty.is_freeze(self.tcx, self.param_env) =>
|
if !self.thir[arg].ty.is_freeze(self.tcx, self.param_env) =>
|
||||||
{
|
{
|
||||||
self.requires_unsafe(expr.span, BorrowOfLayoutConstrainedField)
|
self.requires_unsafe(expr.span, BorrowOfLayoutConstrainedField)
|
||||||
@ -521,7 +521,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
|||||||
BorrowKind::Mut { .. } => {
|
BorrowKind::Mut { .. } => {
|
||||||
self.requires_unsafe(expr.span, MutationOfLayoutConstrainedField)
|
self.requires_unsafe(expr.span, MutationOfLayoutConstrainedField)
|
||||||
}
|
}
|
||||||
BorrowKind::Fake | BorrowKind::Shared => {}
|
BorrowKind::Fake(_) | BorrowKind::Shared => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -423,7 +423,7 @@ impl Subdiagnostic for UnsafeNotInheritedLintNote {
|
|||||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
self,
|
self,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
_f: F,
|
_f: &F,
|
||||||
) {
|
) {
|
||||||
diag.span_note(self.signature_span, fluent::mir_build_unsafe_fn_safe_body);
|
diag.span_note(self.signature_span, fluent::mir_build_unsafe_fn_safe_body);
|
||||||
let body_start = self.body_span.shrink_to_lo();
|
let body_start = self.body_span.shrink_to_lo();
|
||||||
@ -871,7 +871,7 @@ impl<'tcx> Subdiagnostic for AdtDefinedHere<'tcx> {
|
|||||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
self,
|
self,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
_f: F,
|
_f: &F,
|
||||||
) {
|
) {
|
||||||
diag.arg("ty", self.ty);
|
diag.arg("ty", self.ty);
|
||||||
let mut spans = MultiSpan::from(self.adt_def_span);
|
let mut spans = MultiSpan::from(self.adt_def_span);
|
||||||
|
@ -264,7 +264,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hir::PatKind::Deref(subpattern) => {
|
hir::PatKind::Deref(subpattern) => {
|
||||||
PatKind::DerefPattern { subpattern: self.lower_pattern(subpattern) }
|
let mutable = self.typeck_results.pat_has_ref_mut_binding(subpattern);
|
||||||
|
let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
|
||||||
|
PatKind::DerefPattern { subpattern: self.lower_pattern(subpattern), mutability }
|
||||||
}
|
}
|
||||||
hir::PatKind::Ref(subpattern, _) | hir::PatKind::Box(subpattern) => {
|
hir::PatKind::Ref(subpattern, _) | hir::PatKind::Box(subpattern) => {
|
||||||
PatKind::Deref { subpattern: self.lower_pattern(subpattern) }
|
PatKind::Deref { subpattern: self.lower_pattern(subpattern) }
|
||||||
|
@ -688,7 +688,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
|
|||||||
self.print_pat(subpattern, depth_lvl + 2);
|
self.print_pat(subpattern, depth_lvl + 2);
|
||||||
print_indented!(self, "}", depth_lvl + 1);
|
print_indented!(self, "}", depth_lvl + 1);
|
||||||
}
|
}
|
||||||
PatKind::DerefPattern { subpattern } => {
|
PatKind::DerefPattern { subpattern, .. } => {
|
||||||
print_indented!(self, "DerefPattern { ", depth_lvl + 1);
|
print_indented!(self, "DerefPattern { ", depth_lvl + 1);
|
||||||
print_indented!(self, "subpattern:", depth_lvl + 2);
|
print_indented!(self, "subpattern:", depth_lvl + 2);
|
||||||
self.print_pat(subpattern, depth_lvl + 2);
|
self.print_pat(subpattern, depth_lvl + 2);
|
||||||
|
@ -102,7 +102,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
Rvalue::Cast(..)
|
Rvalue::Cast(..)
|
||||||
| Rvalue::Ref(_, BorrowKind::Fake, _)
|
| Rvalue::Ref(_, BorrowKind::Fake(_), _)
|
||||||
| Rvalue::ShallowInitBox(..)
|
| Rvalue::ShallowInitBox(..)
|
||||||
| Rvalue::Use(..)
|
| Rvalue::Use(..)
|
||||||
| Rvalue::ThreadLocalRef(..)
|
| Rvalue::ThreadLocalRef(..)
|
||||||
|
@ -29,7 +29,7 @@ impl<'tcx> MirPass<'tcx> for CleanupPostBorrowck {
|
|||||||
for statement in basic_block.statements.iter_mut() {
|
for statement in basic_block.statements.iter_mut() {
|
||||||
match statement.kind {
|
match statement.kind {
|
||||||
StatementKind::AscribeUserType(..)
|
StatementKind::AscribeUserType(..)
|
||||||
| StatementKind::Assign(box (_, Rvalue::Ref(_, BorrowKind::Fake, _)))
|
| StatementKind::Assign(box (_, Rvalue::Ref(_, BorrowKind::Fake(_), _)))
|
||||||
| StatementKind::Coverage(
|
| StatementKind::Coverage(
|
||||||
// These kinds of coverage statements are markers inserted during
|
// These kinds of coverage statements are markers inserted during
|
||||||
// MIR building, and are not needed after InstrumentCoverage.
|
// MIR building, and are not needed after InstrumentCoverage.
|
||||||
|
@ -80,6 +80,10 @@ use rustc_span::symbol::sym;
|
|||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_target::abi::{FieldIdx, VariantIdx};
|
use rustc_target::abi::{FieldIdx, VariantIdx};
|
||||||
use rustc_target::spec::PanicStrategy;
|
use rustc_target::spec::PanicStrategy;
|
||||||
|
use rustc_trait_selection::infer::TyCtxtInferExt as _;
|
||||||
|
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
|
||||||
|
use rustc_trait_selection::traits::ObligationCtxt;
|
||||||
|
use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
|
||||||
use std::{iter, ops};
|
use std::{iter, ops};
|
||||||
|
|
||||||
pub struct StateTransform;
|
pub struct StateTransform;
|
||||||
@ -1584,10 +1588,46 @@ pub(crate) fn mir_coroutine_witnesses<'tcx>(
|
|||||||
let (_, coroutine_layout, _) = compute_layout(liveness_info, body);
|
let (_, coroutine_layout, _) = compute_layout(liveness_info, body);
|
||||||
|
|
||||||
check_suspend_tys(tcx, &coroutine_layout, body);
|
check_suspend_tys(tcx, &coroutine_layout, body);
|
||||||
|
check_field_tys_sized(tcx, &coroutine_layout, def_id);
|
||||||
|
|
||||||
Some(coroutine_layout)
|
Some(coroutine_layout)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_field_tys_sized<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
coroutine_layout: &CoroutineLayout<'tcx>,
|
||||||
|
def_id: LocalDefId,
|
||||||
|
) {
|
||||||
|
// No need to check if unsized_locals/unsized_fn_params is disabled,
|
||||||
|
// since we will error during typeck.
|
||||||
|
if !tcx.features().unsized_locals && !tcx.features().unsized_fn_params {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let infcx = tcx.infer_ctxt().ignoring_regions().build();
|
||||||
|
let param_env = tcx.param_env(def_id);
|
||||||
|
|
||||||
|
let ocx = ObligationCtxt::new(&infcx);
|
||||||
|
for field_ty in &coroutine_layout.field_tys {
|
||||||
|
ocx.register_bound(
|
||||||
|
ObligationCause::new(
|
||||||
|
field_ty.source_info.span,
|
||||||
|
def_id,
|
||||||
|
ObligationCauseCode::SizedCoroutineInterior(def_id),
|
||||||
|
),
|
||||||
|
param_env,
|
||||||
|
field_ty.ty,
|
||||||
|
tcx.require_lang_item(hir::LangItem::Sized, Some(field_ty.source_info.span)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let errors = ocx.select_all_or_error();
|
||||||
|
debug!(?errors);
|
||||||
|
if !errors.is_empty() {
|
||||||
|
infcx.err_ctxt().report_fulfillment_errors(errors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx> MirPass<'tcx> for StateTransform {
|
impl<'tcx> MirPass<'tcx> for StateTransform {
|
||||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||||
let Some(old_yield_ty) = body.yield_ty() else {
|
let Some(old_yield_ty) = body.yield_ty() else {
|
||||||
|
@ -384,7 +384,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||||||
match kind {
|
match kind {
|
||||||
// Reject these borrow types just to be safe.
|
// Reject these borrow types just to be safe.
|
||||||
// FIXME(RalfJung): could we allow them? Should we? No point in it until we have a usecase.
|
// FIXME(RalfJung): could we allow them? Should we? No point in it until we have a usecase.
|
||||||
BorrowKind::Fake | BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } => {
|
BorrowKind::Fake(_) | BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } => {
|
||||||
return Err(Unpromotable);
|
return Err(Unpromotable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1472,7 +1472,7 @@ impl Subdiagnostic for FnTraitMissingParen {
|
|||||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
self,
|
self,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
_: F,
|
_: &F,
|
||||||
) {
|
) {
|
||||||
diag.span_label(self.span, crate::fluent_generated::parse_fn_trait_missing_paren);
|
diag.span_label(self.span, crate::fluent_generated::parse_fn_trait_missing_paren);
|
||||||
let applicability = if self.machine_applicable {
|
let applicability = if self.machine_applicable {
|
||||||
|
@ -1765,7 +1765,7 @@ impl Subdiagnostic for UnusedVariableStringInterp {
|
|||||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
self,
|
self,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
_f: F,
|
_f: &F,
|
||||||
) {
|
) {
|
||||||
diag.span_label(self.lit, crate::fluent_generated::passes_maybe_string_interpolation);
|
diag.span_label(self.lit, crate::fluent_generated::passes_maybe_string_interpolation);
|
||||||
diag.multipart_suggestion(
|
diag.multipart_suggestion(
|
||||||
|
@ -65,7 +65,7 @@ impl<'tcx> Subdiagnostic for Overlap<'tcx> {
|
|||||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
self,
|
self,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
_: F,
|
_: &F,
|
||||||
) {
|
) {
|
||||||
let Overlap { span, range } = self;
|
let Overlap { span, range } = self;
|
||||||
|
|
||||||
@ -113,7 +113,7 @@ impl<'tcx> Subdiagnostic for GappedRange<'tcx> {
|
|||||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
self,
|
self,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
_: F,
|
_: &F,
|
||||||
) {
|
) {
|
||||||
let GappedRange { span, gap, first_range } = self;
|
let GappedRange { span, gap, first_range } = self;
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use rustc_errors::{codes::*, Applicability, MultiSpan};
|
use rustc_errors::{codes::*, Applicability, ElidedLifetimeInPathSubdiag, MultiSpan};
|
||||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||||
use rustc_span::{
|
use rustc_span::{
|
||||||
symbol::{Ident, Symbol},
|
symbol::{Ident, Symbol},
|
||||||
@ -907,6 +907,8 @@ pub(crate) struct ExplicitAnonymousLivetimeReportError {
|
|||||||
pub(crate) struct ImplicitElidedLifetimeNotAllowedHere {
|
pub(crate) struct ImplicitElidedLifetimeNotAllowedHere {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub(crate) span: Span,
|
pub(crate) span: Span,
|
||||||
|
#[subdiagnostic]
|
||||||
|
pub(crate) subdiag: ElidedLifetimeInPathSubdiag,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
|
@ -1883,20 +1883,18 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
|||||||
// async fn foo(_: std::cell::Ref<u32>) { ... }
|
// async fn foo(_: std::cell::Ref<u32>) { ... }
|
||||||
LifetimeRibKind::AnonymousCreateParameter { report_in_path: true, .. }
|
LifetimeRibKind::AnonymousCreateParameter { report_in_path: true, .. }
|
||||||
| LifetimeRibKind::AnonymousWarn(_) => {
|
| LifetimeRibKind::AnonymousWarn(_) => {
|
||||||
let mut err =
|
|
||||||
self.r.dcx().create_err(errors::ImplicitElidedLifetimeNotAllowedHere {
|
|
||||||
span: path_span,
|
|
||||||
});
|
|
||||||
let sess = self.r.tcx.sess;
|
let sess = self.r.tcx.sess;
|
||||||
rustc_errors::add_elided_lifetime_in_path_suggestion(
|
let subdiag = rustc_errors::elided_lifetime_in_path_suggestion(
|
||||||
sess.source_map(),
|
sess.source_map(),
|
||||||
&mut err,
|
|
||||||
expected_lifetimes,
|
expected_lifetimes,
|
||||||
path_span,
|
path_span,
|
||||||
!segment.has_generic_args,
|
!segment.has_generic_args,
|
||||||
elided_lifetime_span,
|
elided_lifetime_span,
|
||||||
);
|
);
|
||||||
err.emit();
|
self.r.dcx().emit_err(errors::ImplicitElidedLifetimeNotAllowedHere {
|
||||||
|
span: path_span,
|
||||||
|
subdiag,
|
||||||
|
});
|
||||||
should_lint = false;
|
should_lint = false;
|
||||||
|
|
||||||
for id in node_ids {
|
for id in node_ids {
|
||||||
|
@ -2548,7 +2548,13 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
|
|||||||
|
|
||||||
let mut search_paths = vec![];
|
let mut search_paths = vec![];
|
||||||
for s in &matches.opt_strs("L") {
|
for s in &matches.opt_strs("L") {
|
||||||
search_paths.push(SearchPath::from_cli_opt(&sysroot, &target_triple, early_dcx, s));
|
search_paths.push(SearchPath::from_cli_opt(
|
||||||
|
&sysroot,
|
||||||
|
&target_triple,
|
||||||
|
early_dcx,
|
||||||
|
s,
|
||||||
|
unstable_opts.unstable_options,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let working_dir = std::env::current_dir().unwrap_or_else(|e| {
|
let working_dir = std::env::current_dir().unwrap_or_else(|e| {
|
||||||
|
@ -52,6 +52,7 @@ impl SearchPath {
|
|||||||
triple: &TargetTriple,
|
triple: &TargetTriple,
|
||||||
early_dcx: &EarlyDiagCtxt,
|
early_dcx: &EarlyDiagCtxt,
|
||||||
path: &str,
|
path: &str,
|
||||||
|
is_unstable_enabled: bool,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let (kind, path) = if let Some(stripped) = path.strip_prefix("native=") {
|
let (kind, path) = if let Some(stripped) = path.strip_prefix("native=") {
|
||||||
(PathKind::Native, stripped)
|
(PathKind::Native, stripped)
|
||||||
@ -68,6 +69,14 @@ impl SearchPath {
|
|||||||
};
|
};
|
||||||
let dir = match path.strip_prefix("@RUSTC_BUILTIN") {
|
let dir = match path.strip_prefix("@RUSTC_BUILTIN") {
|
||||||
Some(stripped) => {
|
Some(stripped) => {
|
||||||
|
if !is_unstable_enabled {
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||||
|
early_dcx.early_fatal(
|
||||||
|
"the `-Z unstable-options` flag must also be passed to \
|
||||||
|
enable the use of `@RUSTC_BUILTIN`",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
make_target_lib_path(sysroot, triple.triple()).join("builtin").join(stripped)
|
make_target_lib_path(sysroot, triple.triple()).join("builtin").join(stripped)
|
||||||
}
|
}
|
||||||
None => PathBuf::from(path),
|
None => PathBuf::from(path),
|
||||||
|
@ -229,7 +229,7 @@ impl<'tcx> Stable<'tcx> for mir::BorrowKind {
|
|||||||
use rustc_middle::mir::BorrowKind::*;
|
use rustc_middle::mir::BorrowKind::*;
|
||||||
match *self {
|
match *self {
|
||||||
Shared => stable_mir::mir::BorrowKind::Shared,
|
Shared => stable_mir::mir::BorrowKind::Shared,
|
||||||
Fake => stable_mir::mir::BorrowKind::Fake,
|
Fake(kind) => stable_mir::mir::BorrowKind::Fake(kind.stable(tables)),
|
||||||
Mut { kind } => stable_mir::mir::BorrowKind::Mut { kind: kind.stable(tables) },
|
Mut { kind } => stable_mir::mir::BorrowKind::Mut { kind: kind.stable(tables) },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -247,6 +247,17 @@ impl<'tcx> Stable<'tcx> for mir::MutBorrowKind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx> Stable<'tcx> for mir::FakeBorrowKind {
|
||||||
|
type T = stable_mir::mir::FakeBorrowKind;
|
||||||
|
fn stable(&self, _: &mut Tables<'_>) -> Self::T {
|
||||||
|
use rustc_middle::mir::FakeBorrowKind::*;
|
||||||
|
match *self {
|
||||||
|
Deep => stable_mir::mir::FakeBorrowKind::Deep,
|
||||||
|
Shallow => stable_mir::mir::FakeBorrowKind::Shallow,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx> Stable<'tcx> for mir::NullOp<'tcx> {
|
impl<'tcx> Stable<'tcx> for mir::NullOp<'tcx> {
|
||||||
type T = stable_mir::mir::NullOp;
|
type T = stable_mir::mir::NullOp;
|
||||||
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
|
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
|
||||||
|
@ -14,7 +14,7 @@ use rustc_data_structures::sync::{IntoDynSyncSend, MappedReadGuard, ReadGuard, R
|
|||||||
use rustc_data_structures::unhash::UnhashMap;
|
use rustc_data_structures::unhash::UnhashMap;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::{self, BorrowedBuf, Read};
|
use std::io::{self, BorrowedBuf, Read};
|
||||||
use std::path::{self};
|
use std::path;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
@ -104,7 +104,7 @@ impl Subdiagnostic for AdjustSignatureBorrow {
|
|||||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
self,
|
self,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
_f: F,
|
_f: &F,
|
||||||
) {
|
) {
|
||||||
match self {
|
match self {
|
||||||
AdjustSignatureBorrow::Borrow { to_borrow } => {
|
AdjustSignatureBorrow::Borrow { to_borrow } => {
|
||||||
|
@ -2938,17 +2938,28 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Didn't add an indirection suggestion, so add a general suggestion to relax `Sized`.
|
// Didn't add an indirection suggestion, so add a general suggestion to relax `Sized`.
|
||||||
let (span, separator) = if let Some(s) = generics.bounds_span_for_suggestions(param.def_id)
|
let (span, separator, open_paren_sp) =
|
||||||
{
|
if let Some((s, open_paren_sp)) = generics.bounds_span_for_suggestions(param.def_id) {
|
||||||
(s, " +")
|
(s, " +", open_paren_sp)
|
||||||
|
} else {
|
||||||
|
(param.name.ident().span.shrink_to_hi(), ":", None)
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut suggs = vec![];
|
||||||
|
let suggestion = format!("{separator} ?Sized");
|
||||||
|
|
||||||
|
if let Some(open_paren_sp) = open_paren_sp {
|
||||||
|
suggs.push((open_paren_sp, "(".to_string()));
|
||||||
|
suggs.push((span, format!("){suggestion}")));
|
||||||
} else {
|
} else {
|
||||||
(param.name.ident().span.shrink_to_hi(), ":")
|
suggs.push((span, suggestion));
|
||||||
};
|
}
|
||||||
err.span_suggestion_verbose(
|
|
||||||
span,
|
err.multipart_suggestion_verbose(
|
||||||
"consider relaxing the implicit `Sized` restriction",
|
"consider relaxing the implicit `Sized` restriction",
|
||||||
format!("{separator} ?Sized"),
|
suggs,
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -867,11 +867,9 @@ pub enum BorrowKind {
|
|||||||
/// Data must be immutable and is aliasable.
|
/// Data must be immutable and is aliasable.
|
||||||
Shared,
|
Shared,
|
||||||
|
|
||||||
/// The immediately borrowed place must be immutable, but projections from
|
/// An immutable, aliasable borrow that is discarded after borrow-checking. Can behave either
|
||||||
/// it don't need to be. This is used to prevent match guards from replacing
|
/// like a normal shared borrow or like a special shallow borrow (see [`FakeBorrowKind`]).
|
||||||
/// the scrutinee. For example, a fake borrow of `a.b` doesn't
|
Fake(FakeBorrowKind),
|
||||||
/// conflict with a mutable borrow of `a.b.c`.
|
|
||||||
Fake,
|
|
||||||
|
|
||||||
/// Data is mutable and not aliasable.
|
/// Data is mutable and not aliasable.
|
||||||
Mut {
|
Mut {
|
||||||
@ -886,7 +884,7 @@ impl BorrowKind {
|
|||||||
BorrowKind::Mut { .. } => Mutability::Mut,
|
BorrowKind::Mut { .. } => Mutability::Mut,
|
||||||
BorrowKind::Shared => Mutability::Not,
|
BorrowKind::Shared => Mutability::Not,
|
||||||
// FIXME: There's no type corresponding to a shallow borrow, so use `&` as an approximation.
|
// FIXME: There's no type corresponding to a shallow borrow, so use `&` as an approximation.
|
||||||
BorrowKind::Fake => Mutability::Not,
|
BorrowKind::Fake(_) => Mutability::Not,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -898,6 +896,17 @@ pub enum MutBorrowKind {
|
|||||||
ClosureCapture,
|
ClosureCapture,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub enum FakeBorrowKind {
|
||||||
|
/// A shared (deep) borrow. Data must be immutable and is aliasable.
|
||||||
|
Deep,
|
||||||
|
/// The immediately borrowed place must be immutable, but projections from
|
||||||
|
/// it don't need to be. This is used to prevent match guards from replacing
|
||||||
|
/// the scrutinee. For example, a fake borrow of `a.b` doesn't
|
||||||
|
/// conflict with a mutable borrow of `a.b.c`.
|
||||||
|
Shallow,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum Mutability {
|
pub enum Mutability {
|
||||||
Not,
|
Not,
|
||||||
|
@ -8,7 +8,7 @@ use std::{fmt, io, iter};
|
|||||||
|
|
||||||
use super::{AssertMessage, BinOp, TerminatorKind};
|
use super::{AssertMessage, BinOp, TerminatorKind};
|
||||||
|
|
||||||
use super::BorrowKind;
|
use super::{BorrowKind, FakeBorrowKind};
|
||||||
|
|
||||||
impl Display for Ty {
|
impl Display for Ty {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
@ -352,7 +352,8 @@ fn pretty_rvalue<W: Write>(writer: &mut W, rval: &Rvalue) -> io::Result<()> {
|
|||||||
Rvalue::Ref(_, borrowkind, place) => {
|
Rvalue::Ref(_, borrowkind, place) => {
|
||||||
let kind = match borrowkind {
|
let kind = match borrowkind {
|
||||||
BorrowKind::Shared => "&",
|
BorrowKind::Shared => "&",
|
||||||
BorrowKind::Fake => "&fake ",
|
BorrowKind::Fake(FakeBorrowKind::Deep) => "&fake ",
|
||||||
|
BorrowKind::Fake(FakeBorrowKind::Shallow) => "&fake shallow ",
|
||||||
BorrowKind::Mut { .. } => "&mut ",
|
BorrowKind::Mut { .. } => "&mut ",
|
||||||
};
|
};
|
||||||
write!(writer, "{kind}{:?}", place)
|
write!(writer, "{kind}{:?}", place)
|
||||||
|
@ -25,7 +25,9 @@ const fn size_align<T>() -> (usize, usize) {
|
|||||||
/// An instance of `Layout` describes a particular layout of memory.
|
/// An instance of `Layout` describes a particular layout of memory.
|
||||||
/// You build a `Layout` up as an input to give to an allocator.
|
/// You build a `Layout` up as an input to give to an allocator.
|
||||||
///
|
///
|
||||||
/// All layouts have an associated size and a power-of-two alignment.
|
/// All layouts have an associated size and a power-of-two alignment. The size, when rounded up to
|
||||||
|
/// the nearest multiple of `align`, does not overflow isize (i.e., the rounded value will always be
|
||||||
|
/// less than or equal to `isize::MAX`).
|
||||||
///
|
///
|
||||||
/// (Note that layouts are *not* required to have non-zero size,
|
/// (Note that layouts are *not* required to have non-zero size,
|
||||||
/// even though `GlobalAlloc` requires that all memory requests
|
/// even though `GlobalAlloc` requires that all memory requests
|
||||||
|
@ -635,7 +635,16 @@ impl Options {
|
|||||||
let libs = matches
|
let libs = matches
|
||||||
.opt_strs("L")
|
.opt_strs("L")
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| SearchPath::from_cli_opt(&sysroot, &target, early_dcx, s))
|
.map(|s| {
|
||||||
|
SearchPath::from_cli_opt(
|
||||||
|
&sysroot,
|
||||||
|
&target,
|
||||||
|
early_dcx,
|
||||||
|
s,
|
||||||
|
#[allow(rustc::bad_opt_access)] // we have no `Session` here
|
||||||
|
unstable_opts.unstable_options,
|
||||||
|
)
|
||||||
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let show_coverage = matches.opt_present("show-coverage");
|
let show_coverage = matches.opt_present("show-coverage");
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
//@ known-bug: #122552
|
|
||||||
//@ edition:2021
|
|
||||||
|
|
||||||
trait X {
|
|
||||||
fn line_stream<'a, Repr>() -> Self::LineStreamFut<{ async {} }, Repr>;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Y;
|
|
||||||
|
|
||||||
pub fn main() {}
|
|
@ -4,8 +4,8 @@ fn full_tested_match() -> () {
|
|||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
let mut _1: (i32, i32);
|
let mut _1: (i32, i32);
|
||||||
let mut _2: std::option::Option<i32>;
|
let mut _2: std::option::Option<i32>;
|
||||||
let mut _3: isize;
|
let mut _3: &std::option::Option<i32>;
|
||||||
let mut _4: &std::option::Option<i32>;
|
let mut _4: isize;
|
||||||
let _5: i32;
|
let _5: i32;
|
||||||
let _6: &i32;
|
let _6: &i32;
|
||||||
let mut _7: bool;
|
let mut _7: bool;
|
||||||
@ -27,8 +27,8 @@ fn full_tested_match() -> () {
|
|||||||
StorageLive(_2);
|
StorageLive(_2);
|
||||||
_2 = Option::<i32>::Some(const 42_i32);
|
_2 = Option::<i32>::Some(const 42_i32);
|
||||||
PlaceMention(_2);
|
PlaceMention(_2);
|
||||||
_3 = discriminant(_2);
|
_4 = discriminant(_2);
|
||||||
switchInt(move _3) -> [0: bb5, 1: bb2, otherwise: bb1];
|
switchInt(move _4) -> [0: bb5, 1: bb2, otherwise: bb1];
|
||||||
}
|
}
|
||||||
|
|
||||||
bb1: {
|
bb1: {
|
||||||
@ -60,7 +60,7 @@ fn full_tested_match() -> () {
|
|||||||
bb7: {
|
bb7: {
|
||||||
StorageLive(_6);
|
StorageLive(_6);
|
||||||
_6 = &((_2 as Some).0: i32);
|
_6 = &((_2 as Some).0: i32);
|
||||||
_4 = &fake _2;
|
_3 = &fake shallow _2;
|
||||||
StorageLive(_7);
|
StorageLive(_7);
|
||||||
_7 = guard() -> [return: bb8, unwind: bb16];
|
_7 = guard() -> [return: bb8, unwind: bb16];
|
||||||
}
|
}
|
||||||
@ -71,7 +71,7 @@ fn full_tested_match() -> () {
|
|||||||
|
|
||||||
bb9: {
|
bb9: {
|
||||||
StorageDead(_7);
|
StorageDead(_7);
|
||||||
FakeRead(ForMatchGuard, _4);
|
FakeRead(ForMatchGuard, _3);
|
||||||
FakeRead(ForGuardBinding, _6);
|
FakeRead(ForGuardBinding, _6);
|
||||||
StorageLive(_5);
|
StorageLive(_5);
|
||||||
_5 = ((_2 as Some).0: i32);
|
_5 = ((_2 as Some).0: i32);
|
||||||
|
@ -4,8 +4,8 @@ fn full_tested_match2() -> () {
|
|||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
let mut _1: (i32, i32);
|
let mut _1: (i32, i32);
|
||||||
let mut _2: std::option::Option<i32>;
|
let mut _2: std::option::Option<i32>;
|
||||||
let mut _3: isize;
|
let mut _3: &std::option::Option<i32>;
|
||||||
let mut _4: &std::option::Option<i32>;
|
let mut _4: isize;
|
||||||
let _5: i32;
|
let _5: i32;
|
||||||
let _6: &i32;
|
let _6: &i32;
|
||||||
let mut _7: bool;
|
let mut _7: bool;
|
||||||
@ -27,8 +27,8 @@ fn full_tested_match2() -> () {
|
|||||||
StorageLive(_2);
|
StorageLive(_2);
|
||||||
_2 = Option::<i32>::Some(const 42_i32);
|
_2 = Option::<i32>::Some(const 42_i32);
|
||||||
PlaceMention(_2);
|
PlaceMention(_2);
|
||||||
_3 = discriminant(_2);
|
_4 = discriminant(_2);
|
||||||
switchInt(move _3) -> [0: bb5, 1: bb2, otherwise: bb1];
|
switchInt(move _4) -> [0: bb5, 1: bb2, otherwise: bb1];
|
||||||
}
|
}
|
||||||
|
|
||||||
bb1: {
|
bb1: {
|
||||||
@ -66,7 +66,7 @@ fn full_tested_match2() -> () {
|
|||||||
bb7: {
|
bb7: {
|
||||||
StorageLive(_6);
|
StorageLive(_6);
|
||||||
_6 = &((_2 as Some).0: i32);
|
_6 = &((_2 as Some).0: i32);
|
||||||
_4 = &fake _2;
|
_3 = &fake shallow _2;
|
||||||
StorageLive(_7);
|
StorageLive(_7);
|
||||||
_7 = guard() -> [return: bb8, unwind: bb16];
|
_7 = guard() -> [return: bb8, unwind: bb16];
|
||||||
}
|
}
|
||||||
@ -77,7 +77,7 @@ fn full_tested_match2() -> () {
|
|||||||
|
|
||||||
bb9: {
|
bb9: {
|
||||||
StorageDead(_7);
|
StorageDead(_7);
|
||||||
FakeRead(ForMatchGuard, _4);
|
FakeRead(ForMatchGuard, _3);
|
||||||
FakeRead(ForGuardBinding, _6);
|
FakeRead(ForGuardBinding, _6);
|
||||||
StorageLive(_5);
|
StorageLive(_5);
|
||||||
_5 = ((_2 as Some).0: i32);
|
_5 = ((_2 as Some).0: i32);
|
||||||
|
@ -4,9 +4,9 @@ fn main() -> () {
|
|||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
let mut _1: i32;
|
let mut _1: i32;
|
||||||
let mut _2: std::option::Option<i32>;
|
let mut _2: std::option::Option<i32>;
|
||||||
let mut _3: isize;
|
let mut _3: &std::option::Option<i32>;
|
||||||
let mut _4: isize;
|
let mut _4: isize;
|
||||||
let mut _5: &std::option::Option<i32>;
|
let mut _5: isize;
|
||||||
let _6: i32;
|
let _6: i32;
|
||||||
let _7: &i32;
|
let _7: &i32;
|
||||||
let mut _8: bool;
|
let mut _8: bool;
|
||||||
@ -38,8 +38,8 @@ fn main() -> () {
|
|||||||
StorageLive(_2);
|
StorageLive(_2);
|
||||||
_2 = Option::<i32>::Some(const 1_i32);
|
_2 = Option::<i32>::Some(const 1_i32);
|
||||||
PlaceMention(_2);
|
PlaceMention(_2);
|
||||||
_4 = discriminant(_2);
|
_5 = discriminant(_2);
|
||||||
switchInt(move _4) -> [1: bb8, otherwise: bb2];
|
switchInt(move _5) -> [1: bb8, otherwise: bb2];
|
||||||
}
|
}
|
||||||
|
|
||||||
bb1: {
|
bb1: {
|
||||||
@ -52,8 +52,8 @@ fn main() -> () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bb3: {
|
bb3: {
|
||||||
_3 = discriminant(_2);
|
_4 = discriminant(_2);
|
||||||
switchInt(move _3) -> [1: bb6, otherwise: bb4];
|
switchInt(move _4) -> [1: bb6, otherwise: bb4];
|
||||||
}
|
}
|
||||||
|
|
||||||
bb4: {
|
bb4: {
|
||||||
@ -87,7 +87,7 @@ fn main() -> () {
|
|||||||
bb10: {
|
bb10: {
|
||||||
StorageLive(_7);
|
StorageLive(_7);
|
||||||
_7 = &((_2 as Some).0: i32);
|
_7 = &((_2 as Some).0: i32);
|
||||||
_5 = &fake _2;
|
_3 = &fake shallow _2;
|
||||||
StorageLive(_8);
|
StorageLive(_8);
|
||||||
_8 = guard() -> [return: bb11, unwind: bb24];
|
_8 = guard() -> [return: bb11, unwind: bb24];
|
||||||
}
|
}
|
||||||
@ -98,7 +98,7 @@ fn main() -> () {
|
|||||||
|
|
||||||
bb12: {
|
bb12: {
|
||||||
StorageDead(_8);
|
StorageDead(_8);
|
||||||
FakeRead(ForMatchGuard, _5);
|
FakeRead(ForMatchGuard, _3);
|
||||||
FakeRead(ForGuardBinding, _7);
|
FakeRead(ForGuardBinding, _7);
|
||||||
StorageLive(_6);
|
StorageLive(_6);
|
||||||
_6 = ((_2 as Some).0: i32);
|
_6 = ((_2 as Some).0: i32);
|
||||||
@ -129,7 +129,7 @@ fn main() -> () {
|
|||||||
bb16: {
|
bb16: {
|
||||||
StorageLive(_11);
|
StorageLive(_11);
|
||||||
_11 = &((_2 as Some).0: i32);
|
_11 = &((_2 as Some).0: i32);
|
||||||
_5 = &fake _2;
|
_3 = &fake shallow _2;
|
||||||
StorageLive(_12);
|
StorageLive(_12);
|
||||||
StorageLive(_13);
|
StorageLive(_13);
|
||||||
_13 = (*_11);
|
_13 = (*_11);
|
||||||
@ -143,7 +143,7 @@ fn main() -> () {
|
|||||||
bb18: {
|
bb18: {
|
||||||
StorageDead(_13);
|
StorageDead(_13);
|
||||||
StorageDead(_12);
|
StorageDead(_12);
|
||||||
FakeRead(ForMatchGuard, _5);
|
FakeRead(ForMatchGuard, _3);
|
||||||
FakeRead(ForGuardBinding, _11);
|
FakeRead(ForGuardBinding, _11);
|
||||||
StorageLive(_10);
|
StorageLive(_10);
|
||||||
_10 = ((_2 as Some).0: i32);
|
_10 = ((_2 as Some).0: i32);
|
||||||
|
@ -7,10 +7,10 @@ fn constant_eq(_1: &str, _2: bool) -> u32 {
|
|||||||
let mut _3: (&str, bool);
|
let mut _3: (&str, bool);
|
||||||
let mut _4: &str;
|
let mut _4: &str;
|
||||||
let mut _5: bool;
|
let mut _5: bool;
|
||||||
let mut _6: bool;
|
let mut _6: &&str;
|
||||||
let mut _7: bool;
|
let mut _7: &bool;
|
||||||
let mut _8: &&str;
|
let mut _8: bool;
|
||||||
let mut _9: &bool;
|
let mut _9: bool;
|
||||||
let mut _10: bool;
|
let mut _10: bool;
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
@ -23,7 +23,7 @@ fn constant_eq(_1: &str, _2: bool) -> u32 {
|
|||||||
StorageDead(_5);
|
StorageDead(_5);
|
||||||
StorageDead(_4);
|
StorageDead(_4);
|
||||||
PlaceMention(_3);
|
PlaceMention(_3);
|
||||||
_7 = <str as PartialEq>::eq((_3.0: &str), const "a") -> [return: bb11, unwind: bb19];
|
_9 = <str as PartialEq>::eq((_3.0: &str), const "a") -> [return: bb11, unwind: bb19];
|
||||||
}
|
}
|
||||||
|
|
||||||
bb1: {
|
bb1: {
|
||||||
@ -52,7 +52,7 @@ fn constant_eq(_1: &str, _2: bool) -> u32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bb7: {
|
bb7: {
|
||||||
_6 = <str as PartialEq>::eq((_3.0: &str), const "b") -> [return: bb10, unwind: bb19];
|
_8 = <str as PartialEq>::eq((_3.0: &str), const "b") -> [return: bb10, unwind: bb19];
|
||||||
}
|
}
|
||||||
|
|
||||||
bb8: {
|
bb8: {
|
||||||
@ -64,16 +64,16 @@ fn constant_eq(_1: &str, _2: bool) -> u32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bb10: {
|
bb10: {
|
||||||
switchInt(move _6) -> [0: bb1, otherwise: bb8];
|
switchInt(move _8) -> [0: bb1, otherwise: bb8];
|
||||||
}
|
}
|
||||||
|
|
||||||
bb11: {
|
bb11: {
|
||||||
switchInt(move _7) -> [0: bb7, otherwise: bb4];
|
switchInt(move _9) -> [0: bb7, otherwise: bb4];
|
||||||
}
|
}
|
||||||
|
|
||||||
bb12: {
|
bb12: {
|
||||||
_8 = &fake (_3.0: &str);
|
_6 = &fake shallow (_3.0: &str);
|
||||||
_9 = &fake (_3.1: bool);
|
_7 = &fake shallow (_3.1: bool);
|
||||||
StorageLive(_10);
|
StorageLive(_10);
|
||||||
_10 = const true;
|
_10 = const true;
|
||||||
switchInt(move _10) -> [0: bb14, otherwise: bb13];
|
switchInt(move _10) -> [0: bb14, otherwise: bb13];
|
||||||
@ -81,8 +81,8 @@ fn constant_eq(_1: &str, _2: bool) -> u32 {
|
|||||||
|
|
||||||
bb13: {
|
bb13: {
|
||||||
StorageDead(_10);
|
StorageDead(_10);
|
||||||
FakeRead(ForMatchGuard, _8);
|
FakeRead(ForMatchGuard, _6);
|
||||||
FakeRead(ForMatchGuard, _9);
|
FakeRead(ForMatchGuard, _7);
|
||||||
_0 = const 1_u32;
|
_0 = const 1_u32;
|
||||||
goto -> bb18;
|
goto -> bb18;
|
||||||
}
|
}
|
||||||
|
@ -4,17 +4,17 @@ fn disjoint_ranges(_1: i32, _2: bool) -> u32 {
|
|||||||
debug x => _1;
|
debug x => _1;
|
||||||
debug b => _2;
|
debug b => _2;
|
||||||
let mut _0: u32;
|
let mut _0: u32;
|
||||||
let mut _3: bool;
|
let mut _3: &i32;
|
||||||
let mut _4: bool;
|
let mut _4: bool;
|
||||||
let mut _5: bool;
|
let mut _5: bool;
|
||||||
let mut _6: bool;
|
let mut _6: bool;
|
||||||
let mut _7: &i32;
|
let mut _7: bool;
|
||||||
let mut _8: bool;
|
let mut _8: bool;
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
PlaceMention(_1);
|
PlaceMention(_1);
|
||||||
_5 = Le(const 0_i32, _1);
|
_6 = Le(const 0_i32, _1);
|
||||||
switchInt(move _5) -> [0: bb3, otherwise: bb8];
|
switchInt(move _6) -> [0: bb3, otherwise: bb8];
|
||||||
}
|
}
|
||||||
|
|
||||||
bb1: {
|
bb1: {
|
||||||
@ -27,8 +27,8 @@ fn disjoint_ranges(_1: i32, _2: bool) -> u32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bb3: {
|
bb3: {
|
||||||
_3 = Le(const 10_i32, _1);
|
_4 = Le(const 10_i32, _1);
|
||||||
switchInt(move _3) -> [0: bb5, otherwise: bb7];
|
switchInt(move _4) -> [0: bb5, otherwise: bb7];
|
||||||
}
|
}
|
||||||
|
|
||||||
bb4: {
|
bb4: {
|
||||||
@ -44,17 +44,17 @@ fn disjoint_ranges(_1: i32, _2: bool) -> u32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bb7: {
|
bb7: {
|
||||||
_4 = Le(_1, const 20_i32);
|
_5 = Le(_1, const 20_i32);
|
||||||
switchInt(move _4) -> [0: bb5, otherwise: bb4];
|
switchInt(move _5) -> [0: bb5, otherwise: bb4];
|
||||||
}
|
}
|
||||||
|
|
||||||
bb8: {
|
bb8: {
|
||||||
_6 = Lt(_1, const 10_i32);
|
_7 = Lt(_1, const 10_i32);
|
||||||
switchInt(move _6) -> [0: bb3, otherwise: bb2];
|
switchInt(move _7) -> [0: bb3, otherwise: bb2];
|
||||||
}
|
}
|
||||||
|
|
||||||
bb9: {
|
bb9: {
|
||||||
_7 = &fake _1;
|
_3 = &fake shallow _1;
|
||||||
StorageLive(_8);
|
StorageLive(_8);
|
||||||
_8 = _2;
|
_8 = _2;
|
||||||
switchInt(move _8) -> [0: bb11, otherwise: bb10];
|
switchInt(move _8) -> [0: bb11, otherwise: bb10];
|
||||||
@ -62,7 +62,7 @@ fn disjoint_ranges(_1: i32, _2: bool) -> u32 {
|
|||||||
|
|
||||||
bb10: {
|
bb10: {
|
||||||
StorageDead(_8);
|
StorageDead(_8);
|
||||||
FakeRead(ForMatchGuard, _7);
|
FakeRead(ForMatchGuard, _3);
|
||||||
_0 = const 0_u32;
|
_0 = const 0_u32;
|
||||||
goto -> bb14;
|
goto -> bb14;
|
||||||
}
|
}
|
||||||
|
@ -80,8 +80,8 @@
|
|||||||
_6 = &(_2.1: bool);
|
_6 = &(_2.1: bool);
|
||||||
StorageLive(_8);
|
StorageLive(_8);
|
||||||
_8 = &(_2.2: std::string::String);
|
_8 = &(_2.2: std::string::String);
|
||||||
- _3 = &fake (_2.0: bool);
|
- _3 = &fake shallow (_2.0: bool);
|
||||||
- _4 = &fake (_2.1: bool);
|
- _4 = &fake shallow (_2.1: bool);
|
||||||
StorageLive(_9);
|
StorageLive(_9);
|
||||||
StorageLive(_10);
|
StorageLive(_10);
|
||||||
_10 = _1;
|
_10 = _1;
|
||||||
@ -137,8 +137,8 @@
|
|||||||
_6 = &(_2.0: bool);
|
_6 = &(_2.0: bool);
|
||||||
StorageLive(_8);
|
StorageLive(_8);
|
||||||
_8 = &(_2.2: std::string::String);
|
_8 = &(_2.2: std::string::String);
|
||||||
- _3 = &fake (_2.0: bool);
|
- _3 = &fake shallow (_2.0: bool);
|
||||||
- _4 = &fake (_2.1: bool);
|
- _4 = &fake shallow (_2.1: bool);
|
||||||
StorageLive(_12);
|
StorageLive(_12);
|
||||||
StorageLive(_13);
|
StorageLive(_13);
|
||||||
_13 = _1;
|
_13 = _1;
|
||||||
|
@ -80,8 +80,8 @@
|
|||||||
_6 = &(_2.1: bool);
|
_6 = &(_2.1: bool);
|
||||||
StorageLive(_8);
|
StorageLive(_8);
|
||||||
_8 = &(_2.2: std::string::String);
|
_8 = &(_2.2: std::string::String);
|
||||||
- _3 = &fake (_2.0: bool);
|
- _3 = &fake shallow (_2.0: bool);
|
||||||
- _4 = &fake (_2.1: bool);
|
- _4 = &fake shallow (_2.1: bool);
|
||||||
StorageLive(_9);
|
StorageLive(_9);
|
||||||
StorageLive(_10);
|
StorageLive(_10);
|
||||||
_10 = _1;
|
_10 = _1;
|
||||||
@ -137,8 +137,8 @@
|
|||||||
_6 = &(_2.0: bool);
|
_6 = &(_2.0: bool);
|
||||||
StorageLive(_8);
|
StorageLive(_8);
|
||||||
_8 = &(_2.2: std::string::String);
|
_8 = &(_2.2: std::string::String);
|
||||||
- _3 = &fake (_2.0: bool);
|
- _3 = &fake shallow (_2.0: bool);
|
||||||
- _4 = &fake (_2.1: bool);
|
- _4 = &fake shallow (_2.1: bool);
|
||||||
StorageLive(_12);
|
StorageLive(_12);
|
||||||
StorageLive(_13);
|
StorageLive(_13);
|
||||||
_13 = _1;
|
_13 = _1;
|
||||||
|
@ -5,17 +5,17 @@
|
|||||||
debug x => _1;
|
debug x => _1;
|
||||||
debug c => _2;
|
debug c => _2;
|
||||||
let mut _0: i32;
|
let mut _0: i32;
|
||||||
let mut _3: isize;
|
let mut _3: &std::option::Option<&&i32>;
|
||||||
let mut _4: &std::option::Option<&&i32>;
|
let mut _4: &i32;
|
||||||
let mut _5: &&i32;
|
let mut _5: &&i32;
|
||||||
let mut _6: &&&i32;
|
let mut _6: &&&i32;
|
||||||
let mut _7: &i32;
|
let mut _7: isize;
|
||||||
let mut _8: bool;
|
let mut _8: bool;
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
PlaceMention(_1);
|
PlaceMention(_1);
|
||||||
_3 = discriminant(_1);
|
_7 = discriminant(_1);
|
||||||
switchInt(move _3) -> [1: bb2, otherwise: bb1];
|
switchInt(move _7) -> [1: bb2, otherwise: bb1];
|
||||||
}
|
}
|
||||||
|
|
||||||
bb1: {
|
bb1: {
|
||||||
@ -33,10 +33,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
bb4: {
|
bb4: {
|
||||||
- _4 = &fake _1;
|
- _3 = &fake shallow _1;
|
||||||
- _5 = &fake (*((_1 as Some).0: &&i32));
|
- _4 = &fake shallow (*(*((_1 as Some).0: &&i32)));
|
||||||
- _6 = &fake ((_1 as Some).0: &&i32);
|
- _5 = &fake shallow (*((_1 as Some).0: &&i32));
|
||||||
- _7 = &fake (*(*((_1 as Some).0: &&i32)));
|
- _6 = &fake shallow ((_1 as Some).0: &&i32);
|
||||||
+ nop;
|
+ nop;
|
||||||
+ nop;
|
+ nop;
|
||||||
+ nop;
|
+ nop;
|
||||||
@ -48,10 +48,10 @@
|
|||||||
|
|
||||||
bb5: {
|
bb5: {
|
||||||
StorageDead(_8);
|
StorageDead(_8);
|
||||||
|
- FakeRead(ForMatchGuard, _3);
|
||||||
- FakeRead(ForMatchGuard, _4);
|
- FakeRead(ForMatchGuard, _4);
|
||||||
- FakeRead(ForMatchGuard, _5);
|
- FakeRead(ForMatchGuard, _5);
|
||||||
- FakeRead(ForMatchGuard, _6);
|
- FakeRead(ForMatchGuard, _6);
|
||||||
- FakeRead(ForMatchGuard, _7);
|
|
||||||
+ nop;
|
+ nop;
|
||||||
+ nop;
|
+ nop;
|
||||||
+ nop;
|
+ nop;
|
||||||
|
@ -5,17 +5,17 @@
|
|||||||
debug x => _1;
|
debug x => _1;
|
||||||
debug c => _2;
|
debug c => _2;
|
||||||
let mut _0: i32;
|
let mut _0: i32;
|
||||||
let mut _3: isize;
|
let mut _3: &std::option::Option<&&i32>;
|
||||||
let mut _4: &std::option::Option<&&i32>;
|
let mut _4: &i32;
|
||||||
let mut _5: &&i32;
|
let mut _5: &&i32;
|
||||||
let mut _6: &&&i32;
|
let mut _6: &&&i32;
|
||||||
let mut _7: &i32;
|
let mut _7: isize;
|
||||||
let mut _8: bool;
|
let mut _8: bool;
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
PlaceMention(_1);
|
PlaceMention(_1);
|
||||||
_3 = discriminant(_1);
|
_7 = discriminant(_1);
|
||||||
switchInt(move _3) -> [1: bb2, otherwise: bb1];
|
switchInt(move _7) -> [1: bb2, otherwise: bb1];
|
||||||
}
|
}
|
||||||
|
|
||||||
bb1: {
|
bb1: {
|
||||||
@ -33,10 +33,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
bb4: {
|
bb4: {
|
||||||
- _4 = &fake _1;
|
- _3 = &fake shallow _1;
|
||||||
- _5 = &fake (*((_1 as Some).0: &&i32));
|
- _4 = &fake shallow (*(*((_1 as Some).0: &&i32)));
|
||||||
- _6 = &fake ((_1 as Some).0: &&i32);
|
- _5 = &fake shallow (*((_1 as Some).0: &&i32));
|
||||||
- _7 = &fake (*(*((_1 as Some).0: &&i32)));
|
- _6 = &fake shallow ((_1 as Some).0: &&i32);
|
||||||
+ nop;
|
+ nop;
|
||||||
+ nop;
|
+ nop;
|
||||||
+ nop;
|
+ nop;
|
||||||
@ -48,10 +48,10 @@
|
|||||||
|
|
||||||
bb5: {
|
bb5: {
|
||||||
StorageDead(_8);
|
StorageDead(_8);
|
||||||
|
- FakeRead(ForMatchGuard, _3);
|
||||||
- FakeRead(ForMatchGuard, _4);
|
- FakeRead(ForMatchGuard, _4);
|
||||||
- FakeRead(ForMatchGuard, _5);
|
- FakeRead(ForMatchGuard, _5);
|
||||||
- FakeRead(ForMatchGuard, _6);
|
- FakeRead(ForMatchGuard, _6);
|
||||||
- FakeRead(ForMatchGuard, _7);
|
|
||||||
+ nop;
|
+ nop;
|
||||||
+ nop;
|
+ nop;
|
||||||
+ nop;
|
+ nop;
|
||||||
|
@ -3,6 +3,11 @@ error[E0229]: associated type bindings are not allowed here
|
|||||||
|
|
|
|
||||||
LL | type A: S<C<X = 0i32> = 34>;
|
LL | type A: S<C<X = 0i32> = 34>;
|
||||||
| ^^^^^^^^ associated type not allowed here
|
| ^^^^^^^^ associated type not allowed here
|
||||||
|
|
|
||||||
|
help: consider removing this type binding
|
||||||
|
|
|
||||||
|
LL | type A: S<C<X = 0i32> = 34>;
|
||||||
|
| ~~~~~~~~~~
|
||||||
|
|
||||||
error[E0229]: associated type bindings are not allowed here
|
error[E0229]: associated type bindings are not allowed here
|
||||||
--> $DIR/invalid_associated_const.rs:4:17
|
--> $DIR/invalid_associated_const.rs:4:17
|
||||||
@ -11,6 +16,10 @@ LL | type A: S<C<X = 0i32> = 34>;
|
|||||||
| ^^^^^^^^ associated type not allowed here
|
| ^^^^^^^^ associated type not allowed here
|
||||||
|
|
|
|
||||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
help: consider removing this type binding
|
||||||
|
|
|
||||||
|
LL | type A: S<C<X = 0i32> = 34>;
|
||||||
|
| ~~~~~~~~~~
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
@ -3,6 +3,11 @@ error[E0229]: associated type bindings are not allowed here
|
|||||||
|
|
|
|
||||||
LL | type A: S<C<X = 0i32> = 34>;
|
LL | type A: S<C<X = 0i32> = 34>;
|
||||||
| ^^^^^^^^ associated type not allowed here
|
| ^^^^^^^^ associated type not allowed here
|
||||||
|
|
|
||||||
|
help: consider removing this type binding
|
||||||
|
|
|
||||||
|
LL | type A: S<C<X = 0i32> = 34>;
|
||||||
|
| ~~~~~~~~~~
|
||||||
|
|
||||||
error[E0229]: associated type bindings are not allowed here
|
error[E0229]: associated type bindings are not allowed here
|
||||||
--> $DIR/issue-102467.rs:7:17
|
--> $DIR/issue-102467.rs:7:17
|
||||||
@ -11,6 +16,10 @@ LL | type A: S<C<X = 0i32> = 34>;
|
|||||||
| ^^^^^^^^ associated type not allowed here
|
| ^^^^^^^^ associated type not allowed here
|
||||||
|
|
|
|
||||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
help: consider removing this type binding
|
||||||
|
|
|
||||||
|
LL | type A: S<C<X = 0i32> = 34>;
|
||||||
|
| ~~~~~~~~~~
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ impl Subdiagnostic for UntranslatableInAddtoDiag {
|
|||||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
self,
|
self,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
f: F,
|
f: &F,
|
||||||
) {
|
) {
|
||||||
diag.note("untranslatable diagnostic");
|
diag.note("untranslatable diagnostic");
|
||||||
//~^ ERROR diagnostics should be created using translatable messages
|
//~^ ERROR diagnostics should be created using translatable messages
|
||||||
@ -72,7 +72,7 @@ impl Subdiagnostic for TranslatableInAddtoDiag {
|
|||||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
self,
|
self,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
f: F,
|
f: &F,
|
||||||
) {
|
) {
|
||||||
diag.note(crate::fluent_generated::no_crate_note);
|
diag.note(crate::fluent_generated::no_crate_note);
|
||||||
}
|
}
|
||||||
|
@ -827,3 +827,13 @@ struct PrimarySpanOnVec {
|
|||||||
//~| NOTE there must be exactly one primary span
|
//~| NOTE there must be exactly one primary span
|
||||||
sub: Vec<Span>,
|
sub: Vec<Span>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
struct NestedParent {
|
||||||
|
#[subdiagnostic]
|
||||||
|
single_sub: A,
|
||||||
|
#[subdiagnostic]
|
||||||
|
option_sub: Option<A>,
|
||||||
|
#[subdiagnostic]
|
||||||
|
vec_sub: Vec<A>,
|
||||||
|
}
|
||||||
|
@ -3,6 +3,11 @@ error[E0229]: associated type bindings are not allowed here
|
|||||||
|
|
|
|
||||||
LL | type A: S<C<X = 0i32> = 34>;
|
LL | type A: S<C<X = 0i32> = 34>;
|
||||||
| ^^^^^^^^ associated type not allowed here
|
| ^^^^^^^^ associated type not allowed here
|
||||||
|
|
|
||||||
|
help: consider removing this type binding
|
||||||
|
|
|
||||||
|
LL | type A: S<C<X = 0i32> = 34>;
|
||||||
|
| ~~~~~~~~~~
|
||||||
|
|
||||||
error[E0229]: associated type bindings are not allowed here
|
error[E0229]: associated type bindings are not allowed here
|
||||||
--> $DIR/issue-102335-const.rs:4:17
|
--> $DIR/issue-102335-const.rs:4:17
|
||||||
@ -11,6 +16,10 @@ LL | type A: S<C<X = 0i32> = 34>;
|
|||||||
| ^^^^^^^^ associated type not allowed here
|
| ^^^^^^^^ associated type not allowed here
|
||||||
|
|
|
|
||||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
help: consider removing this type binding
|
||||||
|
|
|
||||||
|
LL | type A: S<C<X = 0i32> = 34>;
|
||||||
|
| ~~~~~~~~~~
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
trait T {
|
trait T {
|
||||||
type A: S<C<i32 = u32> = ()>;
|
type A: S<C<i32 = u32> = ()>; // Just one erroneous equality constraint
|
||||||
|
//~^ ERROR associated type bindings are not allowed here
|
||||||
|
//~| ERROR associated type bindings are not allowed here
|
||||||
|
}
|
||||||
|
|
||||||
|
trait T2 {
|
||||||
|
type A: S<C<i32 = u32, X = i32> = ()>; // More than one erroneous equality constraints
|
||||||
//~^ ERROR associated type bindings are not allowed here
|
//~^ ERROR associated type bindings are not allowed here
|
||||||
//~| ERROR associated type bindings are not allowed here
|
//~| ERROR associated type bindings are not allowed here
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,49 @@
|
|||||||
error[E0229]: associated type bindings are not allowed here
|
error[E0229]: associated type bindings are not allowed here
|
||||||
--> $DIR/issue-102335-ty.rs:2:17
|
--> $DIR/issue-102335-ty.rs:2:17
|
||||||
|
|
|
|
||||||
LL | type A: S<C<i32 = u32> = ()>;
|
LL | type A: S<C<i32 = u32> = ()>; // Just one erroneous equality constraint
|
||||||
| ^^^^^^^^^ associated type not allowed here
|
| ^^^^^^^^^ associated type not allowed here
|
||||||
|
|
|
||||||
|
help: consider removing this type binding
|
||||||
|
|
|
||||||
|
LL | type A: S<C<i32 = u32> = ()>; // Just one erroneous equality constraint
|
||||||
|
| ~~~~~~~~~~~
|
||||||
|
|
||||||
error[E0229]: associated type bindings are not allowed here
|
error[E0229]: associated type bindings are not allowed here
|
||||||
--> $DIR/issue-102335-ty.rs:2:17
|
--> $DIR/issue-102335-ty.rs:2:17
|
||||||
|
|
|
|
||||||
LL | type A: S<C<i32 = u32> = ()>;
|
LL | type A: S<C<i32 = u32> = ()>; // Just one erroneous equality constraint
|
||||||
| ^^^^^^^^^ associated type not allowed here
|
| ^^^^^^^^^ associated type not allowed here
|
||||||
|
|
|
|
||||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
help: consider removing this type binding
|
||||||
|
|
|
||||||
|
LL | type A: S<C<i32 = u32> = ()>; // Just one erroneous equality constraint
|
||||||
|
| ~~~~~~~~~~~
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error[E0229]: associated type bindings are not allowed here
|
||||||
|
--> $DIR/issue-102335-ty.rs:8:17
|
||||||
|
|
|
||||||
|
LL | type A: S<C<i32 = u32, X = i32> = ()>; // More than one erroneous equality constraints
|
||||||
|
| ^^^^^^^^^ associated type not allowed here
|
||||||
|
|
|
||||||
|
help: consider removing this type binding
|
||||||
|
|
|
||||||
|
LL | type A: S<C<i32 = u32, X = i32> = ()>; // More than one erroneous equality constraints
|
||||||
|
| ~~~~~~~~~~
|
||||||
|
|
||||||
|
error[E0229]: associated type bindings are not allowed here
|
||||||
|
--> $DIR/issue-102335-ty.rs:8:17
|
||||||
|
|
|
||||||
|
LL | type A: S<C<i32 = u32, X = i32> = ()>; // More than one erroneous equality constraints
|
||||||
|
| ^^^^^^^^^ associated type not allowed here
|
||||||
|
|
|
||||||
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
help: consider removing this type binding
|
||||||
|
|
|
||||||
|
LL | type A: S<C<i32 = u32, X = i32> = ()>; // More than one erroneous equality constraints
|
||||||
|
| ~~~~~~~~~~
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0229`.
|
For more information about this error, try `rustc --explain E0229`.
|
||||||
|
@ -1,19 +1,125 @@
|
|||||||
// Test equality constraints on associated types. Check we get an error when an
|
// Test equality constraints on associated types. Check we get an error when an
|
||||||
// equality constraint is used in a qualified path.
|
// equality constraint is used in an invalid context
|
||||||
|
|
||||||
pub trait Foo {
|
|
||||||
type A;
|
|
||||||
fn boo(&self) -> <Self as Foo>::A;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Bar;
|
struct Bar;
|
||||||
|
struct Qux;
|
||||||
|
|
||||||
impl Foo for isize {
|
// Tests for a a non generic trait
|
||||||
|
pub trait Tr1 {
|
||||||
|
type A;
|
||||||
|
fn boo(&self) -> <Self as Tr1>::A;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Tr1 for isize {
|
||||||
type A = usize;
|
type A = usize;
|
||||||
fn boo(&self) -> usize { 42 }
|
fn boo(&self) -> usize { 42 }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn baz<I: Foo>(x: &<I as Foo<A=Bar>>::A) {}
|
// Test for when the assoc type is
|
||||||
|
// specified as an equality constraint
|
||||||
|
impl Tr1<A = usize> for usize {
|
||||||
|
//~^ ERROR associated type bindings are not allowed here
|
||||||
|
//~| ERROR not all trait items implemented, missing: `A`
|
||||||
|
fn boo(&self) -> usize { 42 }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for a wronngly used equality constraint in a func arg
|
||||||
|
fn baz<I: Tr1>(_x: &<I as Tr1<A=Bar>>::A) {}
|
||||||
//~^ ERROR associated type bindings are not allowed here
|
//~^ ERROR associated type bindings are not allowed here
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Tests for a generic trait
|
||||||
|
trait Tr2<T1, T2, T3> {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for when wrongly specifed equality constraint's ident
|
||||||
|
// matches some generic param's ident
|
||||||
|
// (Note: E0229 is emitted only for the first erroneous equality
|
||||||
|
// constraint (T2) not for any subequent ones (e.g. T3))
|
||||||
|
impl Tr2<i32, T2 = Qux, T3 = usize> for Bar {
|
||||||
|
//~^ ERROR associated type bindings are not allowed here
|
||||||
|
//~| ERROR trait takes 3 generic arguments but 1 generic argument was supplied
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for when equality constraint's ident matches a
|
||||||
|
// generic param's ident but has different case
|
||||||
|
impl Tr2<i32, t2 = Qux, T3 = usize> for Qux {
|
||||||
|
//~^ ERROR associated type bindings are not allowed here
|
||||||
|
//~| ERROR trait takes 3 generic arguments but 1 generic argument was supplied
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for when equality constraint's ident
|
||||||
|
// matches none of the generic param idents
|
||||||
|
impl Tr2<i32, X = Qux, Y = usize> for Bar {
|
||||||
|
//~^ ERROR associated type bindings are not allowed here
|
||||||
|
//~| ERROR trait takes 3 generic arguments but 1 generic argument was supplied
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for when the term in equality constraint is itself generic
|
||||||
|
struct GenericTerm<T> { _t: T }
|
||||||
|
impl Tr2<i32, Qux, T3 = GenericTerm<i32>> for Bar {
|
||||||
|
//~^ ERROR associated type bindings are not allowed here
|
||||||
|
//~| ERROR trait takes 3 generic arguments but 2 generic arguments were supplied
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Tests for a trait with a const param
|
||||||
|
trait Tr3<const N: i32, T2, T3> {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for when equality constraint's ident
|
||||||
|
// matches the const param's ident
|
||||||
|
// (Deliberately spread over multiple lines to test that
|
||||||
|
// our suggestion spans are kosher in the face of such formatting)
|
||||||
|
impl Tr3<N
|
||||||
|
//~^ ERROR associated type bindings are not allowed here
|
||||||
|
//~| ERROR associated const equality is incomplete
|
||||||
|
//~| ERROR trait takes 3 generic arguments but 0 generic arguments were supplied
|
||||||
|
= 42, T2 = Qux, T3 = usize> for Bar {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for when equality constraint's ident
|
||||||
|
// matches the const param's ident but has a different case
|
||||||
|
impl Tr3<n = 42, T2 = Qux, T3 = usize> for Qux {
|
||||||
|
//~^ ERROR associated type bindings are not allowed here
|
||||||
|
//~| ERROR associated const equality is incomplete
|
||||||
|
//~| ERROR trait takes 3 generic arguments but 0 generic arguments were supplied
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for when equality constraint's ident
|
||||||
|
// matches the const param ident but the constraint is a type arg
|
||||||
|
impl Tr3<N = u32, T2 = Qux, T3 = usize> for Bar {
|
||||||
|
//~^ ERROR associated type bindings are not allowed here
|
||||||
|
//~| ERROR trait takes 3 generic arguments but 0 generic arguments were supplied
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for when equality constraint's ident
|
||||||
|
// matches a type param ident but the constraint is a const arg
|
||||||
|
impl Tr3<42, T2 = 42, T3 = usize> for Bar {
|
||||||
|
//~^ ERROR associated type bindings are not allowed here
|
||||||
|
//~| ERROR associated const equality is incomplete
|
||||||
|
//~| ERROR trait takes 3 generic arguments but 1 generic argument was supplied
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for when equality constraint's ident
|
||||||
|
// matches none of the param idents
|
||||||
|
impl Tr3<X = 42, Y = Qux, Z = usize> for Bar {
|
||||||
|
//~^ ERROR associated type bindings are not allowed here
|
||||||
|
//~| ERROR associated const equality is incomplete
|
||||||
|
//~| ERROR trait takes 3 generic arguments but 0 generic arguments were supplied
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Test for the case when lifetimes are present
|
||||||
|
struct St<'a, T> { v: &'a T }
|
||||||
|
|
||||||
|
impl<'a, T> St<'a , T = Qux> {
|
||||||
|
//~^ ERROR associated type bindings are not allowed here
|
||||||
|
//~| ERROR struct takes 1 generic argument but 0 generic arguments were supplied
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn main() {}
|
pub fn main() {}
|
||||||
|
@ -1,9 +1,365 @@
|
|||||||
error[E0229]: associated type bindings are not allowed here
|
error[E0658]: associated const equality is incomplete
|
||||||
--> $DIR/associated-types-eq-2.rs:16:30
|
--> $DIR/associated-types-eq-2.rs:76:10
|
||||||
|
|
|
|
||||||
LL | fn baz<I: Foo>(x: &<I as Foo<A=Bar>>::A) {}
|
LL | impl Tr3<N
|
||||||
| ^^^^^ associated type not allowed here
|
| __________^
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
LL | | = 42, T2 = Qux, T3 = usize> for Bar {
|
||||||
|
| |____^
|
||||||
|
|
|
||||||
|
= note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
|
||||||
|
= help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
|
||||||
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error[E0658]: associated const equality is incomplete
|
||||||
|
--> $DIR/associated-types-eq-2.rs:85:10
|
||||||
|
|
|
||||||
|
LL | impl Tr3<n = 42, T2 = Qux, T3 = usize> for Qux {
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
|
||||||
|
= help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
|
||||||
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0229`.
|
error[E0658]: associated const equality is incomplete
|
||||||
|
--> $DIR/associated-types-eq-2.rs:100:14
|
||||||
|
|
|
||||||
|
LL | impl Tr3<42, T2 = 42, T3 = usize> for Bar {
|
||||||
|
| ^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
|
||||||
|
= help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
|
||||||
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
|
|
||||||
|
error[E0658]: associated const equality is incomplete
|
||||||
|
--> $DIR/associated-types-eq-2.rs:108:10
|
||||||
|
|
|
||||||
|
LL | impl Tr3<X = 42, Y = Qux, Z = usize> for Bar {
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
|
||||||
|
= help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
|
||||||
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
|
|
||||||
|
error[E0229]: associated type bindings are not allowed here
|
||||||
|
--> $DIR/associated-types-eq-2.rs:20:10
|
||||||
|
|
|
||||||
|
LL | impl Tr1<A = usize> for usize {
|
||||||
|
| ^^^^^^^^^ associated type not allowed here
|
||||||
|
|
|
||||||
|
help: consider removing this type binding
|
||||||
|
|
|
||||||
|
LL | impl Tr1<A = usize> for usize {
|
||||||
|
| ~~~~~~~~~~~
|
||||||
|
|
||||||
|
error[E0046]: not all trait items implemented, missing: `A`
|
||||||
|
--> $DIR/associated-types-eq-2.rs:20:1
|
||||||
|
|
|
||||||
|
LL | type A;
|
||||||
|
| ------ `A` from trait
|
||||||
|
...
|
||||||
|
LL | impl Tr1<A = usize> for usize {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `A` in implementation
|
||||||
|
|
||||||
|
error[E0229]: associated type bindings are not allowed here
|
||||||
|
--> $DIR/associated-types-eq-2.rs:27:31
|
||||||
|
|
|
||||||
|
LL | fn baz<I: Tr1>(_x: &<I as Tr1<A=Bar>>::A) {}
|
||||||
|
| ^^^^^ associated type not allowed here
|
||||||
|
|
|
||||||
|
help: consider removing this type binding
|
||||||
|
|
|
||||||
|
LL | fn baz<I: Tr1>(_x: &<I as Tr1<A=Bar>>::A) {}
|
||||||
|
| ~~~~~~~
|
||||||
|
|
||||||
|
error[E0107]: trait takes 3 generic arguments but 1 generic argument was supplied
|
||||||
|
--> $DIR/associated-types-eq-2.rs:40:6
|
||||||
|
|
|
||||||
|
LL | impl Tr2<i32, T2 = Qux, T3 = usize> for Bar {
|
||||||
|
| ^^^ --- supplied 1 generic argument
|
||||||
|
| |
|
||||||
|
| expected 3 generic arguments
|
||||||
|
|
|
||||||
|
note: trait defined here, with 3 generic parameters: `T1`, `T2`, `T3`
|
||||||
|
--> $DIR/associated-types-eq-2.rs:33:7
|
||||||
|
|
|
||||||
|
LL | trait Tr2<T1, T2, T3> {
|
||||||
|
| ^^^ -- -- --
|
||||||
|
help: add missing generic arguments
|
||||||
|
|
|
||||||
|
LL | impl Tr2<i32, T2, T3, T2 = Qux, T3 = usize> for Bar {
|
||||||
|
| ++++++++
|
||||||
|
|
||||||
|
error[E0229]: associated type bindings are not allowed here
|
||||||
|
--> $DIR/associated-types-eq-2.rs:40:15
|
||||||
|
|
|
||||||
|
LL | impl Tr2<i32, T2 = Qux, T3 = usize> for Bar {
|
||||||
|
| ^^^^^^^^ associated type not allowed here
|
||||||
|
|
|
||||||
|
help: to use `Qux` as a generic argument specify it directly
|
||||||
|
|
|
||||||
|
LL | impl Tr2<i32, Qux, T3 = usize> for Bar {
|
||||||
|
| ~~~
|
||||||
|
|
||||||
|
error[E0107]: trait takes 3 generic arguments but 1 generic argument was supplied
|
||||||
|
--> $DIR/associated-types-eq-2.rs:47:6
|
||||||
|
|
|
||||||
|
LL | impl Tr2<i32, t2 = Qux, T3 = usize> for Qux {
|
||||||
|
| ^^^ --- supplied 1 generic argument
|
||||||
|
| |
|
||||||
|
| expected 3 generic arguments
|
||||||
|
|
|
||||||
|
note: trait defined here, with 3 generic parameters: `T1`, `T2`, `T3`
|
||||||
|
--> $DIR/associated-types-eq-2.rs:33:7
|
||||||
|
|
|
||||||
|
LL | trait Tr2<T1, T2, T3> {
|
||||||
|
| ^^^ -- -- --
|
||||||
|
help: add missing generic arguments
|
||||||
|
|
|
||||||
|
LL | impl Tr2<i32, T2, T3, t2 = Qux, T3 = usize> for Qux {
|
||||||
|
| ++++++++
|
||||||
|
|
||||||
|
error[E0229]: associated type bindings are not allowed here
|
||||||
|
--> $DIR/associated-types-eq-2.rs:47:15
|
||||||
|
|
|
||||||
|
LL | impl Tr2<i32, t2 = Qux, T3 = usize> for Qux {
|
||||||
|
| ^^^^^^^^ associated type not allowed here
|
||||||
|
|
|
||||||
|
help: consider removing this type binding
|
||||||
|
|
|
||||||
|
LL | impl Tr2<i32, t2 = Qux, T3 = usize> for Qux {
|
||||||
|
| ~~~~~~~~~~
|
||||||
|
|
||||||
|
error[E0107]: trait takes 3 generic arguments but 1 generic argument was supplied
|
||||||
|
--> $DIR/associated-types-eq-2.rs:54:6
|
||||||
|
|
|
||||||
|
LL | impl Tr2<i32, X = Qux, Y = usize> for Bar {
|
||||||
|
| ^^^ --- supplied 1 generic argument
|
||||||
|
| |
|
||||||
|
| expected 3 generic arguments
|
||||||
|
|
|
||||||
|
note: trait defined here, with 3 generic parameters: `T1`, `T2`, `T3`
|
||||||
|
--> $DIR/associated-types-eq-2.rs:33:7
|
||||||
|
|
|
||||||
|
LL | trait Tr2<T1, T2, T3> {
|
||||||
|
| ^^^ -- -- --
|
||||||
|
help: add missing generic arguments
|
||||||
|
|
|
||||||
|
LL | impl Tr2<i32, T2, T3, X = Qux, Y = usize> for Bar {
|
||||||
|
| ++++++++
|
||||||
|
|
||||||
|
error[E0229]: associated type bindings are not allowed here
|
||||||
|
--> $DIR/associated-types-eq-2.rs:54:15
|
||||||
|
|
|
||||||
|
LL | impl Tr2<i32, X = Qux, Y = usize> for Bar {
|
||||||
|
| ^^^^^^^ associated type not allowed here
|
||||||
|
|
|
||||||
|
help: consider removing this type binding
|
||||||
|
|
|
||||||
|
LL | impl Tr2<i32, X = Qux, Y = usize> for Bar {
|
||||||
|
| ~~~~~~~~~
|
||||||
|
|
||||||
|
error[E0107]: trait takes 3 generic arguments but 2 generic arguments were supplied
|
||||||
|
--> $DIR/associated-types-eq-2.rs:61:6
|
||||||
|
|
|
||||||
|
LL | impl Tr2<i32, Qux, T3 = GenericTerm<i32>> for Bar {
|
||||||
|
| ^^^ --- --- supplied 2 generic arguments
|
||||||
|
| |
|
||||||
|
| expected 3 generic arguments
|
||||||
|
|
|
||||||
|
note: trait defined here, with 3 generic parameters: `T1`, `T2`, `T3`
|
||||||
|
--> $DIR/associated-types-eq-2.rs:33:7
|
||||||
|
|
|
||||||
|
LL | trait Tr2<T1, T2, T3> {
|
||||||
|
| ^^^ -- -- --
|
||||||
|
help: add missing generic argument
|
||||||
|
|
|
||||||
|
LL | impl Tr2<i32, Qux, T3, T3 = GenericTerm<i32>> for Bar {
|
||||||
|
| ++++
|
||||||
|
|
||||||
|
error[E0229]: associated type bindings are not allowed here
|
||||||
|
--> $DIR/associated-types-eq-2.rs:61:20
|
||||||
|
|
|
||||||
|
LL | impl Tr2<i32, Qux, T3 = GenericTerm<i32>> for Bar {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^ associated type not allowed here
|
||||||
|
|
|
||||||
|
help: to use `GenericTerm<i32>` as a generic argument specify it directly
|
||||||
|
|
|
||||||
|
LL | impl Tr2<i32, Qux, GenericTerm<i32>> for Bar {
|
||||||
|
| ~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
error[E0107]: trait takes 3 generic arguments but 0 generic arguments were supplied
|
||||||
|
--> $DIR/associated-types-eq-2.rs:76:6
|
||||||
|
|
|
||||||
|
LL | impl Tr3<N
|
||||||
|
| ^^^ expected 3 generic arguments
|
||||||
|
|
|
||||||
|
note: trait defined here, with 3 generic parameters: `N`, `T2`, `T3`
|
||||||
|
--> $DIR/associated-types-eq-2.rs:69:7
|
||||||
|
|
|
||||||
|
LL | trait Tr3<const N: i32, T2, T3> {
|
||||||
|
| ^^^ ------------ -- --
|
||||||
|
help: add missing generic arguments
|
||||||
|
|
|
||||||
|
LL | impl Tr3<N, T2, T3, N
|
||||||
|
| ++++++++++
|
||||||
|
|
||||||
|
error[E0229]: associated type bindings are not allowed here
|
||||||
|
--> $DIR/associated-types-eq-2.rs:76:10
|
||||||
|
|
|
||||||
|
LL | impl Tr3<N
|
||||||
|
| __________^
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
LL | | = 42, T2 = Qux, T3 = usize> for Bar {
|
||||||
|
| |____^ associated type not allowed here
|
||||||
|
|
|
||||||
|
help: to use `42` as a generic argument specify it directly
|
||||||
|
|
|
||||||
|
LL | impl Tr3<42, T2 = Qux, T3 = usize> for Bar {
|
||||||
|
| ~~
|
||||||
|
|
||||||
|
error[E0107]: trait takes 3 generic arguments but 0 generic arguments were supplied
|
||||||
|
--> $DIR/associated-types-eq-2.rs:85:6
|
||||||
|
|
|
||||||
|
LL | impl Tr3<n = 42, T2 = Qux, T3 = usize> for Qux {
|
||||||
|
| ^^^ expected 3 generic arguments
|
||||||
|
|
|
||||||
|
note: trait defined here, with 3 generic parameters: `N`, `T2`, `T3`
|
||||||
|
--> $DIR/associated-types-eq-2.rs:69:7
|
||||||
|
|
|
||||||
|
LL | trait Tr3<const N: i32, T2, T3> {
|
||||||
|
| ^^^ ------------ -- --
|
||||||
|
help: add missing generic arguments
|
||||||
|
|
|
||||||
|
LL | impl Tr3<N, T2, T3, n = 42, T2 = Qux, T3 = usize> for Qux {
|
||||||
|
| ++++++++++
|
||||||
|
|
||||||
|
error[E0229]: associated type bindings are not allowed here
|
||||||
|
--> $DIR/associated-types-eq-2.rs:85:10
|
||||||
|
|
|
||||||
|
LL | impl Tr3<n = 42, T2 = Qux, T3 = usize> for Qux {
|
||||||
|
| ^^^^^^ associated type not allowed here
|
||||||
|
|
|
||||||
|
help: consider removing this type binding
|
||||||
|
|
|
||||||
|
LL | impl Tr3<n = 42, T2 = Qux, T3 = usize> for Qux {
|
||||||
|
| ~~~~~~~
|
||||||
|
|
||||||
|
error[E0107]: trait takes 3 generic arguments but 0 generic arguments were supplied
|
||||||
|
--> $DIR/associated-types-eq-2.rs:93:6
|
||||||
|
|
|
||||||
|
LL | impl Tr3<N = u32, T2 = Qux, T3 = usize> for Bar {
|
||||||
|
| ^^^ expected 3 generic arguments
|
||||||
|
|
|
||||||
|
note: trait defined here, with 3 generic parameters: `N`, `T2`, `T3`
|
||||||
|
--> $DIR/associated-types-eq-2.rs:69:7
|
||||||
|
|
|
||||||
|
LL | trait Tr3<const N: i32, T2, T3> {
|
||||||
|
| ^^^ ------------ -- --
|
||||||
|
help: add missing generic arguments
|
||||||
|
|
|
||||||
|
LL | impl Tr3<N, T2, T3, N = u32, T2 = Qux, T3 = usize> for Bar {
|
||||||
|
| ++++++++++
|
||||||
|
|
||||||
|
error[E0229]: associated type bindings are not allowed here
|
||||||
|
--> $DIR/associated-types-eq-2.rs:93:10
|
||||||
|
|
|
||||||
|
LL | impl Tr3<N = u32, T2 = Qux, T3 = usize> for Bar {
|
||||||
|
| ^^^^^^^ associated type not allowed here
|
||||||
|
|
|
||||||
|
help: consider removing this type binding
|
||||||
|
|
|
||||||
|
LL | impl Tr3<N = u32, T2 = Qux, T3 = usize> for Bar {
|
||||||
|
| ~~~~~~~~
|
||||||
|
|
||||||
|
error[E0107]: trait takes 3 generic arguments but 1 generic argument was supplied
|
||||||
|
--> $DIR/associated-types-eq-2.rs:100:6
|
||||||
|
|
|
||||||
|
LL | impl Tr3<42, T2 = 42, T3 = usize> for Bar {
|
||||||
|
| ^^^ -- supplied 1 generic argument
|
||||||
|
| |
|
||||||
|
| expected 3 generic arguments
|
||||||
|
|
|
||||||
|
note: trait defined here, with 3 generic parameters: `N`, `T2`, `T3`
|
||||||
|
--> $DIR/associated-types-eq-2.rs:69:7
|
||||||
|
|
|
||||||
|
LL | trait Tr3<const N: i32, T2, T3> {
|
||||||
|
| ^^^ ------------ -- --
|
||||||
|
help: add missing generic arguments
|
||||||
|
|
|
||||||
|
LL | impl Tr3<42, T2, T3, T2 = 42, T3 = usize> for Bar {
|
||||||
|
| ++++++++
|
||||||
|
|
||||||
|
error[E0229]: associated type bindings are not allowed here
|
||||||
|
--> $DIR/associated-types-eq-2.rs:100:14
|
||||||
|
|
|
||||||
|
LL | impl Tr3<42, T2 = 42, T3 = usize> for Bar {
|
||||||
|
| ^^^^^^^ associated type not allowed here
|
||||||
|
|
|
||||||
|
help: consider removing this type binding
|
||||||
|
|
|
||||||
|
LL | impl Tr3<42, T2 = 42, T3 = usize> for Bar {
|
||||||
|
| ~~~~~~~~~
|
||||||
|
|
||||||
|
error[E0107]: trait takes 3 generic arguments but 0 generic arguments were supplied
|
||||||
|
--> $DIR/associated-types-eq-2.rs:108:6
|
||||||
|
|
|
||||||
|
LL | impl Tr3<X = 42, Y = Qux, Z = usize> for Bar {
|
||||||
|
| ^^^ expected 3 generic arguments
|
||||||
|
|
|
||||||
|
note: trait defined here, with 3 generic parameters: `N`, `T2`, `T3`
|
||||||
|
--> $DIR/associated-types-eq-2.rs:69:7
|
||||||
|
|
|
||||||
|
LL | trait Tr3<const N: i32, T2, T3> {
|
||||||
|
| ^^^ ------------ -- --
|
||||||
|
help: add missing generic arguments
|
||||||
|
|
|
||||||
|
LL | impl Tr3<N, T2, T3, X = 42, Y = Qux, Z = usize> for Bar {
|
||||||
|
| ++++++++++
|
||||||
|
|
||||||
|
error[E0229]: associated type bindings are not allowed here
|
||||||
|
--> $DIR/associated-types-eq-2.rs:108:10
|
||||||
|
|
|
||||||
|
LL | impl Tr3<X = 42, Y = Qux, Z = usize> for Bar {
|
||||||
|
| ^^^^^^ associated type not allowed here
|
||||||
|
|
|
||||||
|
help: consider removing this type binding
|
||||||
|
|
|
||||||
|
LL | impl Tr3<X = 42, Y = Qux, Z = usize> for Bar {
|
||||||
|
| ~~~~~~~
|
||||||
|
|
||||||
|
error[E0107]: struct takes 1 generic argument but 0 generic arguments were supplied
|
||||||
|
--> $DIR/associated-types-eq-2.rs:119:13
|
||||||
|
|
|
||||||
|
LL | impl<'a, T> St<'a , T = Qux> {
|
||||||
|
| ^^ expected 1 generic argument
|
||||||
|
|
|
||||||
|
note: struct defined here, with 1 generic parameter: `T`
|
||||||
|
--> $DIR/associated-types-eq-2.rs:117:8
|
||||||
|
|
|
||||||
|
LL | struct St<'a, T> { v: &'a T }
|
||||||
|
| ^^ -
|
||||||
|
help: add missing generic argument
|
||||||
|
|
|
||||||
|
LL | impl<'a, T> St<'a, T , T = Qux> {
|
||||||
|
| +++
|
||||||
|
|
||||||
|
error[E0229]: associated type bindings are not allowed here
|
||||||
|
--> $DIR/associated-types-eq-2.rs:119:21
|
||||||
|
|
|
||||||
|
LL | impl<'a, T> St<'a , T = Qux> {
|
||||||
|
| ^^^^^^^ associated type not allowed here
|
||||||
|
|
|
||||||
|
help: to use `Qux` as a generic argument specify it directly
|
||||||
|
|
|
||||||
|
LL | impl<'a, T> St<'a , Qux> {
|
||||||
|
| ~~~
|
||||||
|
|
||||||
|
error: aborting due to 27 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0046, E0107, E0229, E0658.
|
||||||
|
For more information about an error, try `rustc --explain E0046`.
|
||||||
|
@ -29,6 +29,11 @@ error[E0229]: associated type bindings are not allowed here
|
|||||||
|
|
|
|
||||||
LL | impl Foo<N = 3> for Bar {
|
LL | impl Foo<N = 3> for Bar {
|
||||||
| ^^^^^ associated type not allowed here
|
| ^^^^^ associated type not allowed here
|
||||||
|
|
|
||||||
|
help: to use `3` as a generic argument specify it directly
|
||||||
|
|
|
||||||
|
LL | impl Foo<3> for Bar {
|
||||||
|
| ~
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
@ -41,6 +41,11 @@ error[E0229]: associated type bindings are not allowed here
|
|||||||
|
|
|
|
||||||
LL | impl Foo<N = const 3> for Bar {
|
LL | impl Foo<N = const 3> for Bar {
|
||||||
| ^^^^^^^^^^^ associated type not allowed here
|
| ^^^^^^^^^^^ associated type not allowed here
|
||||||
|
|
|
||||||
|
help: to use `3` as a generic argument specify it directly
|
||||||
|
|
|
||||||
|
LL | impl Foo<3> for Bar {
|
||||||
|
| ~
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
|
@ -6,18 +6,18 @@
|
|||||||
|
|
||||||
struct NonClone;
|
struct NonClone;
|
||||||
|
|
||||||
fn main() {
|
fn test1() {
|
||||||
let copyable: u32 = 123;
|
let copyable: u32 = 123;
|
||||||
let clonable_0: Vec<u32> = Vec::new();
|
|
||||||
let clonable_1: Vec<u32> = Vec::new();
|
|
||||||
let non_clonable: NonClone = NonClone;
|
|
||||||
|
|
||||||
let gen_copy_0 = move || {
|
let gen_copy_0 = move || {
|
||||||
yield;
|
yield;
|
||||||
drop(copyable);
|
drop(copyable);
|
||||||
};
|
};
|
||||||
check_copy(&gen_copy_0);
|
check_copy(&gen_copy_0);
|
||||||
check_clone(&gen_copy_0);
|
check_clone(&gen_copy_0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test2() {
|
||||||
|
let copyable: u32 = 123;
|
||||||
let gen_copy_1 = move || {
|
let gen_copy_1 = move || {
|
||||||
/*
|
/*
|
||||||
let v = vec!['a'];
|
let v = vec!['a'];
|
||||||
@ -33,6 +33,10 @@ fn main() {
|
|||||||
};
|
};
|
||||||
check_copy(&gen_copy_1);
|
check_copy(&gen_copy_1);
|
||||||
check_clone(&gen_copy_1);
|
check_clone(&gen_copy_1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test3() {
|
||||||
|
let clonable_0: Vec<u32> = Vec::new();
|
||||||
let gen_clone_0 = move || {
|
let gen_clone_0 = move || {
|
||||||
let v = vec!['a'];
|
let v = vec!['a'];
|
||||||
yield;
|
yield;
|
||||||
@ -43,6 +47,10 @@ fn main() {
|
|||||||
//~^ ERROR the trait bound `Vec<u32>: Copy` is not satisfied
|
//~^ ERROR the trait bound `Vec<u32>: Copy` is not satisfied
|
||||||
//~| ERROR the trait bound `Vec<char>: Copy` is not satisfied
|
//~| ERROR the trait bound `Vec<char>: Copy` is not satisfied
|
||||||
check_clone(&gen_clone_0);
|
check_clone(&gen_clone_0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test4() {
|
||||||
|
let clonable_1: Vec<u32> = Vec::new();
|
||||||
let gen_clone_1 = move || {
|
let gen_clone_1 = move || {
|
||||||
let v = vec!['a'];
|
let v = vec!['a'];
|
||||||
/*
|
/*
|
||||||
@ -59,6 +67,10 @@ fn main() {
|
|||||||
//~^ ERROR the trait bound `Vec<u32>: Copy` is not satisfied
|
//~^ ERROR the trait bound `Vec<u32>: Copy` is not satisfied
|
||||||
//~| ERROR the trait bound `Vec<char>: Copy` is not satisfied
|
//~| ERROR the trait bound `Vec<char>: Copy` is not satisfied
|
||||||
check_clone(&gen_clone_1);
|
check_clone(&gen_clone_1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test5() {
|
||||||
|
let non_clonable: NonClone = NonClone;
|
||||||
let gen_non_clone = move || {
|
let gen_non_clone = move || {
|
||||||
yield;
|
yield;
|
||||||
drop(non_clonable);
|
drop(non_clonable);
|
||||||
@ -71,3 +83,5 @@ fn main() {
|
|||||||
|
|
||||||
fn check_copy<T: Copy>(_x: &T) {}
|
fn check_copy<T: Copy>(_x: &T) {}
|
||||||
fn check_clone<T: Clone>(_x: &T) {}
|
fn check_clone<T: Clone>(_x: &T) {}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
|
@ -1,104 +1,104 @@
|
|||||||
error[E0277]: the trait bound `Vec<u32>: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:36:23: 36:30}`
|
error[E0277]: the trait bound `Vec<u32>: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:40:23: 40:30}`
|
||||||
--> $DIR/clone-impl.rs:42:5
|
--> $DIR/clone-impl.rs:46:5
|
||||||
|
|
|
|
||||||
LL | let gen_clone_0 = move || {
|
LL | let gen_clone_0 = move || {
|
||||||
| ------- within this `{coroutine@$DIR/clone-impl.rs:36:23: 36:30}`
|
| ------- within this `{coroutine@$DIR/clone-impl.rs:40:23: 40:30}`
|
||||||
...
|
...
|
||||||
LL | check_copy(&gen_clone_0);
|
LL | check_copy(&gen_clone_0);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:36:23: 36:30}`, the trait `Copy` is not implemented for `Vec<u32>`, which is required by `{coroutine@$DIR/clone-impl.rs:36:23: 36:30}: Copy`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:40:23: 40:30}`, the trait `Copy` is not implemented for `Vec<u32>`, which is required by `{coroutine@$DIR/clone-impl.rs:40:23: 40:30}: Copy`
|
||||||
|
|
|
|
||||||
note: captured value does not implement `Copy`
|
note: captured value does not implement `Copy`
|
||||||
--> $DIR/clone-impl.rs:40:14
|
--> $DIR/clone-impl.rs:44:14
|
||||||
|
|
|
|
||||||
LL | drop(clonable_0);
|
LL | drop(clonable_0);
|
||||||
| ^^^^^^^^^^ has type `Vec<u32>` which does not implement `Copy`
|
| ^^^^^^^^^^ has type `Vec<u32>` which does not implement `Copy`
|
||||||
note: required by a bound in `check_copy`
|
note: required by a bound in `check_copy`
|
||||||
--> $DIR/clone-impl.rs:72:18
|
--> $DIR/clone-impl.rs:84:18
|
||||||
|
|
|
|
||||||
LL | fn check_copy<T: Copy>(_x: &T) {}
|
LL | fn check_copy<T: Copy>(_x: &T) {}
|
||||||
| ^^^^ required by this bound in `check_copy`
|
| ^^^^ required by this bound in `check_copy`
|
||||||
|
|
||||||
error[E0277]: the trait bound `Vec<char>: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:36:23: 36:30}`
|
error[E0277]: the trait bound `Vec<char>: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:40:23: 40:30}`
|
||||||
--> $DIR/clone-impl.rs:42:5
|
--> $DIR/clone-impl.rs:46:5
|
||||||
|
|
|
|
||||||
LL | let gen_clone_0 = move || {
|
LL | let gen_clone_0 = move || {
|
||||||
| ------- within this `{coroutine@$DIR/clone-impl.rs:36:23: 36:30}`
|
| ------- within this `{coroutine@$DIR/clone-impl.rs:40:23: 40:30}`
|
||||||
...
|
...
|
||||||
LL | check_copy(&gen_clone_0);
|
LL | check_copy(&gen_clone_0);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:36:23: 36:30}`, the trait `Copy` is not implemented for `Vec<char>`, which is required by `{coroutine@$DIR/clone-impl.rs:36:23: 36:30}: Copy`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:40:23: 40:30}`, the trait `Copy` is not implemented for `Vec<char>`, which is required by `{coroutine@$DIR/clone-impl.rs:40:23: 40:30}: Copy`
|
||||||
|
|
|
|
||||||
note: coroutine does not implement `Copy` as this value is used across a yield
|
note: coroutine does not implement `Copy` as this value is used across a yield
|
||||||
--> $DIR/clone-impl.rs:38:9
|
--> $DIR/clone-impl.rs:42:9
|
||||||
|
|
|
|
||||||
LL | let v = vec!['a'];
|
LL | let v = vec!['a'];
|
||||||
| - has type `Vec<char>` which does not implement `Copy`
|
| - has type `Vec<char>` which does not implement `Copy`
|
||||||
LL | yield;
|
LL | yield;
|
||||||
| ^^^^^ yield occurs here, with `v` maybe used later
|
| ^^^^^ yield occurs here, with `v` maybe used later
|
||||||
note: required by a bound in `check_copy`
|
note: required by a bound in `check_copy`
|
||||||
--> $DIR/clone-impl.rs:72:18
|
--> $DIR/clone-impl.rs:84:18
|
||||||
|
|
|
|
||||||
LL | fn check_copy<T: Copy>(_x: &T) {}
|
LL | fn check_copy<T: Copy>(_x: &T) {}
|
||||||
| ^^^^ required by this bound in `check_copy`
|
| ^^^^ required by this bound in `check_copy`
|
||||||
|
|
||||||
error[E0277]: the trait bound `Vec<u32>: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:46:23: 46:30}`
|
error[E0277]: the trait bound `Vec<u32>: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:54:23: 54:30}`
|
||||||
--> $DIR/clone-impl.rs:58:5
|
|
||||||
|
|
|
||||||
LL | let gen_clone_1 = move || {
|
|
||||||
| ------- within this `{coroutine@$DIR/clone-impl.rs:46:23: 46:30}`
|
|
||||||
...
|
|
||||||
LL | check_copy(&gen_clone_1);
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:46:23: 46:30}`, the trait `Copy` is not implemented for `Vec<u32>`, which is required by `{coroutine@$DIR/clone-impl.rs:46:23: 46:30}: Copy`
|
|
||||||
|
|
|
||||||
note: captured value does not implement `Copy`
|
|
||||||
--> $DIR/clone-impl.rs:56:14
|
|
||||||
|
|
|
||||||
LL | drop(clonable_1);
|
|
||||||
| ^^^^^^^^^^ has type `Vec<u32>` which does not implement `Copy`
|
|
||||||
note: required by a bound in `check_copy`
|
|
||||||
--> $DIR/clone-impl.rs:72:18
|
|
||||||
|
|
|
||||||
LL | fn check_copy<T: Copy>(_x: &T) {}
|
|
||||||
| ^^^^ required by this bound in `check_copy`
|
|
||||||
|
|
||||||
error[E0277]: the trait bound `Vec<char>: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:46:23: 46:30}`
|
|
||||||
--> $DIR/clone-impl.rs:58:5
|
|
||||||
|
|
|
||||||
LL | let gen_clone_1 = move || {
|
|
||||||
| ------- within this `{coroutine@$DIR/clone-impl.rs:46:23: 46:30}`
|
|
||||||
...
|
|
||||||
LL | check_copy(&gen_clone_1);
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:46:23: 46:30}`, the trait `Copy` is not implemented for `Vec<char>`, which is required by `{coroutine@$DIR/clone-impl.rs:46:23: 46:30}: Copy`
|
|
||||||
|
|
|
||||||
note: coroutine does not implement `Copy` as this value is used across a yield
|
|
||||||
--> $DIR/clone-impl.rs:52:9
|
|
||||||
|
|
|
||||||
LL | let v = vec!['a'];
|
|
||||||
| - has type `Vec<char>` which does not implement `Copy`
|
|
||||||
...
|
|
||||||
LL | yield;
|
|
||||||
| ^^^^^ yield occurs here, with `v` maybe used later
|
|
||||||
note: required by a bound in `check_copy`
|
|
||||||
--> $DIR/clone-impl.rs:72:18
|
|
||||||
|
|
|
||||||
LL | fn check_copy<T: Copy>(_x: &T) {}
|
|
||||||
| ^^^^ required by this bound in `check_copy`
|
|
||||||
|
|
||||||
error[E0277]: the trait bound `NonClone: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:62:25: 62:32}`
|
|
||||||
--> $DIR/clone-impl.rs:66:5
|
--> $DIR/clone-impl.rs:66:5
|
||||||
|
|
|
|
||||||
LL | let gen_non_clone = move || {
|
LL | let gen_clone_1 = move || {
|
||||||
| ------- within this `{coroutine@$DIR/clone-impl.rs:62:25: 62:32}`
|
| ------- within this `{coroutine@$DIR/clone-impl.rs:54:23: 54:30}`
|
||||||
...
|
...
|
||||||
LL | check_copy(&gen_non_clone);
|
LL | check_copy(&gen_clone_1);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:62:25: 62:32}`, the trait `Copy` is not implemented for `NonClone`, which is required by `{coroutine@$DIR/clone-impl.rs:62:25: 62:32}: Copy`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:54:23: 54:30}`, the trait `Copy` is not implemented for `Vec<u32>`, which is required by `{coroutine@$DIR/clone-impl.rs:54:23: 54:30}: Copy`
|
||||||
|
|
|
|
||||||
note: captured value does not implement `Copy`
|
note: captured value does not implement `Copy`
|
||||||
--> $DIR/clone-impl.rs:64:14
|
--> $DIR/clone-impl.rs:64:14
|
||||||
|
|
|
|
||||||
|
LL | drop(clonable_1);
|
||||||
|
| ^^^^^^^^^^ has type `Vec<u32>` which does not implement `Copy`
|
||||||
|
note: required by a bound in `check_copy`
|
||||||
|
--> $DIR/clone-impl.rs:84:18
|
||||||
|
|
|
||||||
|
LL | fn check_copy<T: Copy>(_x: &T) {}
|
||||||
|
| ^^^^ required by this bound in `check_copy`
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `Vec<char>: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:54:23: 54:30}`
|
||||||
|
--> $DIR/clone-impl.rs:66:5
|
||||||
|
|
|
||||||
|
LL | let gen_clone_1 = move || {
|
||||||
|
| ------- within this `{coroutine@$DIR/clone-impl.rs:54:23: 54:30}`
|
||||||
|
...
|
||||||
|
LL | check_copy(&gen_clone_1);
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:54:23: 54:30}`, the trait `Copy` is not implemented for `Vec<char>`, which is required by `{coroutine@$DIR/clone-impl.rs:54:23: 54:30}: Copy`
|
||||||
|
|
|
||||||
|
note: coroutine does not implement `Copy` as this value is used across a yield
|
||||||
|
--> $DIR/clone-impl.rs:60:9
|
||||||
|
|
|
||||||
|
LL | let v = vec!['a'];
|
||||||
|
| - has type `Vec<char>` which does not implement `Copy`
|
||||||
|
...
|
||||||
|
LL | yield;
|
||||||
|
| ^^^^^ yield occurs here, with `v` maybe used later
|
||||||
|
note: required by a bound in `check_copy`
|
||||||
|
--> $DIR/clone-impl.rs:84:18
|
||||||
|
|
|
||||||
|
LL | fn check_copy<T: Copy>(_x: &T) {}
|
||||||
|
| ^^^^ required by this bound in `check_copy`
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `NonClone: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:74:25: 74:32}`
|
||||||
|
--> $DIR/clone-impl.rs:78:5
|
||||||
|
|
|
||||||
|
LL | let gen_non_clone = move || {
|
||||||
|
| ------- within this `{coroutine@$DIR/clone-impl.rs:74:25: 74:32}`
|
||||||
|
...
|
||||||
|
LL | check_copy(&gen_non_clone);
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:74:25: 74:32}`, the trait `Copy` is not implemented for `NonClone`, which is required by `{coroutine@$DIR/clone-impl.rs:74:25: 74:32}: Copy`
|
||||||
|
|
|
||||||
|
note: captured value does not implement `Copy`
|
||||||
|
--> $DIR/clone-impl.rs:76:14
|
||||||
|
|
|
||||||
LL | drop(non_clonable);
|
LL | drop(non_clonable);
|
||||||
| ^^^^^^^^^^^^ has type `NonClone` which does not implement `Copy`
|
| ^^^^^^^^^^^^ has type `NonClone` which does not implement `Copy`
|
||||||
note: required by a bound in `check_copy`
|
note: required by a bound in `check_copy`
|
||||||
--> $DIR/clone-impl.rs:72:18
|
--> $DIR/clone-impl.rs:84:18
|
||||||
|
|
|
|
||||||
LL | fn check_copy<T: Copy>(_x: &T) {}
|
LL | fn check_copy<T: Copy>(_x: &T) {}
|
||||||
| ^^^^ required by this bound in `check_copy`
|
| ^^^^ required by this bound in `check_copy`
|
||||||
@ -108,22 +108,22 @@ LL + #[derive(Copy)]
|
|||||||
LL | struct NonClone;
|
LL | struct NonClone;
|
||||||
|
|
|
|
||||||
|
|
||||||
error[E0277]: the trait bound `NonClone: Clone` is not satisfied in `{coroutine@$DIR/clone-impl.rs:62:25: 62:32}`
|
error[E0277]: the trait bound `NonClone: Clone` is not satisfied in `{coroutine@$DIR/clone-impl.rs:74:25: 74:32}`
|
||||||
--> $DIR/clone-impl.rs:68:5
|
--> $DIR/clone-impl.rs:80:5
|
||||||
|
|
|
|
||||||
LL | let gen_non_clone = move || {
|
LL | let gen_non_clone = move || {
|
||||||
| ------- within this `{coroutine@$DIR/clone-impl.rs:62:25: 62:32}`
|
| ------- within this `{coroutine@$DIR/clone-impl.rs:74:25: 74:32}`
|
||||||
...
|
...
|
||||||
LL | check_clone(&gen_non_clone);
|
LL | check_clone(&gen_non_clone);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:62:25: 62:32}`, the trait `Clone` is not implemented for `NonClone`, which is required by `{coroutine@$DIR/clone-impl.rs:62:25: 62:32}: Clone`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:74:25: 74:32}`, the trait `Clone` is not implemented for `NonClone`, which is required by `{coroutine@$DIR/clone-impl.rs:74:25: 74:32}: Clone`
|
||||||
|
|
|
|
||||||
note: captured value does not implement `Clone`
|
note: captured value does not implement `Clone`
|
||||||
--> $DIR/clone-impl.rs:64:14
|
--> $DIR/clone-impl.rs:76:14
|
||||||
|
|
|
|
||||||
LL | drop(non_clonable);
|
LL | drop(non_clonable);
|
||||||
| ^^^^^^^^^^^^ has type `NonClone` which does not implement `Clone`
|
| ^^^^^^^^^^^^ has type `NonClone` which does not implement `Clone`
|
||||||
note: required by a bound in `check_clone`
|
note: required by a bound in `check_clone`
|
||||||
--> $DIR/clone-impl.rs:73:19
|
--> $DIR/clone-impl.rs:85:19
|
||||||
|
|
|
|
||||||
LL | fn check_clone<T: Clone>(_x: &T) {}
|
LL | fn check_clone<T: Clone>(_x: &T) {}
|
||||||
| ^^^^^ required by this bound in `check_clone`
|
| ^^^^^ required by this bound in `check_clone`
|
||||||
|
10
tests/ui/coroutine/coroutine-in-orphaned-anon-const.rs
Normal file
10
tests/ui/coroutine/coroutine-in-orphaned-anon-const.rs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
//@ edition:2021
|
||||||
|
|
||||||
|
trait X {
|
||||||
|
fn test() -> Self::Assoc<{ async {} }>;
|
||||||
|
//~^ ERROR associated type `Assoc` not found for `Self`
|
||||||
|
//~| ERROR associated type `Assoc` not found for `Self`
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() {}
|
17
tests/ui/coroutine/coroutine-in-orphaned-anon-const.stderr
Normal file
17
tests/ui/coroutine/coroutine-in-orphaned-anon-const.stderr
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
error[E0220]: associated type `Assoc` not found for `Self`
|
||||||
|
--> $DIR/coroutine-in-orphaned-anon-const.rs:4:24
|
||||||
|
|
|
||||||
|
LL | fn test() -> Self::Assoc<{ async {} }>;
|
||||||
|
| ^^^^^ associated type `Assoc` not found
|
||||||
|
|
||||||
|
error[E0220]: associated type `Assoc` not found for `Self`
|
||||||
|
--> $DIR/coroutine-in-orphaned-anon-const.rs:4:24
|
||||||
|
|
|
||||||
|
LL | fn test() -> Self::Assoc<{ async {} }>;
|
||||||
|
| ^^^^^ associated type `Assoc` not found
|
||||||
|
|
|
||||||
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0220`.
|
@ -3,6 +3,11 @@ error[E0229]: associated type bindings are not allowed here
|
|||||||
|
|
|
|
||||||
LL | fn baz<I>(x: &<I as Foo<A=Bar>>::A) {}
|
LL | fn baz<I>(x: &<I as Foo<A=Bar>>::A) {}
|
||||||
| ^^^^^ associated type not allowed here
|
| ^^^^^ associated type not allowed here
|
||||||
|
|
|
||||||
|
help: consider removing this type binding
|
||||||
|
|
|
||||||
|
LL | fn baz<I>(x: &<I as Foo<A=Bar>>::A) {}
|
||||||
|
| ~~~~~~~
|
||||||
|
|
||||||
error[E0229]: associated type bindings are not allowed here
|
error[E0229]: associated type bindings are not allowed here
|
||||||
--> $DIR/E0229.rs:13:25
|
--> $DIR/E0229.rs:13:25
|
||||||
@ -11,6 +16,10 @@ LL | fn baz<I>(x: &<I as Foo<A=Bar>>::A) {}
|
|||||||
| ^^^^^ associated type not allowed here
|
| ^^^^^ associated type not allowed here
|
||||||
|
|
|
|
||||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
help: consider removing this type binding
|
||||||
|
|
|
||||||
|
LL | fn baz<I>(x: &<I as Foo<A=Bar>>::A) {}
|
||||||
|
| ~~~~~~~
|
||||||
|
|
||||||
error[E0229]: associated type bindings are not allowed here
|
error[E0229]: associated type bindings are not allowed here
|
||||||
--> $DIR/E0229.rs:13:25
|
--> $DIR/E0229.rs:13:25
|
||||||
@ -19,6 +28,10 @@ LL | fn baz<I>(x: &<I as Foo<A=Bar>>::A) {}
|
|||||||
| ^^^^^ associated type not allowed here
|
| ^^^^^ associated type not allowed here
|
||||||
|
|
|
|
||||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
help: consider removing this type binding
|
||||||
|
|
|
||||||
|
LL | fn baz<I>(x: &<I as Foo<A=Bar>>::A) {}
|
||||||
|
| ~~~~~~~
|
||||||
|
|
||||||
error[E0277]: the trait bound `I: Foo` is not satisfied
|
error[E0277]: the trait bound `I: Foo` is not satisfied
|
||||||
--> $DIR/E0229.rs:13:15
|
--> $DIR/E0229.rs:13:15
|
||||||
|
@ -3,6 +3,11 @@ error[E0229]: associated type bindings are not allowed here
|
|||||||
|
|
|
|
||||||
LL | type A: S<C<(), i32 = ()> = ()>;
|
LL | type A: S<C<(), i32 = ()> = ()>;
|
||||||
| ^^^^^^^^ associated type not allowed here
|
| ^^^^^^^^ associated type not allowed here
|
||||||
|
|
|
||||||
|
help: consider removing this type binding
|
||||||
|
|
|
||||||
|
LL | type A: S<C<(), i32 = ()> = ()>;
|
||||||
|
| ~~~~~~~~~~
|
||||||
|
|
||||||
error[E0229]: associated type bindings are not allowed here
|
error[E0229]: associated type bindings are not allowed here
|
||||||
--> $DIR/issue-102335-gat.rs:2:21
|
--> $DIR/issue-102335-gat.rs:2:21
|
||||||
@ -11,6 +16,10 @@ LL | type A: S<C<(), i32 = ()> = ()>;
|
|||||||
| ^^^^^^^^ associated type not allowed here
|
| ^^^^^^^^ associated type not allowed here
|
||||||
|
|
|
|
||||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
help: consider removing this type binding
|
||||||
|
|
|
||||||
|
LL | type A: S<C<(), i32 = ()> = ()>;
|
||||||
|
| ~~~~~~~~~~
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user