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:
bors 2024-04-23 16:11:09 +00:00
commit c2f2db79ca
118 changed files with 2113 additions and 654 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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 {

View File

@ -17,9 +17,9 @@ use rustc_middle::hir::nested_filter::OnlyBodies;
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 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
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 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
(
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 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
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 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
)
}
(BorrowKind::Shared, BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }) => {
(
BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep),
BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture },
) => {
first_borrow_desc = "first ";
self.cannot_reborrow_already_uniquely_borrowed(
span,
@ -1659,8 +1662,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
)
}
(BorrowKind::Shared, BorrowKind::Shared | BorrowKind::Fake)
| (BorrowKind::Fake, BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake) => {
(
BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep),
BorrowKind::Shared | BorrowKind::Fake(_),
)
| (
BorrowKind::Fake(FakeBorrowKind::Shallow),
BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake(_),
) => {
unreachable!()
}
};
@ -3572,7 +3581,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
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,

View File

@ -654,7 +654,7 @@ impl UseSpans<'_> {
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 }
}

View File

@ -1056,18 +1056,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
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 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, '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) {
@ -1197,7 +1200,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
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 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// 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 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
| 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 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
return false;
}
Read(
ReadKind::Borrow(BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake)
ReadKind::Borrow(BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake(_))
| ReadKind::Copy,
) => {
// Access authorized

View File

@ -55,7 +55,7 @@ use crate::Overlap;
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");

View File

@ -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 @@ impl<'cx, 'tcx> LoanInvalidationsGenerator<'cx, '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 @@ impl<'cx, 'tcx> LoanInvalidationsGenerator<'cx, 'tcx> {
// 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 @@ impl<'cx, 'tcx> LoanInvalidationsGenerator<'cx, 'tcx> {
// only mutable borrows should be 2-phase
assert!(match borrow.kind {
BorrowKind::Shared | BorrowKind::Fake => false,
BorrowKind::Shared | BorrowKind::Fake(_) => false,
BorrowKind::Mut { .. } => true,
});

View File

@ -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());

View File

@ -414,7 +414,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
BorrowKind::Shared => {
PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow)
}
BorrowKind::Fake => {
BorrowKind::Fake(_) => {
PlaceContext::NonMutatingUse(NonMutatingUseContext::FakeBorrow)
}
BorrowKind::Mut { .. } => {
@ -487,7 +487,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
}
}
Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Fake, place)
Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Fake(_), place)
| Rvalue::AddressOf(Mutability::Not, place) => {
let borrowed_place_has_mut_interior = qualifs::in_place::<HasMutInterior, _>(
self.ccx,

View File

@ -105,7 +105,7 @@ where
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)
}
}

View File

@ -965,7 +965,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
}
},
Rvalue::Ref(_, BorrowKind::Fake, _) => {
Rvalue::Ref(_, BorrowKind::Fake(_), _) => {
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(
location,

View File

@ -177,7 +177,7 @@ where
{
/// 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 @@ where
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
f: F,
f: &F,
);
}
@ -1197,7 +1197,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
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)

View File

@ -227,6 +227,36 @@ impl IntoDiagArg for rustc_lint_defs::Level {
}
}
impl<Id> IntoDiagArg for hir::def::Res<Id> {
fn into_diag_arg(self) -> DiagArgValue {
DiagArgValue::Str(Cow::Borrowed(self.descr()))
}
}
impl IntoDiagArg for DiagLocation {
fn into_diag_arg(self) -> DiagArgValue {
DiagArgValue::Str(Cow::from(self.to_string()))
}
}
impl IntoDiagArg for Backtrace {
fn into_diag_arg(self) -> DiagArgValue {
DiagArgValue::Str(Cow::from(self.to_string()))
}
}
impl IntoDiagArg for Level {
fn into_diag_arg(self) -> DiagArgValue {
DiagArgValue::Str(Cow::from(self.to_string()))
}
}
impl IntoDiagArg for type_ir::ClosureKind {
fn into_diag_arg(self) -> DiagArgValue {
DiagArgValue::Str(self.as_str().into())
}
}
#[derive(Clone)]
pub struct DiagSymbolList(Vec<Symbol>);
@ -244,12 +274,6 @@ impl IntoDiagArg for DiagSymbolList {
}
}
impl<Id> IntoDiagArg for hir::def::Res<Id> {
fn into_diag_arg(self) -> DiagArgValue {
DiagArgValue::Str(Cow::Borrowed(self.descr()))
}
}
impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetDataLayoutErrors<'_> {
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>,
}

