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>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
_: F,
|
||||
_: &F,
|
||||
) {
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
diag.note(self.0);
|
||||
|
@ -382,7 +382,7 @@ impl Subdiagnostic for EmptyLabelManySpans {
|
||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
_: F,
|
||||
_: &F,
|
||||
) {
|
||||
diag.span_labels(self.0, "");
|
||||
}
|
||||
@ -751,7 +751,7 @@ impl Subdiagnostic for StableFeature {
|
||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
_: F,
|
||||
_: &F,
|
||||
) {
|
||||
diag.arg("name", self.name);
|
||||
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 {
|
||||
let kind = match self.kind {
|
||||
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 ",
|
||||
// FIXME: differentiate `TwoPhaseBorrow`
|
||||
mir::BorrowKind::Mut {
|
||||
|
@ -17,9 +17,9 @@
|
||||
use rustc_middle::mir::tcx::PlaceTy;
|
||||
use rustc_middle::mir::{
|
||||
self, AggregateKind, BindingForm, BorrowKind, CallSource, ClearCrossCrate, ConstraintCategory,
|
||||
FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, MutBorrowKind, Operand, Place,
|
||||
PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
|
||||
VarBindingForm,
|
||||
FakeBorrowKind, FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, MutBorrowKind,
|
||||
Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator,
|
||||
TerminatorKind, VarBindingForm,
|
||||
};
|
||||
use rustc_middle::ty::{
|
||||
self, suggest_constraining_type_params, PredicateKind, ToPredicate, Ty, TyCtxt,
|
||||
@ -1486,7 +1486,7 @@ pub(crate) fn report_conflicting_borrow(
|
||||
let first_borrow_desc;
|
||||
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 },
|
||||
) => {
|
||||
first_borrow_desc = "mutable ";
|
||||
@ -1504,7 +1504,7 @@ pub(crate) fn report_conflicting_borrow(
|
||||
}
|
||||
(
|
||||
BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow },
|
||||
BorrowKind::Shared,
|
||||
BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep),
|
||||
) => {
|
||||
first_borrow_desc = "immutable ";
|
||||
let mut err = self.cannot_reborrow_already_borrowed(
|
||||
@ -1566,7 +1566,7 @@ pub(crate) fn report_conflicting_borrow(
|
||||
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) =
|
||||
self.classify_immutable_section(issued_borrow.assigned_place)
|
||||
{
|
||||
@ -1629,7 +1629,10 @@ pub(crate) fn report_conflicting_borrow(
|
||||
)
|
||||
}
|
||||
|
||||
(BorrowKind::Shared, BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }) => {
|
||||
(
|
||||
BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep),
|
||||
BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture },
|
||||
) => {
|
||||
first_borrow_desc = "first ";
|
||||
self.cannot_reborrow_already_uniquely_borrowed(
|
||||
span,
|
||||
@ -1659,8 +1662,14 @@ pub(crate) fn report_conflicting_borrow(
|
||||
)
|
||||
}
|
||||
|
||||
(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!()
|
||||
}
|
||||
};
|
||||
@ -3572,7 +3581,7 @@ pub(crate) fn report_illegal_mutation_of_borrowed(
|
||||
let loan_span = loan_spans.args_or_use();
|
||||
|
||||
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) {
|
||||
let mut err = self.cannot_mutate_in_immutable_section(
|
||||
span,
|
||||
|
@ -654,7 +654,7 @@ pub(super) fn var_subdiag(
|
||||
match kind {
|
||||
Some(kd) => match kd {
|
||||
rustc_middle::mir::BorrowKind::Shared
|
||||
| rustc_middle::mir::BorrowKind::Fake => {
|
||||
| rustc_middle::mir::BorrowKind::Fake(_) => {
|
||||
CaptureVarKind::Immut { kind_span: capture_kind_span }
|
||||
}
|
||||
|
||||
|
@ -1056,18 +1056,19 @@ fn check_access_for_conflict(
|
||||
Control::Continue
|
||||
}
|
||||
|
||||
(Read(_), BorrowKind::Shared | BorrowKind::Fake)
|
||||
| (Read(ReadKind::Borrow(BorrowKind::Fake)), BorrowKind::Mut { .. }) => {
|
||||
Control::Continue
|
||||
}
|
||||
(Read(_), BorrowKind::Shared | BorrowKind::Fake(_))
|
||||
| (
|
||||
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
|
||||
// disallowed on NLL). See rust-lang/rust#56254
|
||||
Control::Continue
|
||||
}
|
||||
|
||||
(Write(WriteKind::Move), BorrowKind::Fake) => {
|
||||
(Write(WriteKind::Move), BorrowKind::Fake(FakeBorrowKind::Shallow)) => {
|
||||
// Handled by initialization checks.
|
||||
Control::Continue
|
||||
}
|
||||
@ -1175,10 +1176,12 @@ fn consume_rvalue(
|
||||
match rvalue {
|
||||
&Rvalue::Ref(_ /*rgn*/, bk, place) => {
|
||||
let access_kind = match bk {
|
||||
BorrowKind::Fake => {
|
||||
BorrowKind::Fake(FakeBorrowKind::Shallow) => {
|
||||
(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 { .. } => {
|
||||
let wk = WriteKind::MutableBorrow(bk);
|
||||
if allow_two_phase_borrow(bk) {
|
||||
@ -1197,7 +1200,7 @@ fn consume_rvalue(
|
||||
flow_state,
|
||||
);
|
||||
|
||||
let action = if bk == BorrowKind::Fake {
|
||||
let action = if bk == BorrowKind::Fake(FakeBorrowKind::Shallow) {
|
||||
InitializationRequiringAction::MatchOn
|
||||
} else {
|
||||
InitializationRequiringAction::Borrow
|
||||
@ -1557,7 +1560,7 @@ fn check_activations(&mut self, location: Location, span: Span, flow_state: &Flo
|
||||
|
||||
// only mutable borrows should be 2-phase
|
||||
assert!(match borrow.kind {
|
||||
BorrowKind::Shared | BorrowKind::Fake => false,
|
||||
BorrowKind::Shared | BorrowKind::Fake(_) => false,
|
||||
BorrowKind::Mut { .. } => true,
|
||||
});
|
||||
|
||||
@ -2122,14 +2125,14 @@ fn check_access_permissions(
|
||||
| WriteKind::Replace
|
||||
| WriteKind::StorageDeadOrDrop
|
||||
| WriteKind::MutableBorrow(BorrowKind::Shared)
|
||||
| WriteKind::MutableBorrow(BorrowKind::Fake),
|
||||
| WriteKind::MutableBorrow(BorrowKind::Fake(_)),
|
||||
)
|
||||
| Write(
|
||||
WriteKind::Move
|
||||
| WriteKind::Replace
|
||||
| WriteKind::StorageDeadOrDrop
|
||||
| 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()
|
||||
&& !self.has_buffered_diags()
|
||||
@ -2153,7 +2156,7 @@ fn check_access_permissions(
|
||||
return false;
|
||||
}
|
||||
Read(
|
||||
ReadKind::Borrow(BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake)
|
||||
ReadKind::Borrow(BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake(_))
|
||||
| ReadKind::Copy,
|
||||
) => {
|
||||
// Access authorized
|
||||
|
@ -55,7 +55,7 @@
|
||||
use crate::{AccessDepth, Deep, Shallow};
|
||||
use rustc_hir as hir;
|
||||
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 std::cmp::max;
|
||||
@ -271,10 +271,10 @@ fn place_components_conflict<'tcx>(
|
||||
// If the second example, where we did, then we still know
|
||||
// that the borrow can access a *part* of our place that
|
||||
// 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()
|
||||
{
|
||||
debug!("borrow_conflicts_with_place: fake borrow");
|
||||
debug!("borrow_conflicts_with_place: shallow borrow");
|
||||
false
|
||||
} else {
|
||||
debug!("borrow_conflicts_with_place: full borrow, CONFLICT");
|
||||
|
@ -1,6 +1,8 @@
|
||||
use rustc_data_structures::graph::dominators::Dominators;
|
||||
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::{InlineAsmOperand, Terminator, TerminatorKind};
|
||||
use rustc_middle::mir::{Statement, StatementKind};
|
||||
@ -239,10 +241,12 @@ fn consume_rvalue(&mut self, location: Location, rvalue: &Rvalue<'tcx>) {
|
||||
match rvalue {
|
||||
&Rvalue::Ref(_ /*rgn*/, bk, place) => {
|
||||
let access_kind = match bk {
|
||||
BorrowKind::Fake => {
|
||||
BorrowKind::Fake(FakeBorrowKind::Shallow) => {
|
||||
(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 { .. } => {
|
||||
let wk = WriteKind::MutableBorrow(bk);
|
||||
if allow_two_phase_borrow(bk) {
|
||||
@ -357,8 +361,11 @@ fn check_access_for_conflict(
|
||||
// have already taken the reservation
|
||||
}
|
||||
|
||||
(Read(_), BorrowKind::Fake | BorrowKind::Shared)
|
||||
| (Read(ReadKind::Borrow(BorrowKind::Fake)), BorrowKind::Mut { .. }) => {
|
||||
(Read(_), BorrowKind::Fake(_) | BorrowKind::Shared)
|
||||
| (
|
||||
Read(ReadKind::Borrow(BorrowKind::Fake(FakeBorrowKind::Shallow))),
|
||||
BorrowKind::Mut { .. },
|
||||
) => {
|
||||
// Reads don't invalidate shared or shallow borrows
|
||||
}
|
||||
|
||||
@ -403,7 +410,7 @@ fn check_activations(&mut self, location: Location) {
|
||||
|
||||
// only mutable borrows should be 2-phase
|
||||
assert!(match borrow.kind {
|
||||
BorrowKind::Shared | BorrowKind::Fake => false,
|
||||
BorrowKind::Shared | BorrowKind::Fake(_) => false,
|
||||
BorrowKind::Mut { .. } => true,
|
||||
});
|
||||
|
||||
|
@ -601,7 +601,7 @@ impl Subdiagnostic for FormatUnusedArg {
|
||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
f: F,
|
||||
f: &F,
|
||||
) {
|
||||
diag.arg("named", self.named);
|
||||
let msg = f(diag, crate::fluent_generated::builtin_macros_format_unused_arg.into());
|
||||
|
@ -414,7 +414,7 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
|
||||
BorrowKind::Shared => {
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow)
|
||||
}
|
||||
BorrowKind::Fake => {
|
||||
BorrowKind::Fake(_) => {
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::FakeBorrow)
|
||||
}
|
||||
BorrowKind::Mut { .. } => {
|
||||
@ -487,7 +487,7 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
|
||||
}
|
||||
}
|
||||
|
||||
Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Fake, place)
|
||||
Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Fake(_), place)
|
||||
| Rvalue::AddressOf(Mutability::Not, place) => {
|
||||
let borrowed_place_has_mut_interior = qualifs::in_place::<HasMutInterior, _>(
|
||||
self.ccx,
|
||||
|
@ -105,7 +105,7 @@ fn address_of_allows_mutation(&self) -> bool {
|
||||
fn ref_allows_mutation(&self, kind: mir::BorrowKind, place: mir::Place<'tcx>) -> bool {
|
||||
match kind {
|
||||
mir::BorrowKind::Mut { .. } => true,
|
||||
mir::BorrowKind::Shared | mir::BorrowKind::Fake => {
|
||||
mir::BorrowKind::Shared | mir::BorrowKind::Fake(_) => {
|
||||
self.shared_borrow_allows_mutation(place)
|
||||
}
|
||||
}
|
||||
|
@ -965,7 +965,7 @@ macro_rules! check_kinds {
|
||||
}
|
||||
}
|
||||
},
|
||||
Rvalue::Ref(_, BorrowKind::Fake, _) => {
|
||||
Rvalue::Ref(_, BorrowKind::Fake(_), _) => {
|
||||
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
|
||||
self.fail(
|
||||
location,
|
||||
|
@ -177,7 +177,7 @@ pub trait Subdiagnostic
|
||||
{
|
||||
/// Add a subdiagnostic to an existing diagnostic.
|
||||
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
|
||||
@ -185,7 +185,7 @@ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
|
||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
f: F,
|
||||
f: &F,
|
||||
);
|
||||
}
|
||||
|
||||
@ -1197,7 +1197,7 @@ pub fn subdiagnostic(
|
||||
dcx: &crate::DiagCtxt,
|
||||
subdiagnostic: impl Subdiagnostic,
|
||||
) -> &mut Self {
|
||||
subdiagnostic.add_to_diag_with(self, |diag, msg| {
|
||||
subdiagnostic.add_to_diag_with(self, &|diag, msg| {
|
||||
let args = diag.args.iter();
|
||||
let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
|
||||
dcx.eagerly_translate(msg, args)
|
||||
|
@ -227,6 +227,36 @@ fn into_diag_arg(self) -> DiagArgValue {
|
||||
}
|
||||
}
|
||||
|
||||
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)]
|
||||
pub struct DiagSymbolList(Vec<Symbol>);
|
||||
|
||||
@ -244,12 +274,6 @@ fn into_diag_arg(self) -> DiagArgValue {
|
||||
}
|
||||
}
|
||||
|
||||
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<'_> {
|
||||
fn into_diag(self, dcx: &DiagCtxt, level: Level) -> Diag<'_, G> {
|
||||
match self {
|
||||
@ -302,7 +326,7 @@ impl Subdiagnostic for SingleLabelManySpans {
|
||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
_: F,
|
||||
_: &F,
|
||||
) {
|
||||
diag.span_labels(self.spans, self.label);
|
||||
}
|
||||
@ -316,24 +340,6 @@ pub struct ExpectedLifetimeParameter {
|
||||
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)]
|
||||
#[suggestion(errors_indicate_anonymous_lifetime, code = "{suggestion}", style = "verbose")]
|
||||
pub struct IndicateAnonymousLifetime {
|
||||
@ -343,8 +349,10 @@ pub struct IndicateAnonymousLifetime {
|
||||
pub suggestion: String,
|
||||
}
|
||||
|
||||
impl IntoDiagArg for type_ir::ClosureKind {
|
||||
fn into_diag_arg(self) -> DiagArgValue {
|
||||
DiagArgValue::Str(self.as_str().into())
|
||||
}
|
||||
#[derive(Subdiagnostic)]
|
||||
pub struct ElidedLifetimeInPathSubdiag {
|
||||
#[subdiagnostic]
|
||||
pub expected: ExpectedLifetimeParameter,
|
||||
#[subdiagnostic]
|
||||
pub indicate: Option<IndicateAnonymousLifetime>,
|
||||
}
|
||||
|
@ -40,8 +40,8 @@
|
||||
SubdiagMessageOp, Subdiagnostic,
|
||||
};
|
||||
pub use diagnostic_impls::{
|
||||
DiagArgFromDisplay, DiagSymbolList, ExpectedLifetimeParameter, IndicateAnonymousLifetime,
|
||||
SingleLabelManySpans,
|
||||
DiagArgFromDisplay, DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter,
|
||||
IndicateAnonymousLifetime, SingleLabelManySpans,
|
||||
};
|
||||
pub use emitter::ColorConfig;
|
||||
pub use rustc_error_messages::{
|
||||
@ -1911,27 +1911,24 @@ fn can_be_subdiag(&self) -> bool {
|
||||
}
|
||||
|
||||
// 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,
|
||||
diag: &mut Diag<'_, G>,
|
||||
n: usize,
|
||||
path_span: Span,
|
||||
incl_angl_brckt: bool,
|
||||
insertion_span: Span,
|
||||
) {
|
||||
diag.subdiagnostic(diag.dcx, 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.
|
||||
return;
|
||||
}
|
||||
let anon_lts = vec!["'_"; n].join(", ");
|
||||
let suggestion =
|
||||
if incl_angl_brckt { format!("<{anon_lts}>") } else { format!("{anon_lts}, ") };
|
||||
) -> ElidedLifetimeInPathSubdiag {
|
||||
let expected = ExpectedLifetimeParameter { span: path_span, count: n };
|
||||
// Do not try to suggest anything if generated by a proc-macro.
|
||||
let indicate = source_map.is_span_accessible(insertion_span).then(|| {
|
||||
let anon_lts = vec!["'_"; n].join(", ");
|
||||
let suggestion =
|
||||
if incl_angl_brckt { format!("<{anon_lts}>") } else { format!("{anon_lts}, ") };
|
||||
|
||||
diag.subdiagnostic(
|
||||
diag.dcx,
|
||||
IndicateAnonymousLifetime { span: insertion_span.shrink_to_hi(), count: n, suggestion },
|
||||
);
|
||||
IndicateAnonymousLifetime { span: insertion_span.shrink_to_hi(), count: n, suggestion }
|
||||
});
|
||||
|
||||
ElidedLifetimeInPathSubdiag { expected, indicate }
|
||||
}
|
||||
|
||||
pub fn report_ambiguity_error<'a, G: EmissionGuarantee>(
|
||||
|
@ -644,13 +644,49 @@ pub fn outlives_for_param(
|
||||
})
|
||||
}
|
||||
|
||||
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(
|
||||
|bound| {
|
||||
// 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())
|
||||
let span_for_parentheses = if let Some(trait_ref) = bound.trait_ref()
|
||||
&& let [.., segment] = trait_ref.path.segments
|
||||
&& segment.args().parenthesized == GenericArgsParentheses::ParenSugar
|
||||
&& 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::def::{CtorKind, DefKind};
|
||||
use rustc_hir::Node;
|
||||
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_middle::middle::resolve_bound_vars::ResolvedArg;
|
||||
use rustc_middle::middle::stability::EvalResult;
|
||||
use rustc_middle::traits::ObligationCauseCode;
|
||||
use rustc_middle::ty::fold::BottomUpFolder;
|
||||
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
|
||||
use rustc_middle::ty::util::{Discr, InspectCoroutineFields, IntTypeExt};
|
||||
@ -24,10 +23,10 @@
|
||||
};
|
||||
use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS};
|
||||
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::TypeErrCtxtExt 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 std::cell::LazyCell;
|
||||
@ -1715,55 +1714,31 @@ fn visit_ty(&mut self, t: Ty<'tcx>) {
|
||||
err.emit()
|
||||
}
|
||||
|
||||
// FIXME(@lcnr): This should not be computed per coroutine, but instead once for
|
||||
// each typeck root.
|
||||
pub(super) fn check_coroutine_obligations(
|
||||
tcx: TyCtxt<'_>,
|
||||
def_id: LocalDefId,
|
||||
) -> 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 param_env = tcx.param_env(typeck.hir_owner.def_id);
|
||||
let typeck_results = tcx.typeck(def_id);
|
||||
let param_env = tcx.param_env(def_id);
|
||||
|
||||
let coroutine_interior_predicates = &typeck.coroutine_interior_predicates[&def_id];
|
||||
debug!(?coroutine_interior_predicates);
|
||||
debug!(?typeck_results.coroutine_stalled_predicates);
|
||||
|
||||
let infcx = tcx
|
||||
.infer_ctxt()
|
||||
// typeck writeback gives us predicates with their regions erased.
|
||||
// As borrowck already has checked lifetimes, we do not need to do it again.
|
||||
.ignoring_regions()
|
||||
// Bind opaque types to type checking root, as they should have been checked by borrowck,
|
||||
// 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)
|
||||
.with_opaque_type_inference(def_id)
|
||||
.build();
|
||||
|
||||
let mut fulfillment_cx = <dyn TraitEngine<'_>>::new(&infcx);
|
||||
for (predicate, cause) in coroutine_interior_predicates {
|
||||
let obligation = Obligation::new(tcx, cause.clone(), param_env, *predicate);
|
||||
fulfillment_cx.register_predicate_obligation(&infcx, obligation);
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
for (predicate, cause) in &typeck_results.coroutine_stalled_predicates {
|
||||
ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, *predicate));
|
||||
}
|
||||
|
||||
if (tcx.features().unsized_locals || tcx.features().unsized_fn_params)
|
||||
&& 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);
|
||||
let errors = ocx.select_all_or_error();
|
||||
debug!(?errors);
|
||||
if !errors.is_empty() {
|
||||
return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
|
||||
|
@ -17,6 +17,7 @@
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_infer::traits::FulfillmentError;
|
||||
use rustc_middle::query::Key;
|
||||
use rustc_middle::ty::GenericParamDefKind;
|
||||
use rustc_middle::ty::{self, suggest_constraining_type_param};
|
||||
use rustc_middle::ty::{AdtDef, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_middle::ty::{Binder, TraitRef};
|
||||
@ -1200,12 +1201,12 @@ pub fn report_trait_object_with_no_traits_error(
|
||||
/// Emits an error regarding forbidden type binding associations
|
||||
pub fn prohibit_assoc_item_binding(
|
||||
tcx: TyCtxt<'_>,
|
||||
span: Span,
|
||||
segment: Option<(&hir::PathSegment<'_>, Span)>,
|
||||
binding: &hir::TypeBinding<'_>,
|
||||
segment: Option<(DefId, &hir::PathSegment<'_>, Span)>,
|
||||
) -> ErrorGuaranteed {
|
||||
tcx.dcx().emit_err(AssocTypeBindingNotAllowed {
|
||||
span,
|
||||
fn_trait_expansion: if let Some((segment, span)) = segment
|
||||
let mut err = tcx.dcx().create_err(AssocTypeBindingNotAllowed {
|
||||
span: binding.span,
|
||||
fn_trait_expansion: if let Some((_, segment, span)) = segment
|
||||
&& segment.args().parenthesized == hir::GenericArgsParentheses::ParenSugar
|
||||
{
|
||||
Some(ParenthesizedFnTraitExpansion {
|
||||
@ -1215,7 +1216,109 @@ pub fn prohibit_assoc_item_binding(
|
||||
} else {
|
||||
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(
|
||||
|
@ -454,7 +454,7 @@ pub(crate) fn check_generic_arg_count(
|
||||
if gen_pos != GenericArgPosition::Type
|
||||
&& 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 =
|
||||
|
@ -323,7 +323,7 @@ pub fn lower_generic_args_of_path_segment(
|
||||
ty::BoundConstness::NotConst,
|
||||
);
|
||||
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
|
||||
}
|
||||
@ -620,7 +620,7 @@ pub fn lower_generic_args_of_assoc_item(
|
||||
ty::BoundConstness::NotConst,
|
||||
);
|
||||
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
|
||||
}
|
||||
@ -765,7 +765,7 @@ fn lower_mono_trait_ref(
|
||||
constness,
|
||||
);
|
||||
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)
|
||||
}
|
||||
@ -1544,7 +1544,7 @@ pub fn prohibit_generic_args<'a>(
|
||||
for segment in segments {
|
||||
// Only emit the first error to avoid overloading the user with error messages.
|
||||
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>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
_f: F,
|
||||
_f: &F,
|
||||
) {
|
||||
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>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
_f: F,
|
||||
_f: &F,
|
||||
) {
|
||||
let mut multispan: MultiSpan = self.semi.into();
|
||||
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>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
f: F,
|
||||
f: &F,
|
||||
) {
|
||||
match self {
|
||||
CastUnknownPointerSub::To(span) => {
|
||||
|
@ -750,6 +750,15 @@ fn walk_pat(
|
||||
}
|
||||
}
|
||||
}
|
||||
} 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 @@ pub(in super::super) fn resolve_coroutine_interiors(&self) {
|
||||
obligations
|
||||
.extend(self.fulfillment_cx.borrow_mut().drain_unstalled_obligations(&self.infcx));
|
||||
|
||||
let obligations = obligations.into_iter().map(|o| (o.predicate, o.cause)).collect();
|
||||
debug!(?obligations);
|
||||
self.typeck_results
|
||||
.borrow_mut()
|
||||
.coroutine_interior_predicates
|
||||
.insert(expr_def_id, obligations);
|
||||
let obligations = obligations.into_iter().map(|o| (o.predicate, o.cause));
|
||||
self.typeck_results.borrow_mut().coroutine_stalled_predicates.extend(obligations);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@
|
||||
};
|
||||
use rustc_hir_analysis::collect::suggest_impl_trait;
|
||||
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::middle::stability::EvalResult;
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
|
@ -711,13 +711,23 @@ fn cat_pattern_<F>(
|
||||
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
|
||||
// PatKind::Ref since that information is already contained
|
||||
// in the type.
|
||||
let subplace = self.cat_deref(pat, place_with_id)?;
|
||||
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) => {
|
||||
let Some(element_ty) = place_with_id.place.ty().builtin_index() else {
|
||||
|
@ -3291,14 +3291,17 @@ enum Introducer {
|
||||
param.name.ident(),
|
||||
));
|
||||
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(
|
||||
msg,
|
||||
candidates.iter().map(|t| {
|
||||
vec![
|
||||
(param.span.shrink_to_lo(), "(".to_string()),
|
||||
(
|
||||
bounds_span.unwrap(),
|
||||
bounds_span,
|
||||
format!(" + {})", self.tcx.def_path_str(t.def_id)),
|
||||
),
|
||||
]
|
||||
@ -3308,32 +3311,46 @@ enum Introducer {
|
||||
return;
|
||||
}
|
||||
|
||||
let (sp, introducer) = if let Some(span) = bounds_span {
|
||||
(span, Introducer::Plus)
|
||||
} else if let Some(colon_span) = param.colon_span {
|
||||
(colon_span.shrink_to_hi(), Introducer::Nothing)
|
||||
} else if param.is_impl_trait() {
|
||||
(param.span.shrink_to_hi(), Introducer::Plus)
|
||||
} else {
|
||||
(param.span.shrink_to_hi(), Introducer::Colon)
|
||||
};
|
||||
let (sp, introducer, open_paren_sp) =
|
||||
if let Some((span, open_paren_sp)) = bounds_span {
|
||||
(span, Introducer::Plus, open_paren_sp)
|
||||
} else if let Some(colon_span) = param.colon_span {
|
||||
(colon_span.shrink_to_hi(), Introducer::Nothing, None)
|
||||
} else if param.is_impl_trait() {
|
||||
(param.span.shrink_to_hi(), Introducer::Plus, None)
|
||||
} else {
|
||||
(param.span.shrink_to_hi(), Introducer::Colon, None)
|
||||
};
|
||||
|
||||
err.span_suggestions(
|
||||
sp,
|
||||
let all_suggs = candidates.iter().map(|cand| {
|
||||
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,
|
||||
candidates.iter().map(|t| {
|
||||
format!(
|
||||
"{} {}",
|
||||
match introducer {
|
||||
Introducer::Plus => " +",
|
||||
Introducer::Colon => ":",
|
||||
Introducer::Nothing => "",
|
||||
},
|
||||
self.tcx.def_path_str(t.def_id)
|
||||
)
|
||||
}),
|
||||
all_suggs,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
Node::Item(hir::Item {
|
||||
|
@ -551,15 +551,10 @@ fn visit_user_provided_sigs(&mut self) {
|
||||
fn visit_coroutine_interior(&mut self) {
|
||||
let fcx_typeck_results = self.fcx.typeck_results.borrow();
|
||||
assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
|
||||
self.tcx().with_stable_hashing_context(move |ref hcx| {
|
||||
for (&expr_def_id, predicates) in
|
||||
fcx_typeck_results.coroutine_interior_predicates.to_sorted(hcx, false).into_iter()
|
||||
{
|
||||
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);
|
||||
}
|
||||
})
|
||||
for (predicate, cause) in &fcx_typeck_results.coroutine_stalled_predicates {
|
||||
let (predicate, cause) = self.resolve((*predicate, cause.clone()), &cause.span);
|
||||
self.typeck_results.coroutine_stalled_predicates.insert((predicate, cause));
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
|
@ -239,7 +239,7 @@ impl Subdiagnostic for RegionOriginNote<'_> {
|
||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
_f: F,
|
||||
_f: &F,
|
||||
) {
|
||||
let mut label_or_note = |span, msg: DiagMessage| {
|
||||
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>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
_f: F,
|
||||
_f: &F,
|
||||
) {
|
||||
match self {
|
||||
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>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
_f: F,
|
||||
_f: &F,
|
||||
) {
|
||||
let mut mk_suggestion = || {
|
||||
let (
|
||||
@ -454,7 +454,7 @@ impl Subdiagnostic for IntroducesStaticBecauseUnmetLifetimeReq {
|
||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||
mut self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
_f: F,
|
||||
_f: &F,
|
||||
) {
|
||||
self.unmet_requirements
|
||||
.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>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
f: F,
|
||||
f: &F,
|
||||
) {
|
||||
let mut type_param_span: MultiSpan = self.spans.clone().into();
|
||||
for &span in &self.spans {
|
||||
@ -818,7 +818,7 @@ impl Subdiagnostic for DynTraitConstraintSuggestion {
|
||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
f: F,
|
||||
f: &F,
|
||||
) {
|
||||
let mut multi_span: MultiSpan = vec![self.span].into();
|
||||
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>>(
|
||||
mut self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
f: F,
|
||||
f: &F,
|
||||
) {
|
||||
for sp in self.spans {
|
||||
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>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
_f: F,
|
||||
_f: &F,
|
||||
) {
|
||||
diag.code(E0772);
|
||||
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>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
f: F,
|
||||
f: &F,
|
||||
) {
|
||||
diag.arg("path", self.path);
|
||||
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>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
f: F,
|
||||
f: &F,
|
||||
) {
|
||||
diag.arg("pref_kind", self.prefix);
|
||||
diag.arg("suff_kind", self.suffix);
|
||||
|
@ -2369,7 +2369,7 @@ pub fn construct_generic_bound_failure(
|
||||
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 {
|
||||
GenericKind::Param(param) => {
|
||||
let generics = self.tcx.generics_of(generic_param_scope);
|
||||
@ -2380,10 +2380,10 @@ pub fn construct_generic_bound_failure(
|
||||
// instead we suggest `T: 'a + 'b` in that case.
|
||||
let hir_generics = self.tcx.hir().get_generics(scope).unwrap();
|
||||
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.
|
||||
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)
|
||||
}
|
||||
@ -2406,12 +2406,18 @@ pub fn construct_generic_bound_failure(
|
||||
let mut suggs = vec![];
|
||||
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
|
||||
{
|
||||
let suggestion =
|
||||
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
|
||||
&& let ty::Projection = p.kind(self.tcx)
|
||||
&& 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| {
|
||||
if tcx.is_coroutine(def_id.to_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));
|
||||
|
@ -321,6 +321,7 @@ fn test_search_paths_tracking_hash_different_order() {
|
||||
&opts.target_triple,
|
||||
&early_dcx,
|
||||
search_path,
|
||||
false,
|
||||
));
|
||||
};
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
|
||||
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_middle::middle::stability;
|
||||
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");
|
||||
}
|
||||
BuiltinLintDiag::ElidedLifetimesInPaths(n, path_span, incl_angl_brckt, insertion_span) => {
|
||||
add_elided_lifetime_in_path_suggestion(
|
||||
sess.source_map(),
|
||||
diag,
|
||||
n,
|
||||
path_span,
|
||||
incl_angl_brckt,
|
||||
insertion_span,
|
||||
diag.subdiagnostic(
|
||||
sess.dcx(),
|
||||
elided_lifetime_in_path_suggestion(
|
||||
sess.source_map(),
|
||||
n,
|
||||
path_span,
|
||||
incl_angl_brckt,
|
||||
insertion_span,
|
||||
),
|
||||
);
|
||||
}
|
||||
BuiltinLintDiag::UnknownCrateTypes(span, note, sugg) => {
|
||||
|
@ -27,7 +27,7 @@ impl Subdiagnostic for OverruledAttributeSub {
|
||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
_f: F,
|
||||
_f: &F,
|
||||
) {
|
||||
match self {
|
||||
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>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
_f: F,
|
||||
_f: &F,
|
||||
) {
|
||||
// Access to associates types should use `<T as Bound>::Assoc`, which does not need a
|
||||
// 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>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
_f: F,
|
||||
_f: &F,
|
||||
) {
|
||||
diag.multipart_suggestion(
|
||||
fluent::lint_suggestion,
|
||||
@ -451,7 +451,7 @@ impl Subdiagnostic for BuiltinUnpermittedTypeInitSub {
|
||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
_f: F,
|
||||
_f: &F,
|
||||
) {
|
||||
let mut err = self.err;
|
||||
loop {
|
||||
@ -506,7 +506,7 @@ impl Subdiagnostic for BuiltinClashingExternSub<'_> {
|
||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
_f: F,
|
||||
_f: &F,
|
||||
) {
|
||||
let mut expected_str = DiagStyledString::new();
|
||||
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>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
_f: F,
|
||||
_f: &F,
|
||||
) {
|
||||
for (c, span) in self.spans {
|
||||
diag.span_label(span, format!("{c:?}"));
|
||||
@ -806,7 +806,7 @@ impl Subdiagnostic for HiddenUnicodeCodepointsDiagSub {
|
||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
_f: F,
|
||||
_f: &F,
|
||||
) {
|
||||
match self {
|
||||
HiddenUnicodeCodepointsDiagSub::Escape { spans } => {
|
||||
@ -954,7 +954,7 @@ impl Subdiagnostic for NonBindingLetSub {
|
||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
_f: F,
|
||||
_f: &F,
|
||||
) {
|
||||
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>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
_f: F,
|
||||
_f: &F,
|
||||
) {
|
||||
match self {
|
||||
NonSnakeCaseDiagSub::Label { span } => {
|
||||
@ -1482,7 +1482,7 @@ impl Subdiagnostic for OverflowingBinHexSign {
|
||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
_f: F,
|
||||
_f: &F,
|
||||
) {
|
||||
match self {
|
||||
OverflowingBinHexSign::Positive => {
|
||||
|
@ -71,6 +71,7 @@ pub(crate) fn into_tokens(self, mut structure: Structure<'_>) -> TokenStream {
|
||||
span_field: None,
|
||||
applicability: None,
|
||||
has_suggestion_parts: false,
|
||||
has_subdiagnostic: false,
|
||||
is_enum,
|
||||
};
|
||||
builder.into_tokens().unwrap_or_else(|v| v.to_compile_error())
|
||||
@ -90,7 +91,7 @@ pub(crate) fn into_tokens(self, mut structure: Structure<'_>) -> TokenStream {
|
||||
fn add_to_diag_with<__G, __F>(
|
||||
self,
|
||||
#diag: &mut rustc_errors::Diag<'_, __G>,
|
||||
#f: __F
|
||||
#f: &__F
|
||||
) where
|
||||
__G: rustc_errors::EmissionGuarantee,
|
||||
__F: rustc_errors::SubdiagMessageOp<__G>,
|
||||
@ -133,6 +134,10 @@ struct SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
||||
/// during finalization if still `false`.
|
||||
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.
|
||||
is_enum: bool,
|
||||
}
|
||||
@ -373,6 +378,13 @@ fn generate_field_code_inner_path(
|
||||
|
||||
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![];
|
||||
if kind_stats.has_multipart_suggestion {
|
||||
@ -480,18 +492,6 @@ fn generate_field_code_inner_list(
|
||||
|
||||
pub(crate) fn into_tokens(&mut self) -> Result<TokenStream, DiagnosticDeriveError> {
|
||||
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 =
|
||||
kind_slugs.iter().map(|(kind, _slug, _no_span)| kind).collect();
|
||||
@ -510,6 +510,19 @@ pub(crate) fn into_tokens(&mut self) -> Result<TokenStream, DiagnosticDeriveErro
|
||||
.map(|binding| self.generate_field_attr_code(binding, kind_stats))
|
||||
.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 diag = &self.parent.diag;
|
||||
|
@ -144,6 +144,7 @@ pub fn extension(attr: TokenStream, input: TokenStream) -> TokenStream {
|
||||
help,
|
||||
note,
|
||||
warning,
|
||||
subdiagnostic,
|
||||
suggestion,
|
||||
suggestion_short,
|
||||
suggestion_hidden,
|
||||
|
@ -985,7 +985,8 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||
Ref(region, borrow_kind, ref place) => {
|
||||
let kind_str = match borrow_kind {
|
||||
BorrowKind::Shared => "",
|
||||
BorrowKind::Fake => "fake ",
|
||||
BorrowKind::Fake(FakeBorrowKind::Deep) => "fake ",
|
||||
BorrowKind::Fake(FakeBorrowKind::Shallow) => "fake shallow ",
|
||||
BorrowKind::Mut { .. } => "mut ",
|
||||
};
|
||||
|
||||
|
@ -236,6 +236,11 @@ pub fn as_local(&self) -> Option<Local> {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_place(&self, tcx: TyCtxt<'tcx>) -> Place<'tcx> {
|
||||
Place { local: self.local, projection: tcx.mk_place_elems(self.projection) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn last_projection(&self) -> Option<(PlaceRef<'tcx>, PlaceElem<'tcx>)> {
|
||||
if let &[ref proj_base @ .., elem] = self.projection {
|
||||
@ -446,7 +451,7 @@ pub fn is_safe_to_remove(&self) -> bool {
|
||||
impl BorrowKind {
|
||||
pub fn mutability(&self) -> Mutability {
|
||||
match *self {
|
||||
BorrowKind::Shared | BorrowKind::Fake => Mutability::Not,
|
||||
BorrowKind::Shared | BorrowKind::Fake(_) => Mutability::Not,
|
||||
BorrowKind::Mut { .. } => Mutability::Mut,
|
||||
}
|
||||
}
|
||||
@ -454,7 +459,7 @@ pub fn mutability(&self) -> Mutability {
|
||||
pub fn allows_two_phase_borrow(&self) -> bool {
|
||||
match *self {
|
||||
BorrowKind::Shared
|
||||
| BorrowKind::Fake
|
||||
| BorrowKind::Fake(_)
|
||||
| BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::ClosureCapture } => {
|
||||
false
|
||||
}
|
||||
|
@ -165,13 +165,16 @@ pub enum BorrowKind {
|
||||
/// Data must be immutable and is aliasable.
|
||||
Shared,
|
||||
|
||||
/// 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`.
|
||||
/// An immutable, aliasable borrow that is discarded after borrow-checking. Can behave either
|
||||
/// like a normal shared borrow or like a special shallow borrow (see [`FakeBorrowKind`]).
|
||||
///
|
||||
/// 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:
|
||||
/// This is used when lowering index expressions and matches. This is used to prevent code like
|
||||
/// the following from compiling:
|
||||
/// ```compile_fail,E0510
|
||||
/// let mut x: &[_] = &[[0, 1]];
|
||||
/// let y: &[_] = &[];
|
||||
/// let _ = x[0][{x = y; 1}];
|
||||
/// ```
|
||||
/// ```compile_fail,E0510
|
||||
/// let mut x = &Some(0);
|
||||
/// match *x {
|
||||
@ -180,11 +183,8 @@ pub enum BorrowKind {
|
||||
/// 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.
|
||||
Fake,
|
||||
Fake(FakeBorrowKind),
|
||||
|
||||
/// Data is mutable and not aliasable.
|
||||
Mut { kind: MutBorrowKind },
|
||||
@ -240,6 +240,57 @@ pub enum MutBorrowKind {
|
||||
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
|
||||
|
||||
|
@ -294,7 +294,7 @@ pub fn to_mutbl_lossy(self) -> hir::Mutability {
|
||||
|
||||
// We have no type corresponding to a shallow borrow, so use
|
||||
// `&` as an approximation.
|
||||
BorrowKind::Fake => hir::Mutability::Not,
|
||||
BorrowKind::Fake(_) => hir::Mutability::Not,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -655,7 +655,7 @@ fn super_rvalue(&mut self,
|
||||
BorrowKind::Shared => PlaceContext::NonMutatingUse(
|
||||
NonMutatingUseContext::SharedBorrow
|
||||
),
|
||||
BorrowKind::Fake => PlaceContext::NonMutatingUse(
|
||||
BorrowKind::Fake(_) => PlaceContext::NonMutatingUse(
|
||||
NonMutatingUseContext::FakeBorrow
|
||||
),
|
||||
BorrowKind::Mut { .. } =>
|
||||
@ -1284,6 +1284,8 @@ pub enum NonMutatingUseContext {
|
||||
/// Shared borrow.
|
||||
SharedBorrow,
|
||||
/// 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,
|
||||
/// AddressOf for *const pointer.
|
||||
AddressOf,
|
||||
|
@ -642,7 +642,7 @@ fn walk_(&self, it: &mut impl FnMut(&Pat<'tcx>) -> bool) {
|
||||
AscribeUserType { subpattern, .. }
|
||||
| Binding { subpattern: Some(subpattern), .. }
|
||||
| Deref { subpattern }
|
||||
| DerefPattern { subpattern }
|
||||
| DerefPattern { subpattern, .. }
|
||||
| InlineConstant { subpattern, .. } => subpattern.walk_(it),
|
||||
Leaf { subpatterns } | Variant { subpatterns, .. } => {
|
||||
subpatterns.iter().for_each(|field| field.pattern.walk_(it))
|
||||
@ -760,6 +760,7 @@ pub enum PatKind<'tcx> {
|
||||
/// Deref pattern, written `box P` for now.
|
||||
DerefPattern {
|
||||
subpattern: Box<Pat<'tcx>>,
|
||||
mutability: hir::Mutability,
|
||||
},
|
||||
|
||||
/// One of the following:
|
||||
@ -1166,7 +1167,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
}
|
||||
write!(f, "{subpattern}")
|
||||
}
|
||||
PatKind::DerefPattern { ref subpattern } => {
|
||||
PatKind::DerefPattern { ref subpattern, .. } => {
|
||||
write!(f, "deref!({subpattern})")
|
||||
}
|
||||
PatKind::Constant { value } => write!(f, "{value}"),
|
||||
|
@ -229,7 +229,7 @@ pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
|
||||
match &pat.kind {
|
||||
AscribeUserType { subpattern, ascription: _ }
|
||||
| Deref { subpattern }
|
||||
| DerefPattern { subpattern }
|
||||
| DerefPattern { subpattern, .. }
|
||||
| Binding { subpattern: Some(subpattern), .. } => visitor.visit_pat(subpattern),
|
||||
Binding { .. } | Wild | Never | Error(_) => {}
|
||||
Variant { subpatterns, adt_def: _, args: _, variant_index: _ } | Leaf { subpatterns } => {
|
||||
|
@ -279,24 +279,29 @@ pub fn suggest_constraining_type_params<'a>(
|
||||
constraint.sort();
|
||||
constraint.dedup();
|
||||
let constraint = constraint.join(" + ");
|
||||
let mut suggest_restrict = |span, bound_list_non_empty| {
|
||||
suggestions.push((
|
||||
span,
|
||||
if span_to_replace.is_some() {
|
||||
constraint.clone()
|
||||
} else if constraint.starts_with('<') {
|
||||
constraint.to_string()
|
||||
} else if bound_list_non_empty {
|
||||
format!(" + {constraint}")
|
||||
} else {
|
||||
format!(" {constraint}")
|
||||
},
|
||||
SuggestChangingConstraintsMessage::RestrictBoundFurther,
|
||||
))
|
||||
let mut suggest_restrict = |span, bound_list_non_empty, open_paren_sp| {
|
||||
let suggestion = if span_to_replace.is_some() {
|
||||
constraint.clone()
|
||||
} else if constraint.starts_with('<') {
|
||||
constraint.to_string()
|
||||
} else if bound_list_non_empty {
|
||||
format!(" + {constraint}")
|
||||
} else {
|
||||
format!(" {constraint}")
|
||||
};
|
||||
|
||||
use 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 {
|
||||
suggest_restrict(span, true);
|
||||
suggest_restrict(span, true, None);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -327,8 +332,8 @@ pub fn suggest_constraining_type_params<'a>(
|
||||
// --
|
||||
// |
|
||||
// replace with: `T: Bar +`
|
||||
if let Some(span) = generics.bounds_span_for_suggestions(param.def_id) {
|
||||
suggest_restrict(span, true);
|
||||
if let Some((span, open_paren_sp)) = generics.bounds_span_for_suggestions(param.def_id) {
|
||||
suggest_restrict(span, true, open_paren_sp);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -7,10 +7,8 @@
|
||||
GenericArgs, GenericArgsRef, Ty, UserArgs,
|
||||
},
|
||||
};
|
||||
use rustc_data_structures::{
|
||||
fx::FxIndexMap,
|
||||
unord::{ExtendUnord, UnordItems, UnordSet},
|
||||
};
|
||||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::unord::{ExtendUnord, UnordItems, UnordSet};
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir::{
|
||||
self as hir,
|
||||
@ -201,8 +199,7 @@ pub struct TypeckResults<'tcx> {
|
||||
|
||||
/// Stores the predicates that apply on coroutine witness types.
|
||||
/// formatting modified file tests/ui/coroutine/retain-resume-ref.rs
|
||||
pub coroutine_interior_predicates:
|
||||
LocalDefIdMap<Vec<(ty::Predicate<'tcx>, ObligationCause<'tcx>)>>,
|
||||
pub coroutine_stalled_predicates: FxIndexSet<(ty::Predicate<'tcx>, ObligationCause<'tcx>)>,
|
||||
|
||||
/// We sometimes treat byte string literals (which are of type `&[u8; N]`)
|
||||
/// as `&[u8]`, depending on the pattern in which they are used.
|
||||
@ -243,7 +240,7 @@ pub fn new(hir_owner: OwnerId) -> TypeckResults<'tcx> {
|
||||
closure_min_captures: Default::default(),
|
||||
closure_fake_reads: Default::default(),
|
||||
rvalue_scopes: Default::default(),
|
||||
coroutine_interior_predicates: Default::default(),
|
||||
coroutine_stalled_predicates: Default::default(),
|
||||
treat_byte_string_as_slice: Default::default(),
|
||||
closure_size_eval: Default::default(),
|
||||
offset_of_data: Default::default(),
|
||||
@ -451,7 +448,7 @@ pub fn skipped_ref_pats_mut(&mut self) -> LocalSetInContextMut<'_> {
|
||||
/// This is computed from the typeck results since we want to make
|
||||
/// sure to apply any match-ergonomics adjustments, which we cannot
|
||||
/// 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;
|
||||
pat.walk(|pat| {
|
||||
if let hir::PatKind::Binding(_, id, _, _) = pat.kind
|
||||
|
@ -685,7 +685,7 @@ fn add_fake_borrows_of_base(
|
||||
fake_borrow_temp.into(),
|
||||
Rvalue::Ref(
|
||||
tcx.lifetimes.re_erased,
|
||||
BorrowKind::Fake,
|
||||
BorrowKind::Fake(FakeBorrowKind::Shallow),
|
||||
Place { local: base_place.local, projection },
|
||||
),
|
||||
);
|
||||
|
@ -10,10 +10,7 @@
|
||||
use crate::build::ForGuard::{self, OutsideGuard, RefWithinGuard};
|
||||
use crate::build::{BlockAnd, BlockAndExtension, Builder};
|
||||
use crate::build::{GuardFrame, GuardFrameLocal, LocalsForNode};
|
||||
use rustc_data_structures::{
|
||||
fx::{FxHashSet, FxIndexMap, FxIndexSet},
|
||||
stack::ensure_sufficient_stack,
|
||||
};
|
||||
use rustc_data_structures::{fx::FxIndexMap, stack::ensure_sufficient_stack};
|
||||
use rustc_hir::{BindingMode, ByRef};
|
||||
use rustc_middle::middle::region;
|
||||
use rustc_middle::mir::{self, *};
|
||||
@ -211,7 +208,7 @@ fn then_else_break_inner(
|
||||
/// 2. Create the decision tree ([Builder::lower_match_tree]).
|
||||
/// 3. Determine the fake borrows that are needed from the places that were
|
||||
/// 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]).
|
||||
///
|
||||
/// ## False edges
|
||||
@ -380,12 +377,19 @@ fn lower_match_tree<'pat>(
|
||||
match_start_span: Span,
|
||||
match_has_guard: bool,
|
||||
candidates: &mut [&mut Candidate<'pat, 'tcx>],
|
||||
) -> Vec<(Place<'tcx>, Local)> {
|
||||
// The set of places that we are creating fake borrows of. If there are
|
||||
// no match guards then we don't need any fake borrows, so don't track
|
||||
// them.
|
||||
let fake_borrows = match_has_guard
|
||||
.then(|| util::FakeBorrowCollector::collect_fake_borrows(self, candidates));
|
||||
) -> Vec<(Place<'tcx>, Local, FakeBorrowKind)> {
|
||||
// The set of places that we are creating fake borrows of. If there are no match guards then
|
||||
// we don't need any fake borrows, so don't track them.
|
||||
let fake_borrows: Vec<(Place<'tcx>, Local, FakeBorrowKind)> = if match_has_guard {
|
||||
util::collect_fake_borrows(
|
||||
self,
|
||||
candidates,
|
||||
scrutinee_span,
|
||||
scrutinee_place_builder.base(),
|
||||
)
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
|
||||
// See the doc comment on `match_candidates` for why we have an
|
||||
// otherwise block. Match checking will ensure this is actually
|
||||
@ -439,11 +443,7 @@ fn lower_match_tree<'pat>(
|
||||
});
|
||||
}
|
||||
|
||||
if let Some(ref borrows) = fake_borrows {
|
||||
self.calculate_fake_borrows(borrows, scrutinee_span)
|
||||
} else {
|
||||
Vec::new()
|
||||
}
|
||||
fake_borrows
|
||||
}
|
||||
|
||||
/// Lower the bindings, guards and arm bodies of a `match` expression.
|
||||
@ -459,7 +459,7 @@ fn lower_match_arms(
|
||||
scrutinee_span: Span,
|
||||
arm_candidates: Vec<(&'_ Arm<'tcx>, Candidate<'_, 'tcx>)>,
|
||||
outer_source_info: SourceInfo,
|
||||
fake_borrow_temps: Vec<(Place<'tcx>, Local)>,
|
||||
fake_borrow_temps: Vec<(Place<'tcx>, Local, FakeBorrowKind)>,
|
||||
) -> BlockAnd<()> {
|
||||
let arm_end_blocks: Vec<_> = arm_candidates
|
||||
.into_iter()
|
||||
@ -543,7 +543,7 @@ fn bind_pattern(
|
||||
&mut self,
|
||||
outer_source_info: SourceInfo,
|
||||
candidate: Candidate<'_, 'tcx>,
|
||||
fake_borrow_temps: &[(Place<'tcx>, Local)],
|
||||
fake_borrow_temps: &[(Place<'tcx>, Local, FakeBorrowKind)],
|
||||
scrutinee_span: Span,
|
||||
arm_match_scope: Option<(&Arm<'tcx>, region::Scope)>,
|
||||
storages_alive: bool,
|
||||
@ -940,7 +940,7 @@ pub(super) fn visit_primary_bindings(
|
||||
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);
|
||||
}
|
||||
|
||||
@ -1165,6 +1165,7 @@ enum TestCase<'pat, 'tcx> {
|
||||
Constant { value: mir::Const<'tcx> },
|
||||
Range(&'pat PatRange<'tcx>),
|
||||
Slice { len: usize, variable_length: bool },
|
||||
Deref { temp: Place<'tcx>, mutability: Mutability },
|
||||
Or { pats: Box<[FlatPat<'pat, 'tcx>]> },
|
||||
}
|
||||
|
||||
@ -1224,6 +1225,13 @@ enum TestKind<'tcx> {
|
||||
|
||||
/// Test that the length of the slice is equal to `len`.
|
||||
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.
|
||||
@ -1905,81 +1913,6 @@ fn test_candidates<'pat, 'b, 'c>(
|
||||
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 @@ fn bind_and_guard_matched_candidate<'pat>(
|
||||
&mut self,
|
||||
candidate: Candidate<'pat, 'tcx>,
|
||||
parent_data: &[PatternExtraData<'tcx>],
|
||||
fake_borrows: &[(Place<'tcx>, Local)],
|
||||
fake_borrows: &[(Place<'tcx>, Local, FakeBorrowKind)],
|
||||
scrutinee_span: Span,
|
||||
arm_match_scope: Option<(&Arm<'tcx>, region::Scope)>,
|
||||
schedule_drops: bool,
|
||||
@ -2174,8 +2107,8 @@ fn bind_and_guard_matched_candidate<'pat>(
|
||||
|
||||
let re_erased = tcx.lifetimes.re_erased;
|
||||
let scrutinee_source_info = self.source_info(scrutinee_span);
|
||||
for &(place, temp) in fake_borrows {
|
||||
let borrow = Rvalue::Ref(re_erased, BorrowKind::Fake, place);
|
||||
for &(place, temp, kind) in fake_borrows {
|
||||
let borrow = Rvalue::Ref(re_erased, BorrowKind::Fake(kind), place);
|
||||
self.cfg.push_assign(block, scrutinee_source_info, Place::from(temp), borrow);
|
||||
}
|
||||
|
||||
@ -2198,7 +2131,7 @@ fn bind_and_guard_matched_candidate<'pat>(
|
||||
let guard_frame = self.guard_context.pop().unwrap();
|
||||
debug!("Exiting guard building context with locals: {:?}", guard_frame);
|
||||
|
||||
for &(_, temp) in fake_borrows {
|
||||
for &(_, temp, _) in fake_borrows {
|
||||
let cause = FakeReadCause::ForMatchGuard;
|
||||
self.cfg.push_fake_read(post_guard_block, guard_end, cause, Place::from(temp));
|
||||
}
|
||||
|
@ -42,6 +42,8 @@ pub(super) fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<
|
||||
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::Irrefutable { .. } => span_bug!(
|
||||
@ -143,34 +145,18 @@ pub(super) fn perform_test(
|
||||
);
|
||||
}
|
||||
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 = 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();
|
||||
self.cfg.push_assign(
|
||||
// `let ref_str: &str = <String as Deref>::deref(&place);`
|
||||
self.call_deref(
|
||||
block,
|
||||
source_info,
|
||||
ref_string,
|
||||
Rvalue::Ref(re_erased, BorrowKind::Shared, place),
|
||||
);
|
||||
self.cfg.terminate(
|
||||
block,
|
||||
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,
|
||||
},
|
||||
eq_block,
|
||||
place,
|
||||
Mutability::Not,
|
||||
ty,
|
||||
ref_str,
|
||||
test.span,
|
||||
);
|
||||
self.non_scalar_compare(
|
||||
eq_block,
|
||||
@ -270,9 +256,66 @@ pub(super) fn perform_test(
|
||||
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
|
||||
fn compare(
|
||||
&mut self,
|
||||
@ -660,13 +703,21 @@ pub(super) fn sort_candidate(
|
||||
}
|
||||
}
|
||||
|
||||
(TestKind::Deref { temp: test_temp, .. }, TestCase::Deref { temp, .. })
|
||||
if test_temp == temp =>
|
||||
{
|
||||
fully_matched = true;
|
||||
Some(TestBranch::Success)
|
||||
}
|
||||
|
||||
(
|
||||
TestKind::Switch { .. }
|
||||
| TestKind::SwitchInt { .. }
|
||||
| TestKind::If
|
||||
| TestKind::Len { .. }
|
||||
| TestKind::Range { .. }
|
||||
| TestKind::Eq { .. },
|
||||
| TestKind::Eq { .. }
|
||||
| TestKind::Deref { .. },
|
||||
_,
|
||||
) => {
|
||||
fully_matched = false;
|
||||
|
@ -1,12 +1,13 @@
|
||||
use crate::build::expr::as_place::{PlaceBase, PlaceBuilder};
|
||||
use crate::build::matches::{Binding, Candidate, FlatPat, MatchPair, TestCase};
|
||||
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_middle::mir::*;
|
||||
use rustc_middle::thir::{self, *};
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::TypeVisitableExt;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_span::Span;
|
||||
|
||||
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
pub(crate) fn field_match_pairs<'pat>(
|
||||
@ -249,10 +250,15 @@ pub(in crate::build) fn new(
|
||||
default_irrefutable()
|
||||
}
|
||||
|
||||
PatKind::DerefPattern { .. } => {
|
||||
// FIXME(deref_patterns)
|
||||
// Treat it like a wildcard for now.
|
||||
default_irrefutable()
|
||||
PatKind::DerefPattern { ref subpattern, mutability } => {
|
||||
// Create a new temporary for each deref pattern.
|
||||
// FIXME(deref_patterns): dedup temporaries to avoid multiple `deref()` calls?
|
||||
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 @@ pub(in crate::build) fn new(
|
||||
|
||||
pub(super) struct FakeBorrowCollector<'a, '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> {
|
||||
pub(super) fn collect_fake_borrows(
|
||||
cx: &'a mut Builder<'b, 'tcx>,
|
||||
candidates: &[&mut Candidate<'_, 'tcx>],
|
||||
) -> FxIndexSet<Place<'tcx>> {
|
||||
let mut collector = Self { cx, fake_borrows: FxIndexSet::default() };
|
||||
for candidate in candidates.iter() {
|
||||
collector.visit_candidate(candidate);
|
||||
// Fake borrow this place and its dereference prefixes.
|
||||
fn fake_borrow(&mut self, place: Place<'tcx>, kind: FakeBorrowKind) {
|
||||
if self.fake_borrows.get(&place).is_some_and(|k| *k >= kind) {
|
||||
return;
|
||||
}
|
||||
self.fake_borrows.insert(place, kind);
|
||||
// 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>) {
|
||||
@ -300,10 +390,27 @@ fn visit_match_pair(&mut self, match_pair: &MatchPair<'_, 'tcx>) {
|
||||
for flat_pat in pats.iter() {
|
||||
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 {
|
||||
// Insert a Shallow borrow of any place that is switched on.
|
||||
if let Some(place) = match_pair.place {
|
||||
self.fake_borrows.insert(place);
|
||||
self.fake_borrow(place, FakeBorrowKind::Shallow);
|
||||
}
|
||||
|
||||
for subpair in &match_pair.subpairs {
|
||||
@ -313,6 +420,14 @@ fn visit_match_pair(&mut self, match_pair: &MatchPair<'_, '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
|
||||
// behind a dereference projection.
|
||||
//
|
||||
@ -329,13 +444,13 @@ fn visit_binding(&mut self, Binding { source, .. }: &Binding<'tcx>) {
|
||||
// y if { y == 1 && (x = &2) == () } => y,
|
||||
// _ => 3,
|
||||
// }
|
||||
if let Some(i) = source.projection.iter().rposition(|elem| elem == ProjectionElem::Deref) {
|
||||
let proj_base = &source.projection[..i];
|
||||
self.fake_borrows.insert(Place {
|
||||
local: source.local,
|
||||
projection: self.cx.tcx.mk_place_elems(proj_base),
|
||||
});
|
||||
}
|
||||
//
|
||||
// We don't just fake borrow the whole place because this is allowed:
|
||||
// match u {
|
||||
// _ if { u = true; false } => (),
|
||||
// x => (),
|
||||
// }
|
||||
self.fake_borrow_deref_prefixes(*source, FakeBorrowKind::Shallow);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -513,7 +513,7 @@ fn visit_expr(&mut self, expr: &'a Expr<'tcx>) {
|
||||
visit::walk_expr(&mut visitor, expr);
|
||||
if visitor.found {
|
||||
match borrow_kind {
|
||||
BorrowKind::Fake | BorrowKind::Shared
|
||||
BorrowKind::Fake(_) | BorrowKind::Shared
|
||||
if !self.thir[arg].ty.is_freeze(self.tcx, self.param_env) =>
|
||||
{
|
||||
self.requires_unsafe(expr.span, BorrowOfLayoutConstrainedField)
|
||||
@ -521,7 +521,7 @@ fn visit_expr(&mut self, expr: &'a Expr<'tcx>) {
|
||||
BorrowKind::Mut { .. } => {
|
||||
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>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
_f: F,
|
||||
_f: &F,
|
||||
) {
|
||||
diag.span_note(self.signature_span, fluent::mir_build_unsafe_fn_safe_body);
|
||||
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>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
_f: F,
|
||||
_f: &F,
|
||||
) {
|
||||
diag.arg("ty", self.ty);
|
||||
let mut spans = MultiSpan::from(self.adt_def_span);
|
||||
|
@ -264,7 +264,9 @@ fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tc
|
||||
}
|
||||
|
||||
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) => {
|
||||
PatKind::Deref { subpattern: self.lower_pattern(subpattern) }
|
||||
|
@ -688,7 +688,7 @@ fn print_pat_kind(&mut self, pat_kind: &PatKind<'tcx>, depth_lvl: usize) {
|
||||
self.print_pat(subpattern, depth_lvl + 2);
|
||||
print_indented!(self, "}", depth_lvl + 1);
|
||||
}
|
||||
PatKind::DerefPattern { subpattern } => {
|
||||
PatKind::DerefPattern { subpattern, .. } => {
|
||||
print_indented!(self, "DerefPattern { ", depth_lvl + 1);
|
||||
print_indented!(self, "subpattern:", depth_lvl + 2);
|
||||
self.print_pat(subpattern, depth_lvl + 2);
|
||||
|
@ -102,7 +102,7 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
|
||||
}
|
||||
|
||||
Rvalue::Cast(..)
|
||||
| Rvalue::Ref(_, BorrowKind::Fake, _)
|
||||
| Rvalue::Ref(_, BorrowKind::Fake(_), _)
|
||||
| Rvalue::ShallowInitBox(..)
|
||||
| Rvalue::Use(..)
|
||||
| Rvalue::ThreadLocalRef(..)
|
||||
|
@ -29,7 +29,7 @@ fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
for statement in basic_block.statements.iter_mut() {
|
||||
match statement.kind {
|
||||
StatementKind::AscribeUserType(..)
|
||||
| StatementKind::Assign(box (_, Rvalue::Ref(_, BorrowKind::Fake, _)))
|
||||
| StatementKind::Assign(box (_, Rvalue::Ref(_, BorrowKind::Fake(_), _)))
|
||||
| StatementKind::Coverage(
|
||||
// These kinds of coverage statements are markers inserted during
|
||||
// MIR building, and are not needed after InstrumentCoverage.
|
||||
|
@ -80,6 +80,10 @@
|
||||
use rustc_span::Span;
|
||||
use rustc_target::abi::{FieldIdx, VariantIdx};
|
||||
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};
|
||||
|
||||
pub struct StateTransform;
|
||||
@ -1584,10 +1588,46 @@ pub(crate) fn mir_coroutine_witnesses<'tcx>(
|
||||
let (_, coroutine_layout, _) = compute_layout(liveness_info, body);
|
||||
|
||||
check_suspend_tys(tcx, &coroutine_layout, body);
|
||||
check_field_tys_sized(tcx, &coroutine_layout, def_id);
|
||||
|
||||
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 {
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
let Some(old_yield_ty) = body.yield_ty() else {
|
||||
|
@ -384,7 +384,7 @@ fn validate_ref(&mut self, kind: BorrowKind, place: &Place<'tcx>) -> Result<(),
|
||||
match kind {
|
||||
// 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.
|
||||
BorrowKind::Fake | BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } => {
|
||||
BorrowKind::Fake(_) | BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } => {
|
||||
return Err(Unpromotable);
|
||||
}
|
||||
|
||||
|
@ -1472,7 +1472,7 @@ impl Subdiagnostic for FnTraitMissingParen {
|
||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
_: F,
|
||||
_: &F,
|
||||
) {
|
||||
diag.span_label(self.span, crate::fluent_generated::parse_fn_trait_missing_paren);
|
||||
let applicability = if self.machine_applicable {
|
||||
|
@ -1765,7 +1765,7 @@ impl Subdiagnostic for UnusedVariableStringInterp {
|
||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
_f: F,
|
||||
_f: &F,
|
||||
) {
|
||||
diag.span_label(self.lit, crate::fluent_generated::passes_maybe_string_interpolation);
|
||||
diag.multipart_suggestion(
|
||||
|
@ -65,7 +65,7 @@ impl<'tcx> Subdiagnostic for Overlap<'tcx> {
|
||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
_: F,
|
||||
_: &F,
|
||||
) {
|
||||
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>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
_: F,
|
||||
_: &F,
|
||||
) {
|
||||
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_span::{
|
||||
symbol::{Ident, Symbol},
|
||||
@ -907,6 +907,8 @@ pub(crate) struct ExplicitAnonymousLivetimeReportError {
|
||||
pub(crate) struct ImplicitElidedLifetimeNotAllowedHere {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
#[subdiagnostic]
|
||||
pub(crate) subdiag: ElidedLifetimeInPathSubdiag,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
@ -1883,20 +1883,18 @@ fn resolve_elided_lifetimes_in_path(
|
||||
// async fn foo(_: std::cell::Ref<u32>) { ... }
|
||||
LifetimeRibKind::AnonymousCreateParameter { report_in_path: true, .. }
|
||||
| LifetimeRibKind::AnonymousWarn(_) => {
|
||||
let mut err =
|
||||
self.r.dcx().create_err(errors::ImplicitElidedLifetimeNotAllowedHere {
|
||||
span: path_span,
|
||||
});
|
||||
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(),
|
||||
&mut err,
|
||||
expected_lifetimes,
|
||||
path_span,
|
||||
!segment.has_generic_args,
|
||||
elided_lifetime_span,
|
||||
);
|
||||
err.emit();
|
||||
self.r.dcx().emit_err(errors::ImplicitElidedLifetimeNotAllowedHere {
|
||||
span: path_span,
|
||||
subdiag,
|
||||
});
|
||||
should_lint = false;
|
||||
|
||||
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![];
|
||||
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| {
|
||||
|
@ -52,6 +52,7 @@ pub fn from_cli_opt(
|
||||
triple: &TargetTriple,
|
||||
early_dcx: &EarlyDiagCtxt,
|
||||
path: &str,
|
||||
is_unstable_enabled: bool,
|
||||
) -> Self {
|
||||
let (kind, path) = if let Some(stripped) = path.strip_prefix("native=") {
|
||||
(PathKind::Native, stripped)
|
||||
@ -68,6 +69,14 @@ pub fn from_cli_opt(
|
||||
};
|
||||
let dir = match path.strip_prefix("@RUSTC_BUILTIN") {
|
||||
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)
|
||||
}
|
||||
None => PathBuf::from(path),
|
||||
|
@ -229,7 +229,7 @@ fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
|
||||
use rustc_middle::mir::BorrowKind::*;
|
||||
match *self {
|
||||
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) },
|
||||
}
|
||||
}
|
||||
@ -247,6 +247,17 @@ fn stable(&self, _: &mut Tables<'_>) -> Self::T {
|
||||
}
|
||||
}
|
||||
|
||||
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> {
|
||||
type T = stable_mir::mir::NullOp;
|
||||
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
|
||||
|
@ -14,7 +14,7 @@
|
||||
use rustc_data_structures::unhash::UnhashMap;
|
||||
use std::fs;
|
||||
use std::io::{self, BorrowedBuf, Read};
|
||||
use std::path::{self};
|
||||
use std::path;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
@ -104,7 +104,7 @@ impl Subdiagnostic for AdjustSignatureBorrow {
|
||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
_f: F,
|
||||
_f: &F,
|
||||
) {
|
||||
match self {
|
||||
AdjustSignatureBorrow::Borrow { to_borrow } => {
|
||||
|
@ -2938,17 +2938,28 @@ fn maybe_suggest_unsized_generics(&self, err: &mut Diag<'_>, span: Span, node: N
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
|
||||
// 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)
|
||||
{
|
||||
(s, " +")
|
||||
let (span, separator, open_paren_sp) =
|
||||
if let Some((s, open_paren_sp)) = generics.bounds_span_for_suggestions(param.def_id) {
|
||||
(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 {
|
||||
(param.name.ident().span.shrink_to_hi(), ":")
|
||||
};
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
suggs.push((span, suggestion));
|
||||
}
|
||||
|
||||
err.multipart_suggestion_verbose(
|
||||
"consider relaxing the implicit `Sized` restriction",
|
||||
format!("{separator} ?Sized"),
|
||||
suggs,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
@ -867,11 +867,9 @@ pub enum BorrowKind {
|
||||
/// Data must be immutable and is aliasable.
|
||||
Shared,
|
||||
|
||||
/// 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`.
|
||||
Fake,
|
||||
/// An immutable, aliasable borrow that is discarded after borrow-checking. Can behave either
|
||||
/// like a normal shared borrow or like a special shallow borrow (see [`FakeBorrowKind`]).
|
||||
Fake(FakeBorrowKind),
|
||||
|
||||
/// Data is mutable and not aliasable.
|
||||
Mut {
|
||||
@ -886,7 +884,7 @@ pub fn to_mutable_lossy(self) -> Mutability {
|
||||
BorrowKind::Mut { .. } => Mutability::Mut,
|
||||
BorrowKind::Shared => Mutability::Not,
|
||||
// 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,
|
||||
}
|
||||
|
||||
#[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)]
|
||||
pub enum Mutability {
|
||||
Not,
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
use super::{AssertMessage, BinOp, TerminatorKind};
|
||||
|
||||
use super::BorrowKind;
|
||||
use super::{BorrowKind, FakeBorrowKind};
|
||||
|
||||
impl Display for Ty {
|
||||
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) => {
|
||||
let kind = match borrowkind {
|
||||
BorrowKind::Shared => "&",
|
||||
BorrowKind::Fake => "&fake ",
|
||||
BorrowKind::Fake(FakeBorrowKind::Deep) => "&fake ",
|
||||
BorrowKind::Fake(FakeBorrowKind::Shallow) => "&fake shallow ",
|
||||
BorrowKind::Mut { .. } => "&mut ",
|
||||
};
|
||||
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.
|
||||
/// 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,
|
||||
/// even though `GlobalAlloc` requires that all memory requests
|
||||
|
@ -635,7 +635,16 @@ fn println_condition(condition: Condition) {
|
||||
let libs = matches
|
||||
.opt_strs("L")
|
||||
.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();
|
||||
|
||||
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 _1: (i32, i32);
|
||||
let mut _2: std::option::Option<i32>;
|
||||
let mut _3: isize;
|
||||
let mut _4: &std::option::Option<i32>;
|
||||
let mut _3: &std::option::Option<i32>;
|
||||
let mut _4: isize;
|
||||
let _5: i32;
|
||||
let _6: &i32;
|
||||
let mut _7: bool;
|
||||
@ -27,8 +27,8 @@ fn full_tested_match() -> () {
|
||||
StorageLive(_2);
|
||||
_2 = Option::<i32>::Some(const 42_i32);
|
||||
PlaceMention(_2);
|
||||
_3 = discriminant(_2);
|
||||
switchInt(move _3) -> [0: bb5, 1: bb2, otherwise: bb1];
|
||||
_4 = discriminant(_2);
|
||||
switchInt(move _4) -> [0: bb5, 1: bb2, otherwise: bb1];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
@ -60,7 +60,7 @@ fn full_tested_match() -> () {
|
||||
bb7: {
|
||||
StorageLive(_6);
|
||||
_6 = &((_2 as Some).0: i32);
|
||||
_4 = &fake _2;
|
||||
_3 = &fake shallow _2;
|
||||
StorageLive(_7);
|
||||
_7 = guard() -> [return: bb8, unwind: bb16];
|
||||
}
|
||||
@ -71,7 +71,7 @@ fn full_tested_match() -> () {
|
||||
|
||||
bb9: {
|
||||
StorageDead(_7);
|
||||
FakeRead(ForMatchGuard, _4);
|
||||
FakeRead(ForMatchGuard, _3);
|
||||
FakeRead(ForGuardBinding, _6);
|
||||
StorageLive(_5);
|
||||
_5 = ((_2 as Some).0: i32);
|
||||
|
@ -4,8 +4,8 @@ fn full_tested_match2() -> () {
|
||||
let mut _0: ();
|
||||
let mut _1: (i32, i32);
|
||||
let mut _2: std::option::Option<i32>;
|
||||
let mut _3: isize;
|
||||
let mut _4: &std::option::Option<i32>;
|
||||
let mut _3: &std::option::Option<i32>;
|
||||
let mut _4: isize;
|
||||
let _5: i32;
|
||||
let _6: &i32;
|
||||
let mut _7: bool;
|
||||
@ -27,8 +27,8 @@ fn full_tested_match2() -> () {
|
||||
StorageLive(_2);
|
||||
_2 = Option::<i32>::Some(const 42_i32);
|
||||
PlaceMention(_2);
|
||||
_3 = discriminant(_2);
|
||||
switchInt(move _3) -> [0: bb5, 1: bb2, otherwise: bb1];
|
||||
_4 = discriminant(_2);
|
||||
switchInt(move _4) -> [0: bb5, 1: bb2, otherwise: bb1];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
@ -66,7 +66,7 @@ fn full_tested_match2() -> () {
|
||||
bb7: {
|
||||
StorageLive(_6);
|
||||
_6 = &((_2 as Some).0: i32);
|
||||
_4 = &fake _2;
|
||||
_3 = &fake shallow _2;
|
||||
StorageLive(_7);
|
||||
_7 = guard() -> [return: bb8, unwind: bb16];
|
||||
}
|
||||
@ -77,7 +77,7 @@ fn full_tested_match2() -> () {
|
||||
|
||||
bb9: {
|
||||
StorageDead(_7);
|
||||
FakeRead(ForMatchGuard, _4);
|
||||
FakeRead(ForMatchGuard, _3);
|
||||
FakeRead(ForGuardBinding, _6);
|
||||
StorageLive(_5);
|
||||
_5 = ((_2 as Some).0: i32);
|
||||
|
@ -4,9 +4,9 @@ fn main() -> () {
|
||||
let mut _0: ();
|
||||
let mut _1: 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 _5: &std::option::Option<i32>;
|
||||
let mut _5: isize;
|
||||
let _6: i32;
|
||||
let _7: &i32;
|
||||
let mut _8: bool;
|
||||
@ -38,8 +38,8 @@ fn main() -> () {
|
||||
StorageLive(_2);
|
||||
_2 = Option::<i32>::Some(const 1_i32);
|
||||
PlaceMention(_2);
|
||||
_4 = discriminant(_2);
|
||||
switchInt(move _4) -> [1: bb8, otherwise: bb2];
|
||||
_5 = discriminant(_2);
|
||||
switchInt(move _5) -> [1: bb8, otherwise: bb2];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
@ -52,8 +52,8 @@ fn main() -> () {
|
||||
}
|
||||
|
||||
bb3: {
|
||||
_3 = discriminant(_2);
|
||||
switchInt(move _3) -> [1: bb6, otherwise: bb4];
|
||||
_4 = discriminant(_2);
|
||||
switchInt(move _4) -> [1: bb6, otherwise: bb4];
|
||||
}
|
||||
|
||||
bb4: {
|
||||
@ -87,7 +87,7 @@ fn main() -> () {
|
||||
bb10: {
|
||||
StorageLive(_7);
|
||||
_7 = &((_2 as Some).0: i32);
|
||||
_5 = &fake _2;
|
||||
_3 = &fake shallow _2;
|
||||
StorageLive(_8);
|
||||
_8 = guard() -> [return: bb11, unwind: bb24];
|
||||
}
|
||||
@ -98,7 +98,7 @@ fn main() -> () {
|
||||
|
||||
bb12: {
|
||||
StorageDead(_8);
|
||||
FakeRead(ForMatchGuard, _5);
|
||||
FakeRead(ForMatchGuard, _3);
|
||||
FakeRead(ForGuardBinding, _7);
|
||||
StorageLive(_6);
|
||||
_6 = ((_2 as Some).0: i32);
|
||||
@ -129,7 +129,7 @@ fn main() -> () {
|
||||
bb16: {
|
||||
StorageLive(_11);
|
||||
_11 = &((_2 as Some).0: i32);
|
||||
_5 = &fake _2;
|
||||
_3 = &fake shallow _2;
|
||||
StorageLive(_12);
|
||||
StorageLive(_13);
|
||||
_13 = (*_11);
|
||||
@ -143,7 +143,7 @@ fn main() -> () {
|
||||
bb18: {
|
||||
StorageDead(_13);
|
||||
StorageDead(_12);
|
||||
FakeRead(ForMatchGuard, _5);
|
||||
FakeRead(ForMatchGuard, _3);
|
||||
FakeRead(ForGuardBinding, _11);
|
||||
StorageLive(_10);
|
||||
_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 _4: &str;
|
||||
let mut _5: bool;
|
||||
let mut _6: bool;
|
||||
let mut _7: bool;
|
||||
let mut _8: &&str;
|
||||
let mut _9: &bool;
|
||||
let mut _6: &&str;
|
||||
let mut _7: &bool;
|
||||
let mut _8: bool;
|
||||
let mut _9: bool;
|
||||
let mut _10: bool;
|
||||
|
||||
bb0: {
|
||||
@ -23,7 +23,7 @@ fn constant_eq(_1: &str, _2: bool) -> u32 {
|
||||
StorageDead(_5);
|
||||
StorageDead(_4);
|
||||
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: {
|
||||
@ -52,7 +52,7 @@ fn constant_eq(_1: &str, _2: bool) -> u32 {
|
||||
}
|
||||
|
||||
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: {
|
||||
@ -64,16 +64,16 @@ fn constant_eq(_1: &str, _2: bool) -> u32 {
|
||||
}
|
||||
|
||||
bb10: {
|
||||
switchInt(move _6) -> [0: bb1, otherwise: bb8];
|
||||
switchInt(move _8) -> [0: bb1, otherwise: bb8];
|
||||
}
|
||||
|
||||
bb11: {
|
||||
switchInt(move _7) -> [0: bb7, otherwise: bb4];
|
||||
switchInt(move _9) -> [0: bb7, otherwise: bb4];
|
||||
}
|
||||
|
||||
bb12: {
|
||||
_8 = &fake (_3.0: &str);
|
||||
_9 = &fake (_3.1: bool);
|
||||
_6 = &fake shallow (_3.0: &str);
|
||||
_7 = &fake shallow (_3.1: bool);
|
||||
StorageLive(_10);
|
||||
_10 = const true;
|
||||
switchInt(move _10) -> [0: bb14, otherwise: bb13];
|
||||
@ -81,8 +81,8 @@ fn constant_eq(_1: &str, _2: bool) -> u32 {
|
||||
|
||||
bb13: {
|
||||
StorageDead(_10);
|
||||
FakeRead(ForMatchGuard, _8);
|
||||
FakeRead(ForMatchGuard, _9);
|
||||
FakeRead(ForMatchGuard, _6);
|
||||
FakeRead(ForMatchGuard, _7);
|
||||
_0 = const 1_u32;
|
||||
goto -> bb18;
|
||||
}
|
||||
|
@ -4,17 +4,17 @@ fn disjoint_ranges(_1: i32, _2: bool) -> u32 {
|
||||
debug x => _1;
|
||||
debug b => _2;
|
||||
let mut _0: u32;
|
||||
let mut _3: bool;
|
||||
let mut _3: &i32;
|
||||
let mut _4: bool;
|
||||
let mut _5: bool;
|
||||
let mut _6: bool;
|
||||
let mut _7: &i32;
|
||||
let mut _7: bool;
|
||||
let mut _8: bool;
|
||||
|
||||
bb0: {
|
||||
PlaceMention(_1);
|
||||
_5 = Le(const 0_i32, _1);
|
||||
switchInt(move _5) -> [0: bb3, otherwise: bb8];
|
||||
_6 = Le(const 0_i32, _1);
|
||||
switchInt(move _6) -> [0: bb3, otherwise: bb8];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
@ -27,8 +27,8 @@ fn disjoint_ranges(_1: i32, _2: bool) -> u32 {
|
||||
}
|
||||
|
||||
bb3: {
|
||||
_3 = Le(const 10_i32, _1);
|
||||
switchInt(move _3) -> [0: bb5, otherwise: bb7];
|
||||
_4 = Le(const 10_i32, _1);
|
||||
switchInt(move _4) -> [0: bb5, otherwise: bb7];
|
||||
}
|
||||
|
||||
bb4: {
|
||||
@ -44,17 +44,17 @@ fn disjoint_ranges(_1: i32, _2: bool) -> u32 {
|
||||
}
|
||||
|
||||
bb7: {
|
||||
_4 = Le(_1, const 20_i32);
|
||||
switchInt(move _4) -> [0: bb5, otherwise: bb4];
|
||||
_5 = Le(_1, const 20_i32);
|
||||
switchInt(move _5) -> [0: bb5, otherwise: bb4];
|
||||
}
|
||||
|
||||
bb8: {
|
||||
_6 = Lt(_1, const 10_i32);
|
||||
switchInt(move _6) -> [0: bb3, otherwise: bb2];
|
||||
_7 = Lt(_1, const 10_i32);
|
||||
switchInt(move _7) -> [0: bb3, otherwise: bb2];
|
||||
}
|
||||
|
||||
bb9: {
|
||||
_7 = &fake _1;
|
||||
_3 = &fake shallow _1;
|
||||
StorageLive(_8);
|
||||
_8 = _2;
|
||||
switchInt(move _8) -> [0: bb11, otherwise: bb10];
|
||||
@ -62,7 +62,7 @@ fn disjoint_ranges(_1: i32, _2: bool) -> u32 {
|
||||
|
||||
bb10: {
|
||||
StorageDead(_8);
|
||||
FakeRead(ForMatchGuard, _7);
|
||||
FakeRead(ForMatchGuard, _3);
|
||||
_0 = const 0_u32;
|
||||
goto -> bb14;
|
||||
}
|
||||
|
@ -80,8 +80,8 @@
|
||||
_6 = &(_2.1: bool);
|
||||
StorageLive(_8);
|
||||
_8 = &(_2.2: std::string::String);
|
||||
- _3 = &fake (_2.0: bool);
|
||||
- _4 = &fake (_2.1: bool);
|
||||
- _3 = &fake shallow (_2.0: bool);
|
||||
- _4 = &fake shallow (_2.1: bool);
|
||||
StorageLive(_9);
|
||||
StorageLive(_10);
|
||||
_10 = _1;
|
||||
@ -137,8 +137,8 @@
|
||||
_6 = &(_2.0: bool);
|
||||
StorageLive(_8);
|
||||
_8 = &(_2.2: std::string::String);
|
||||
- _3 = &fake (_2.0: bool);
|
||||
- _4 = &fake (_2.1: bool);
|
||||
- _3 = &fake shallow (_2.0: bool);
|
||||
- _4 = &fake shallow (_2.1: bool);
|
||||
StorageLive(_12);
|
||||
StorageLive(_13);
|
||||
_13 = _1;
|
||||
|
@ -80,8 +80,8 @@
|
||||
_6 = &(_2.1: bool);
|
||||
StorageLive(_8);
|
||||
_8 = &(_2.2: std::string::String);
|
||||
- _3 = &fake (_2.0: bool);
|
||||
- _4 = &fake (_2.1: bool);
|
||||
- _3 = &fake shallow (_2.0: bool);
|
||||
- _4 = &fake shallow (_2.1: bool);
|
||||
StorageLive(_9);
|
||||
StorageLive(_10);
|
||||
_10 = _1;
|
||||
@ -137,8 +137,8 @@
|
||||
_6 = &(_2.0: bool);
|
||||
StorageLive(_8);
|
||||
_8 = &(_2.2: std::string::String);
|
||||
- _3 = &fake (_2.0: bool);
|
||||
- _4 = &fake (_2.1: bool);
|
||||
- _3 = &fake shallow (_2.0: bool);
|
||||
- _4 = &fake shallow (_2.1: bool);
|
||||
StorageLive(_12);
|
||||
StorageLive(_13);
|
||||
_13 = _1;
|
||||
|
@ -5,17 +5,17 @@
|
||||
debug x => _1;
|
||||
debug c => _2;
|
||||
let mut _0: i32;
|
||||
let mut _3: isize;
|
||||
let mut _4: &std::option::Option<&&i32>;
|
||||
let mut _3: &std::option::Option<&&i32>;
|
||||
let mut _4: &i32;
|
||||
let mut _5: &&i32;
|
||||
let mut _6: &&&i32;
|
||||
let mut _7: &i32;
|
||||
let mut _7: isize;
|
||||
let mut _8: bool;
|
||||
|
||||
bb0: {
|
||||
PlaceMention(_1);
|
||||
_3 = discriminant(_1);
|
||||
switchInt(move _3) -> [1: bb2, otherwise: bb1];
|
||||
_7 = discriminant(_1);
|
||||
switchInt(move _7) -> [1: bb2, otherwise: bb1];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
@ -33,10 +33,10 @@
|
||||
}
|
||||
|
||||
bb4: {
|
||||
- _4 = &fake _1;
|
||||
- _5 = &fake (*((_1 as Some).0: &&i32));
|
||||
- _6 = &fake ((_1 as Some).0: &&i32);
|
||||
- _7 = &fake (*(*((_1 as Some).0: &&i32)));
|
||||
- _3 = &fake shallow _1;
|
||||
- _4 = &fake shallow (*(*((_1 as Some).0: &&i32)));
|
||||
- _5 = &fake shallow (*((_1 as Some).0: &&i32));
|
||||
- _6 = &fake shallow ((_1 as Some).0: &&i32);
|
||||
+ nop;
|
||||
+ nop;
|
||||
+ nop;
|
||||
@ -48,10 +48,10 @@
|
||||
|
||||
bb5: {
|
||||
StorageDead(_8);
|
||||
- FakeRead(ForMatchGuard, _3);
|
||||
- FakeRead(ForMatchGuard, _4);
|
||||
- FakeRead(ForMatchGuard, _5);
|
||||
- FakeRead(ForMatchGuard, _6);
|
||||
- FakeRead(ForMatchGuard, _7);
|
||||
+ nop;
|
||||
+ nop;
|
||||
+ nop;
|
||||
|
@ -5,17 +5,17 @@
|
||||
debug x => _1;
|
||||
debug c => _2;
|
||||
let mut _0: i32;
|
||||
let mut _3: isize;
|
||||
let mut _4: &std::option::Option<&&i32>;
|
||||
let mut _3: &std::option::Option<&&i32>;
|
||||
let mut _4: &i32;
|
||||
let mut _5: &&i32;
|
||||
let mut _6: &&&i32;
|
||||
let mut _7: &i32;
|
||||
let mut _7: isize;
|
||||
let mut _8: bool;
|
||||
|
||||
bb0: {
|
||||
PlaceMention(_1);
|
||||
_3 = discriminant(_1);
|
||||
switchInt(move _3) -> [1: bb2, otherwise: bb1];
|
||||
_7 = discriminant(_1);
|
||||
switchInt(move _7) -> [1: bb2, otherwise: bb1];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
@ -33,10 +33,10 @@
|
||||
}
|
||||
|
||||
bb4: {
|
||||
- _4 = &fake _1;
|
||||
- _5 = &fake (*((_1 as Some).0: &&i32));
|
||||
- _6 = &fake ((_1 as Some).0: &&i32);
|
||||
- _7 = &fake (*(*((_1 as Some).0: &&i32)));
|
||||
- _3 = &fake shallow _1;
|
||||
- _4 = &fake shallow (*(*((_1 as Some).0: &&i32)));
|
||||
- _5 = &fake shallow (*((_1 as Some).0: &&i32));
|
||||
- _6 = &fake shallow ((_1 as Some).0: &&i32);
|
||||
+ nop;
|
||||
+ nop;
|
||||
+ nop;
|
||||
@ -48,10 +48,10 @@
|
||||
|
||||
bb5: {
|
||||
StorageDead(_8);
|
||||
- FakeRead(ForMatchGuard, _3);
|
||||
- FakeRead(ForMatchGuard, _4);
|
||||
- FakeRead(ForMatchGuard, _5);
|
||||
- FakeRead(ForMatchGuard, _6);
|
||||
- FakeRead(ForMatchGuard, _7);
|
||||
+ nop;
|
||||
+ nop;
|
||||
+ nop;
|
||||
|
@ -3,6 +3,11 @@ error[E0229]: associated type bindings are not allowed here
|
||||
|
|
||||
LL | type A: S<C<X = 0i32> = 34>;
|
||||
| ^^^^^^^^ 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
|
||||
--> $DIR/invalid_associated_const.rs:4:17
|
||||
@ -11,6 +16,10 @@ LL | type A: S<C<X = 0i32> = 34>;
|
||||
| ^^^^^^^^ 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<X = 0i32> = 34>;
|
||||
| ~~~~~~~~~~
|
||||
|
||||
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>;
|
||||
| ^^^^^^^^ 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
|
||||
--> $DIR/issue-102467.rs:7:17
|
||||
@ -11,6 +16,10 @@ LL | type A: S<C<X = 0i32> = 34>;
|
||||
| ^^^^^^^^ 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<X = 0i32> = 34>;
|
||||
| ~~~~~~~~~~
|
||||
|
||||
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>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
f: F,
|
||||
f: &F,
|
||||
) {
|
||||
diag.note("untranslatable diagnostic");
|
||||
//~^ 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>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
f: F,
|
||||
f: &F,
|
||||
) {
|
||||
diag.note(crate::fluent_generated::no_crate_note);
|
||||
}
|
||||
|
@ -827,3 +827,13 @@ struct PrimarySpanOnVec {
|
||||
//~| NOTE there must be exactly one primary 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>;
|
||||
| ^^^^^^^^ 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
|
||||
--> $DIR/issue-102335-const.rs:4:17
|
||||
@ -11,6 +16,10 @@ LL | type A: S<C<X = 0i32> = 34>;
|
||||
| ^^^^^^^^ 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<X = 0i32> = 34>;
|
||||
| ~~~~~~~~~~
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -1,5 +1,11 @@
|
||||
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
|
||||
}
|
||||
|
@ -1,17 +1,49 @@
|
||||
error[E0229]: associated type bindings are not allowed here
|
||||
--> $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
|
||||
|
|
||||
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
|
||||
--> $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
|
||||
|
|
||||
= 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`.
|
||||
|
@ -1,19 +1,125 @@
|
||||
// Test equality constraints on associated types. Check we get an error when an
|
||||
// equality constraint is used in a qualified path.
|
||||
|
||||
pub trait Foo {
|
||||
type A;
|
||||
fn boo(&self) -> <Self as Foo>::A;
|
||||
}
|
||||
// equality constraint is used in an invalid context
|
||||
|
||||
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;
|
||||
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
|
||||
|
||||
|
||||
|
||||
// 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() {}
|
||||
|
@ -1,9 +1,365 @@
|
||||
error[E0229]: associated type bindings are not allowed here
|
||||
--> $DIR/associated-types-eq-2.rs:16:30
|
||||
error[E0658]: associated const equality is incomplete
|
||||
--> $DIR/associated-types-eq-2.rs:76:10
|
||||
|
|
||||
LL | fn baz<I: Foo>(x: &<I as Foo<A=Bar>>::A) {}
|
||||
| ^^^^^ associated type not allowed here
|
||||
LL | impl Tr3<N
|
||||
| __________^
|
||||
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 {
|
||||
| ^^^^^ 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
|
||||
|
||||
|
@ -41,6 +41,11 @@ error[E0229]: associated type bindings are not allowed here
|
||||
|
|
||||
LL | impl Foo<N = const 3> for Bar {
|
||||
| ^^^^^^^^^^^ 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
|
||||
|
||||
|
@ -6,18 +6,18 @@
|
||||
|
||||
struct NonClone;
|
||||
|
||||
fn main() {
|
||||
fn test1() {
|
||||
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 || {
|
||||
yield;
|
||||
drop(copyable);
|
||||
};
|
||||
check_copy(&gen_copy_0);
|
||||
check_clone(&gen_copy_0);
|
||||
}
|
||||
|
||||
fn test2() {
|
||||
let copyable: u32 = 123;
|
||||
let gen_copy_1 = move || {
|
||||
/*
|
||||
let v = vec!['a'];
|
||||
@ -33,6 +33,10 @@ fn main() {
|
||||
};
|
||||
check_copy(&gen_copy_1);
|
||||
check_clone(&gen_copy_1);
|
||||
}
|
||||
|
||||
fn test3() {
|
||||
let clonable_0: Vec<u32> = Vec::new();
|
||||
let gen_clone_0 = move || {
|
||||
let v = vec!['a'];
|
||||
yield;
|
||||
@ -43,6 +47,10 @@ fn main() {
|
||||
//~^ ERROR the trait bound `Vec<u32>: Copy` is not satisfied
|
||||
//~| ERROR the trait bound `Vec<char>: Copy` is not satisfied
|
||||
check_clone(&gen_clone_0);
|
||||
}
|
||||
|
||||
fn test4() {
|
||||
let clonable_1: Vec<u32> = Vec::new();
|
||||
let gen_clone_1 = move || {
|
||||
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<char>: Copy` is not satisfied
|
||||
check_clone(&gen_clone_1);
|
||||
}
|
||||
|
||||
fn test5() {
|
||||
let non_clonable: NonClone = NonClone;
|
||||
let gen_non_clone = move || {
|
||||
yield;
|
||||
drop(non_clonable);
|
||||
@ -71,3 +83,5 @@ fn main() {
|
||||
|
||||
fn check_copy<T: Copy>(_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}`
|
||||
--> $DIR/clone-impl.rs:42:5
|
||||
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:46:5
|
||||
|
|
||||
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);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ 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`
|
||||
--> $DIR/clone-impl.rs:40:14
|
||||
--> $DIR/clone-impl.rs:44:14
|
||||
|
|
||||
LL | drop(clonable_0);
|
||||
| ^^^^^^^^^^ has type `Vec<u32>` which does not implement `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) {}
|
||||
| ^^^^ 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}`
|
||||
--> $DIR/clone-impl.rs:42:5
|
||||
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:46:5
|
||||
|
|
||||
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);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ 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
|
||||
--> $DIR/clone-impl.rs:38:9
|
||||
--> $DIR/clone-impl.rs:42: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
|
||||
--> $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<u32>: 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<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}`
|
||||
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:66:5
|
||||
|
|
||||
LL | let gen_non_clone = move || {
|
||||
| ------- within this `{coroutine@$DIR/clone-impl.rs:62:25: 62:32}`
|
||||
LL | let gen_clone_1 = move || {
|
||||
| ------- within this `{coroutine@$DIR/clone-impl.rs:54:23: 54:30}`
|
||||
...
|
||||
LL | check_copy(&gen_non_clone);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ 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`
|
||||
LL | check_copy(&gen_clone_1);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ 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`
|
||||
--> $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);
|
||||
| ^^^^^^^^^^^^ has type `NonClone` which does not implement `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) {}
|
||||
| ^^^^ required by this bound in `check_copy`
|
||||
@ -108,22 +108,22 @@ LL + #[derive(Copy)]
|
||||
LL | struct NonClone;
|
||||
|
|
||||
|
||||
error[E0277]: the trait bound `NonClone: Clone` is not satisfied in `{coroutine@$DIR/clone-impl.rs:62:25: 62:32}`
|
||||
--> $DIR/clone-impl.rs:68:5
|
||||
error[E0277]: the trait bound `NonClone: Clone` is not satisfied in `{coroutine@$DIR/clone-impl.rs:74:25: 74:32}`
|
||||
--> $DIR/clone-impl.rs:80:5
|
||||
|
|
||||
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);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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`
|
||||
--> $DIR/clone-impl.rs:64:14
|
||||
--> $DIR/clone-impl.rs:76:14
|
||||
|
|
||||
LL | drop(non_clonable);
|
||||
| ^^^^^^^^^^^^ has type `NonClone` which does not implement `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) {}
|
||||
| ^^^^^ 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) {}
|
||||
| ^^^^^ 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
|
||||
--> $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
|
||||
|
|
||||
= 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
|
||||
--> $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
|
||||
|
|
||||
= 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
|
||||
--> $DIR/E0229.rs:13:15
|
||||
|
@ -3,6 +3,11 @@ error[E0229]: associated type bindings are not allowed here
|
||||
|
|
||||
LL | type A: S<C<(), i32 = ()> = ()>;
|
||||
| ^^^^^^^^ 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
|
||||
--> $DIR/issue-102335-gat.rs:2:21
|
||||
@ -11,6 +16,10 @@ LL | type A: S<C<(), i32 = ()> = ()>;
|
||||
| ^^^^^^^^ 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 = ()> = ()>;
|
||||
| ~~~~~~~~~~
|
||||
|
||||
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