View File

@ -40,8 +40,8 @@ pub use diagnostic::{
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 @@ impl Level {
}
// 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>(

View File

@ -644,13 +644,49 @@ impl<'hir> Generics<'hir> {
})
}
pub fn bounds_span_for_suggestions(&self, param_def_id: LocalDefId) -> Option<Span> {
/// Returns a suggestable empty span right after the "final" bound of the generic parameter.
///
/// If that bound needs to be wrapped in parentheses to avoid ambiguity with
/// subsequent bounds, it also returns an empty span for an open parenthesis
/// as the second component.
///
/// E.g., adding `+ 'static` after `Fn() -> dyn Future<Output = ()>` or
/// `Fn() -> &'static dyn Debug` requires parentheses:
/// `Fn() -> (dyn Future<Output = ()>) + 'static` and
/// `Fn() -> &'static (dyn Debug) + 'static`, respectively.
pub fn bounds_span_for_suggestions(
&self,
param_def_id: LocalDefId,
) -> Option<(Span, Option<Span>)> {
self.bounds_for_param(param_def_id).flat_map(|bp| bp.bounds.iter().rev()).find_map(
|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()))),
)
},
)
}

View File

@ -10,11 +10,10 @@ use rustc_hir as hir;
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_middle::ty::{
};
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 opaque_type_cycle_error(
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));

View File

@ -17,6 +17,7 @@ use rustc_hir::def::{DefKind, Res};
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 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
/// 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(

View File

@ -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 =

View File

@ -323,7 +323,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
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 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
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 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
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 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
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));
}
}

View File

@ -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) => {

View File

@ -750,6 +750,15 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
}
}
}
} else if let PatKind::Deref(subpattern) = pat.kind {
// A deref pattern is a bit special: the binding mode of its inner bindings
// determines whether to borrow *at the level of the deref pattern* rather than
// borrowing the bound place (since that inner place is inside the temporary that
// stores the result of calling `deref()`/`deref_mut()` so can't be captured).
let mutable = mc.typeck_results.pat_has_ref_mut_binding(subpattern);
let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
let bk = ty::BorrowKind::from_mutbl(mutability);
delegate.borrow(place, discr_place.hir_id, bk);
}
}));
}

View File

@ -588,12 +588,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
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);
}
}

View File

@ -23,7 +23,7 @@ use rustc_hir::{
};
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;

View File

@ -711,13 +711,23 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
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 {

View File

@ -3291,14 +3291,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
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 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
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 {

View File

@ -551,15 +551,10 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
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")]

View File

@ -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());

View File

@ -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);

View File

@ -2369,7 +2369,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
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 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
// 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 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
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)

View File

@ -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));

View File

@ -321,6 +321,7 @@ fn test_search_paths_tracking_hash_different_order() {
&opts.target_triple,
&early_dcx,
search_path,
false,
));
};

View File

@ -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) => {

View File

@ -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 } => {

View File

@ -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 => {

View File

@ -71,6 +71,7 @@ impl SubdiagnosticDerive {
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 @@ impl SubdiagnosticDerive {
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 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
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 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
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 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
.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;

View File

@ -144,6 +144,7 @@ decl_derive!(
help,
note,
warning,
subdiagnostic,
suggestion,
suggestion_short,
suggestion_hidden,

View File

@ -985,7 +985,8 @@ impl<'tcx> Debug for Rvalue<'tcx> {
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 ",
};

View File

@ -236,6 +236,11 @@ impl<'tcx> PlaceRef<'tcx> {
}
}
#[inline]
pub fn to_place(&self, tcx: TyCtxt<'tcx>) -> Place<'tcx> {
Place { local: self.local, projection: tcx.mk_place_elems(self.projection) }
}
#[inline]
pub fn last_projection(&self) -> Option<(PlaceRef<'tcx>, PlaceElem<'tcx>)> {
if let &[ref proj_base @ .., elem] = self.projection {
@ -446,7 +451,7 @@ impl<'tcx> Rvalue<'tcx> {
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 @@ impl BorrowKind {
pub fn allows_two_phase_borrow(&self) -> bool {
match *self {
BorrowKind::Shared
| BorrowKind::Fake
| BorrowKind::Fake(_)
| BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::ClosureCapture } => {
false
}

View File

@ -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

View File

@ -294,7 +294,7 @@ impl BorrowKind {
// We have no type corresponding to a shallow borrow, so use
// `&` as an approximation.
BorrowKind::Fake => hir::Mutability::Not,
BorrowKind::Fake(_) => hir::Mutability::Not,
}
}
}

View File

@ -655,7 +655,7 @@ macro_rules! make_mir_visitor {
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,

View File

@ -642,7 +642,7 @@ impl<'tcx> Pat<'tcx> {
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 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
}
write!(f, "{subpattern}")
}
PatKind::DerefPattern { ref subpattern } => {
PatKind::DerefPattern { ref subpattern, .. } => {
write!(f, "deref!({subpattern})")
}
PatKind::Constant { value } => write!(f, "{value}"),

View File

@ -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 } => {

View File

@ -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;
}

View File

@ -7,10 +7,8 @@ use crate::{
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 @@ impl<'tcx> 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 @@ impl<'tcx> TypeckResults<'tcx> {
/// 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

View File

@ -685,7 +685,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
fake_borrow_temp.into(),
Rvalue::Ref(
tcx.lifetimes.re_erased,
BorrowKind::Fake,
BorrowKind::Fake(FakeBorrowKind::Shallow),
Place { local: base_place.local, projection },
),
);

View File

@ -10,10 +10,7 @@ use crate::build::scope::DropKind;
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 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// 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 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
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 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
});
}
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 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
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 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
&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 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
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 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
target_blocks,
);
}
/// Determine the fake borrows that are needed from a set of places that
/// have to be stable across match guards.
///
/// Returns a list of places that need a fake borrow and the temporary
/// that's used to store the fake borrow.
///
/// Match exhaustiveness checking is not able to handle the case where the
/// place being matched on is mutated in the guards. We add "fake borrows"
/// to the guards that prevent any mutation of the place being matched.
/// There are a some subtleties:
///
/// 1. Borrowing `*x` doesn't prevent assigning to `x`. If `x` is a shared
/// reference, the borrow isn't even tracked. As such we have to add fake
/// borrows of any prefixes of a place
/// 2. We don't want `match x { _ => (), }` to conflict with mutable
/// borrows of `x`, so we only add fake borrows for places which are
/// bound or tested by the match.
/// 3. We don't want the fake borrows to conflict with `ref mut` bindings,
/// so we use a special BorrowKind for them.
/// 4. The fake borrows may be of places in inactive variants, so it would
/// be UB to generate code for them. They therefore have to be removed
/// by a MIR pass run after borrow checking.
fn calculate_fake_borrows<'b>(
&mut self,
fake_borrows: &'b FxIndexSet<Place<'tcx>>,
temp_span: Span,
) -> Vec<(Place<'tcx>, Local)> {
let tcx = self.tcx;
debug!("add_fake_borrows fake_borrows = {:?}", fake_borrows);
let mut all_fake_borrows = Vec::with_capacity(fake_borrows.len());
// Insert a Shallow borrow of the prefixes of any fake borrows.
for place in fake_borrows {
let mut cursor = place.projection.as_ref();
while let [proj_base @ .., elem] = cursor {
cursor = proj_base;
if let ProjectionElem::Deref = elem {
// Insert a shallow borrow after a deref. For other
// projections the borrow of prefix_cursor will
// conflict with any mutation of base.
all_fake_borrows.push(PlaceRef { local: place.local, projection: proj_base });
}
}
all_fake_borrows.push(place.as_ref());
}
// Deduplicate
let mut dedup = FxHashSet::default();
all_fake_borrows.retain(|b| dedup.insert(*b));
debug!("add_fake_borrows all_fake_borrows = {:?}", all_fake_borrows);
all_fake_borrows
.into_iter()
.map(|matched_place_ref| {
let matched_place = Place {
local: matched_place_ref.local,
projection: tcx.mk_place_elems(matched_place_ref.projection),
};
let fake_borrow_deref_ty = matched_place.ty(&self.local_decls, tcx).ty;
let fake_borrow_ty =
Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, fake_borrow_deref_ty);
let mut fake_borrow_temp = LocalDecl::new(fake_borrow_ty, temp_span);
fake_borrow_temp.local_info = ClearCrossCrate::Set(Box::new(LocalInfo::FakeBorrow));
let fake_borrow_temp = self.local_decls.push(fake_borrow_temp);
(matched_place, fake_borrow_temp)
})
.collect()
}
}
///////////////////////////////////////////////////////////////////////////
@ -2044,7 +1977,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
&mut self,
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 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
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 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
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));
}

View File

@ -42,6 +42,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
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 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
);
}
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 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
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 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
}
(TestKind::Deref { temp: test_temp, .. }, TestCase::Deref { temp, .. })
if test_temp == temp =>
{
fully_matched = true;
Some(TestBranch::Success)
}
(
TestKind::Switch { .. }
| TestKind::SwitchInt { .. }
| TestKind::If
| TestKind::Len { .. }
| TestKind::Range { .. }
| TestKind::Eq { .. },
| TestKind::Eq { .. }
| TestKind::Deref { .. },
_,
) => {
fully_matched = false;

View File

@ -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 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
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 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
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 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, '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 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, '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 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, '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);
}
}

View File

@ -513,7 +513,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, '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 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
BorrowKind::Mut { .. } => {
self.requires_unsafe(expr.span, MutationOfLayoutConstrainedField)
}
BorrowKind::Fake | BorrowKind::Shared => {}
BorrowKind::Fake(_) | BorrowKind::Shared => {}
}
}
}

View File

@ -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);

View File

@ -264,7 +264,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
}
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) }

View File

@ -688,7 +688,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
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);

View File

@ -102,7 +102,7 @@ where
}
Rvalue::Cast(..)
| Rvalue::Ref(_, BorrowKind::Fake, _)
| Rvalue::Ref(_, BorrowKind::Fake(_), _)
| Rvalue::ShallowInitBox(..)
| Rvalue::Use(..)
| Rvalue::ThreadLocalRef(..)

View File

@ -29,7 +29,7 @@ impl<'tcx> MirPass<'tcx> for CleanupPostBorrowck {
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.

View File

@ -80,6 +80,10 @@ use rustc_span::symbol::sym;
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 {

View File

@ -384,7 +384,7 @@ impl<'tcx> Validator<'_, 'tcx> {
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);
}

View File

@ -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 {

View File

@ -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(

View File

@ -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;

View File

@ -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)]

View File

@ -1883,20 +1883,18 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
// 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 {

View File

@ -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| {

View File

@ -52,6 +52,7 @@ impl SearchPath {
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 @@ impl SearchPath {
};
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),

View File

@ -229,7 +229,7 @@ impl<'tcx> Stable<'tcx> for mir::BorrowKind {
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 @@ impl<'tcx> Stable<'tcx> for mir::MutBorrowKind {
}
}
impl<'tcx> Stable<'tcx> for mir::FakeBorrowKind {
type T = stable_mir::mir::FakeBorrowKind;
fn stable(&self, _: &mut Tables<'_>) -> Self::T {
use rustc_middle::mir::FakeBorrowKind::*;
match *self {
Deep => stable_mir::mir::FakeBorrowKind::Deep,
Shallow => stable_mir::mir::FakeBorrowKind::Shallow,
}
}
}
impl<'tcx> Stable<'tcx> for mir::NullOp<'tcx> {
type T = stable_mir::mir::NullOp;
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {

View File

@ -14,7 +14,7 @@ use rustc_data_structures::sync::{IntoDynSyncSend, MappedReadGuard, ReadGuard, R
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;

View File

@ -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 } => {

View File

@ -2938,17 +2938,28 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
_ => {}
};
// 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,
);
}

View File

@ -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 @@ impl BorrowKind {
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,

View File

@ -8,7 +8,7 @@ use std::{fmt, io, iter};
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)

View File

@ -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

View File

@ -635,7 +635,16 @@ impl Options {
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");

View File

@ -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() {}

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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>,
}

View File

@ -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

View File

@ -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
}

View File

@ -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`.

View File

@ -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() {}

View File

@ -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`.

View File

@ -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

View File

@ -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

View File

@ -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() {}

View File

@ -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`

View 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() {}

View 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`.

View File

@ -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

View File

@ -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