Auto merge of #132840 - matthiaskrgr:rollup-ibarl2r, r=matthiaskrgr
Rollup of 2 pull requests Successful merges: - #132136 (ABI compatibility: remove section on target features) - #132816 (Dont suggest `use<impl Trait>` when we have an edition-2024-related borrowck issue) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
c24e166527
@ -4,15 +4,16 @@
|
|||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
use either::Either;
|
use either::Either;
|
||||||
|
use itertools::Itertools as _;
|
||||||
use rustc_data_structures::fx::FxIndexSet;
|
use rustc_data_structures::fx::FxIndexSet;
|
||||||
use rustc_errors::{Applicability, Diag};
|
use rustc_errors::{Diag, Subdiagnostic};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_middle::mir::{self, ConstraintCategory, Location};
|
use rustc_middle::mir::{self, ConstraintCategory, Location};
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
|
self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
|
||||||
};
|
};
|
||||||
use rustc_span::Symbol;
|
use rustc_trait_selection::errors::impl_trait_overcapture_suggestion;
|
||||||
|
|
||||||
use crate::MirBorrowckCtxt;
|
use crate::MirBorrowckCtxt;
|
||||||
use crate::borrow_set::BorrowData;
|
use crate::borrow_set::BorrowData;
|
||||||
@ -61,6 +62,7 @@ pub(crate) fn note_due_to_edition_2024_opaque_capture_rules(
|
|||||||
// *does* mention. We'll use that for the `+ use<'a>` suggestion below.
|
// *does* mention. We'll use that for the `+ use<'a>` suggestion below.
|
||||||
let mut visitor = CheckExplicitRegionMentionAndCollectGenerics {
|
let mut visitor = CheckExplicitRegionMentionAndCollectGenerics {
|
||||||
tcx,
|
tcx,
|
||||||
|
generics: tcx.generics_of(opaque_def_id),
|
||||||
offending_region_idx,
|
offending_region_idx,
|
||||||
seen_opaques: [opaque_def_id].into_iter().collect(),
|
seen_opaques: [opaque_def_id].into_iter().collect(),
|
||||||
seen_lifetimes: Default::default(),
|
seen_lifetimes: Default::default(),
|
||||||
@ -83,34 +85,50 @@ pub(crate) fn note_due_to_edition_2024_opaque_capture_rules(
|
|||||||
"this call may capture more lifetimes than intended, \
|
"this call may capture more lifetimes than intended, \
|
||||||
because Rust 2024 has adjusted the `impl Trait` lifetime capture rules",
|
because Rust 2024 has adjusted the `impl Trait` lifetime capture rules",
|
||||||
);
|
);
|
||||||
let mut seen_generics: Vec<_> =
|
let mut captured_args = visitor.seen_lifetimes;
|
||||||
visitor.seen_lifetimes.iter().map(ToString::to_string).collect();
|
// Add in all of the type and const params, too.
|
||||||
// Capture all in-scope ty/const params.
|
// Ordering here is kinda strange b/c we're walking backwards,
|
||||||
seen_generics.extend(
|
// but we're trying to provide *a* suggestion, not a nice one.
|
||||||
ty::GenericArgs::identity_for_item(tcx, opaque_def_id)
|
let mut next_generics = Some(visitor.generics);
|
||||||
.iter()
|
let mut any_synthetic = false;
|
||||||
.filter(|arg| {
|
while let Some(generics) = next_generics {
|
||||||
matches!(
|
for param in &generics.own_params {
|
||||||
arg.unpack(),
|
if param.kind.is_ty_or_const() {
|
||||||
ty::GenericArgKind::Type(_) | ty::GenericArgKind::Const(_)
|
captured_args.insert(param.def_id);
|
||||||
)
|
}
|
||||||
})
|
if param.kind.is_synthetic() {
|
||||||
.map(|arg| arg.to_string()),
|
any_synthetic = true;
|
||||||
);
|
}
|
||||||
if opaque_def_id.is_local() {
|
}
|
||||||
diag.span_suggestion_verbose(
|
next_generics = generics.parent.map(|def_id| tcx.generics_of(def_id));
|
||||||
tcx.def_span(opaque_def_id).shrink_to_hi(),
|
}
|
||||||
"add a precise capturing bound to avoid overcapturing",
|
|
||||||
format!(" + use<{}>", seen_generics.join(", ")),
|
if let Some(opaque_def_id) = opaque_def_id.as_local()
|
||||||
Applicability::MaybeIncorrect,
|
&& let hir::OpaqueTyOrigin::FnReturn { parent, .. } =
|
||||||
);
|
tcx.hir().expect_opaque_ty(opaque_def_id).origin
|
||||||
|
{
|
||||||
|
if let Some(sugg) = impl_trait_overcapture_suggestion(
|
||||||
|
tcx,
|
||||||
|
opaque_def_id,
|
||||||
|
parent,
|
||||||
|
captured_args,
|
||||||
|
) {
|
||||||
|
sugg.add_to_diag(diag);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
diag.span_help(
|
diag.span_help(
|
||||||
tcx.def_span(opaque_def_id),
|
tcx.def_span(opaque_def_id),
|
||||||
format!(
|
format!(
|
||||||
"if you can modify this crate, add a precise \
|
"if you can modify this crate, add a precise \
|
||||||
capturing bound to avoid overcapturing: `+ use<{}>`",
|
capturing bound to avoid overcapturing: `+ use<{}>`",
|
||||||
seen_generics.join(", ")
|
if any_synthetic {
|
||||||
|
"/* Args */".to_string()
|
||||||
|
} else {
|
||||||
|
captured_args
|
||||||
|
.into_iter()
|
||||||
|
.map(|def_id| tcx.item_name(def_id))
|
||||||
|
.join(", ")
|
||||||
|
}
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -182,9 +200,10 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
|
|||||||
|
|
||||||
struct CheckExplicitRegionMentionAndCollectGenerics<'tcx> {
|
struct CheckExplicitRegionMentionAndCollectGenerics<'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
|
generics: &'tcx ty::Generics,
|
||||||
offending_region_idx: usize,
|
offending_region_idx: usize,
|
||||||
seen_opaques: FxIndexSet<DefId>,
|
seen_opaques: FxIndexSet<DefId>,
|
||||||
seen_lifetimes: FxIndexSet<Symbol>,
|
seen_lifetimes: FxIndexSet<DefId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for CheckExplicitRegionMentionAndCollectGenerics<'tcx> {
|
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for CheckExplicitRegionMentionAndCollectGenerics<'tcx> {
|
||||||
@ -214,7 +233,7 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> Self::Result {
|
|||||||
if param.index as usize == self.offending_region_idx {
|
if param.index as usize == self.offending_region_idx {
|
||||||
ControlFlow::Break(())
|
ControlFlow::Break(())
|
||||||
} else {
|
} else {
|
||||||
self.seen_lifetimes.insert(param.name);
|
self.seen_lifetimes.insert(self.generics.region_param(param, self.tcx).def_id);
|
||||||
ControlFlow::Continue(())
|
ControlFlow::Continue(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -346,7 +346,6 @@ lint_impl_trait_overcaptures = `{$self_ty}` will capture more lifetimes than pos
|
|||||||
*[other] these lifetimes are
|
*[other] these lifetimes are
|
||||||
} in scope but not mentioned in the type's bounds
|
} in scope but not mentioned in the type's bounds
|
||||||
.note2 = all lifetimes in scope will be captured by `impl Trait`s in edition 2024
|
.note2 = all lifetimes in scope will be captured by `impl Trait`s in edition 2024
|
||||||
.suggestion = use the precise capturing `use<...>` syntax to make the captures explicit
|
|
||||||
|
|
||||||
lint_impl_trait_redundant_captures = all possible in-scope parameters are already captured, so `use<...>` syntax is redundant
|
lint_impl_trait_redundant_captures = all possible in-scope parameters are already captured, so `use<...>` syntax is redundant
|
||||||
.suggestion = remove the `use<...>` syntax
|
.suggestion = remove the `use<...>` syntax
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
|
use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
|
||||||
use rustc_data_structures::unord::UnordSet;
|
use rustc_data_structures::unord::UnordSet;
|
||||||
use rustc_errors::{Applicability, LintDiagnostic};
|
use rustc_errors::{LintDiagnostic, Subdiagnostic};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
@ -22,6 +22,9 @@
|
|||||||
use rustc_session::{declare_lint, declare_lint_pass};
|
use rustc_session::{declare_lint, declare_lint_pass};
|
||||||
use rustc_span::edition::Edition;
|
use rustc_span::edition::Edition;
|
||||||
use rustc_span::{Span, Symbol};
|
use rustc_span::{Span, Symbol};
|
||||||
|
use rustc_trait_selection::errors::{
|
||||||
|
AddPreciseCapturingForOvercapture, impl_trait_overcapture_suggestion,
|
||||||
|
};
|
||||||
use rustc_trait_selection::traits::ObligationCtxt;
|
use rustc_trait_selection::traits::ObligationCtxt;
|
||||||
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt;
|
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt;
|
||||||
|
|
||||||
@ -334,32 +337,12 @@ fn visit_ty(&mut self, t: Ty<'tcx>) {
|
|||||||
// If we have uncaptured args, and if the opaque doesn't already have
|
// If we have uncaptured args, and if the opaque doesn't already have
|
||||||
// `use<>` syntax on it, and we're < edition 2024, then warn the user.
|
// `use<>` syntax on it, and we're < edition 2024, then warn the user.
|
||||||
if !uncaptured_args.is_empty() {
|
if !uncaptured_args.is_empty() {
|
||||||
let suggestion = if let Ok(snippet) =
|
let suggestion = impl_trait_overcapture_suggestion(
|
||||||
self.tcx.sess.source_map().span_to_snippet(opaque_span)
|
self.tcx,
|
||||||
&& snippet.starts_with("impl ")
|
opaque_def_id,
|
||||||
{
|
self.parent_def_id,
|
||||||
let (lifetimes, others): (Vec<_>, Vec<_>) =
|
captured,
|
||||||
captured.into_iter().partition(|def_id| {
|
);
|
||||||
self.tcx.def_kind(*def_id) == DefKind::LifetimeParam
|
|
||||||
});
|
|
||||||
// Take all lifetime params first, then all others (ty/ct).
|
|
||||||
let generics: Vec<_> = lifetimes
|
|
||||||
.into_iter()
|
|
||||||
.chain(others)
|
|
||||||
.map(|def_id| self.tcx.item_name(def_id).to_string())
|
|
||||||
.collect();
|
|
||||||
// Make sure that we're not trying to name any APITs
|
|
||||||
if generics.iter().all(|name| !name.starts_with("impl ")) {
|
|
||||||
Some((
|
|
||||||
format!(" + use<{}>", generics.join(", ")),
|
|
||||||
opaque_span.shrink_to_hi(),
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let uncaptured_spans: Vec<_> = uncaptured_args
|
let uncaptured_spans: Vec<_> = uncaptured_args
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -451,7 +434,7 @@ struct ImplTraitOvercapturesLint<'tcx> {
|
|||||||
uncaptured_spans: Vec<Span>,
|
uncaptured_spans: Vec<Span>,
|
||||||
self_ty: Ty<'tcx>,
|
self_ty: Ty<'tcx>,
|
||||||
num_captured: usize,
|
num_captured: usize,
|
||||||
suggestion: Option<(String, Span)>,
|
suggestion: Option<AddPreciseCapturingForOvercapture>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> LintDiagnostic<'a, ()> for ImplTraitOvercapturesLint<'_> {
|
impl<'a> LintDiagnostic<'a, ()> for ImplTraitOvercapturesLint<'_> {
|
||||||
@ -461,13 +444,8 @@ fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::Diag<'a, ()>) {
|
|||||||
.arg("num_captured", self.num_captured)
|
.arg("num_captured", self.num_captured)
|
||||||
.span_note(self.uncaptured_spans, fluent::lint_note)
|
.span_note(self.uncaptured_spans, fluent::lint_note)
|
||||||
.note(fluent::lint_note2);
|
.note(fluent::lint_note2);
|
||||||
if let Some((suggestion, span)) = self.suggestion {
|
if let Some(suggestion) = self.suggestion {
|
||||||
diag.span_suggestion(
|
suggestion.add_to_diag(diag);
|
||||||
span,
|
|
||||||
fluent::lint_suggestion,
|
|
||||||
suggestion,
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -282,6 +282,8 @@ trait_selection_precise_capturing_new = add a `use<...>` bound to explicitly cap
|
|||||||
|
|
||||||
trait_selection_precise_capturing_new_but_apit = add a `use<...>` bound to explicitly capture `{$new_lifetime}` after turning all argument-position `impl Trait` into type parameters, noting that this possibly affects the API of this crate
|
trait_selection_precise_capturing_new_but_apit = add a `use<...>` bound to explicitly capture `{$new_lifetime}` after turning all argument-position `impl Trait` into type parameters, noting that this possibly affects the API of this crate
|
||||||
|
|
||||||
|
trait_selection_precise_capturing_overcaptures = use the precise capturing `use<...>` syntax to make the captures explicit
|
||||||
|
|
||||||
trait_selection_prlf_defined_with_sub = the lifetime `{$sub_symbol}` defined here...
|
trait_selection_prlf_defined_with_sub = the lifetime `{$sub_symbol}` defined here...
|
||||||
trait_selection_prlf_defined_without_sub = the lifetime defined here...
|
trait_selection_prlf_defined_without_sub = the lifetime defined here...
|
||||||
trait_selection_prlf_known_limitation = this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
|
trait_selection_prlf_known_limitation = this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
|
||||||
@ -455,7 +457,9 @@ trait_selection_unable_to_construct_constant_value = unable to construct a const
|
|||||||
trait_selection_unknown_format_parameter_for_on_unimplemented_attr = there is no parameter `{$argument_name}` on trait `{$trait_name}`
|
trait_selection_unknown_format_parameter_for_on_unimplemented_attr = there is no parameter `{$argument_name}` on trait `{$trait_name}`
|
||||||
.help = expect either a generic argument name or {"`{Self}`"} as format argument
|
.help = expect either a generic argument name or {"`{Self}`"} as format argument
|
||||||
|
|
||||||
trait_selection_warn_removing_apit_params = you could use a `use<...>` bound to explicitly capture `{$new_lifetime}`, but argument-position `impl Trait`s are not nameable
|
trait_selection_warn_removing_apit_params_for_overcapture = you could use a `use<...>` bound to explicitly specify captures, but argument-position `impl Trait`s are not nameable
|
||||||
|
|
||||||
|
trait_selection_warn_removing_apit_params_for_undercapture = you could use a `use<...>` bound to explicitly capture `{$new_lifetime}`, but argument-position `impl Trait`s are not nameable
|
||||||
|
|
||||||
trait_selection_where_copy_predicates = copy the `where` clause predicates from the trait
|
trait_selection_where_copy_predicates = copy the `where` clause predicates from the trait
|
||||||
|
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
|
||||||
use rustc_errors::codes::*;
|
use rustc_errors::codes::*;
|
||||||
use rustc_errors::{
|
use rustc_errors::{
|
||||||
Applicability, Diag, DiagCtxtHandle, DiagMessage, DiagStyledString, Diagnostic,
|
Applicability, Diag, DiagCtxtHandle, DiagMessage, DiagStyledString, Diagnostic,
|
||||||
EmissionGuarantee, IntoDiagArg, Level, MultiSpan, SubdiagMessageOp, Subdiagnostic,
|
EmissionGuarantee, IntoDiagArg, Level, MultiSpan, SubdiagMessageOp, Subdiagnostic,
|
||||||
};
|
};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::LocalDefId;
|
use rustc_hir::def::DefKind;
|
||||||
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_hir::intravisit::{Visitor, walk_ty};
|
use rustc_hir::intravisit::{Visitor, walk_ty};
|
||||||
use rustc_hir::{FnRetTy, GenericParamKind};
|
use rustc_hir::{FnRetTy, GenericParamKind};
|
||||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||||
@ -1792,6 +1793,130 @@ fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
|||||||
self.suggs,
|
self.suggs,
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
diag.span_note(self.apit_spans, fluent::trait_selection_warn_removing_apit_params);
|
diag.span_note(
|
||||||
|
self.apit_spans,
|
||||||
|
fluent::trait_selection_warn_removing_apit_params_for_undercapture,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Given a set of captured `DefId` for an RPIT (opaque_def_id) and a given
|
||||||
|
/// function (fn_def_id), try to suggest adding `+ use<...>` to capture just
|
||||||
|
/// the specified parameters. If one of those parameters is an APIT, then try
|
||||||
|
/// to suggest turning it into a regular type parameter.
|
||||||
|
pub fn impl_trait_overcapture_suggestion<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
opaque_def_id: LocalDefId,
|
||||||
|
fn_def_id: LocalDefId,
|
||||||
|
captured_args: FxIndexSet<DefId>,
|
||||||
|
) -> Option<AddPreciseCapturingForOvercapture> {
|
||||||
|
let generics = tcx.generics_of(fn_def_id);
|
||||||
|
|
||||||
|
let mut captured_lifetimes = FxIndexSet::default();
|
||||||
|
let mut captured_non_lifetimes = FxIndexSet::default();
|
||||||
|
let mut synthetics = vec![];
|
||||||
|
|
||||||
|
for arg in captured_args {
|
||||||
|
if tcx.def_kind(arg) == DefKind::LifetimeParam {
|
||||||
|
captured_lifetimes.insert(tcx.item_name(arg));
|
||||||
|
} else {
|
||||||
|
let idx = generics.param_def_id_to_index(tcx, arg).expect("expected arg in scope");
|
||||||
|
let param = generics.param_at(idx as usize, tcx);
|
||||||
|
if param.kind.is_synthetic() {
|
||||||
|
synthetics.push((tcx.def_span(arg), param.name));
|
||||||
|
} else {
|
||||||
|
captured_non_lifetimes.insert(tcx.item_name(arg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut next_fresh_param = || {
|
||||||
|
["T", "U", "V", "W", "X", "Y", "A", "B", "C"]
|
||||||
|
.into_iter()
|
||||||
|
.map(Symbol::intern)
|
||||||
|
.chain((0..).map(|i| Symbol::intern(&format!("T{i}"))))
|
||||||
|
.find(|s| captured_non_lifetimes.insert(*s))
|
||||||
|
.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut suggs = vec![];
|
||||||
|
let mut apit_spans = vec![];
|
||||||
|
|
||||||
|
if !synthetics.is_empty() {
|
||||||
|
let mut new_params = String::new();
|
||||||
|
for (i, (span, name)) in synthetics.into_iter().enumerate() {
|
||||||
|
apit_spans.push(span);
|
||||||
|
|
||||||
|
let fresh_param = next_fresh_param();
|
||||||
|
|
||||||
|
// Suggest renaming.
|
||||||
|
suggs.push((span, fresh_param.to_string()));
|
||||||
|
|
||||||
|
// Super jank. Turn `impl Trait` into `T: Trait`.
|
||||||
|
//
|
||||||
|
// This currently involves stripping the `impl` from the name of
|
||||||
|
// the parameter, since APITs are always named after how they are
|
||||||
|
// rendered in the AST. This sucks! But to recreate the bound list
|
||||||
|
// from the APIT itself would be miserable, so we're stuck with
|
||||||
|
// this for now!
|
||||||
|
if i > 0 {
|
||||||
|
new_params += ", ";
|
||||||
|
}
|
||||||
|
let name_as_bounds = name.as_str().trim_start_matches("impl").trim_start();
|
||||||
|
new_params += fresh_param.as_str();
|
||||||
|
new_params += ": ";
|
||||||
|
new_params += name_as_bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(generics) = tcx.hir().get_generics(fn_def_id) else {
|
||||||
|
// This shouldn't happen, but don't ICE.
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add generics or concatenate to the end of the list.
|
||||||
|
suggs.push(if let Some(params_span) = generics.span_for_param_suggestion() {
|
||||||
|
(params_span, format!(", {new_params}"))
|
||||||
|
} else {
|
||||||
|
(generics.span, format!("<{new_params}>"))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let concatenated_bounds = captured_lifetimes
|
||||||
|
.into_iter()
|
||||||
|
.chain(captured_non_lifetimes)
|
||||||
|
.map(|sym| sym.to_string())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", ");
|
||||||
|
|
||||||
|
suggs.push((
|
||||||
|
tcx.def_span(opaque_def_id).shrink_to_hi(),
|
||||||
|
format!(" + use<{concatenated_bounds}>"),
|
||||||
|
));
|
||||||
|
|
||||||
|
Some(AddPreciseCapturingForOvercapture { suggs, apit_spans })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AddPreciseCapturingForOvercapture {
|
||||||
|
pub suggs: Vec<(Span, String)>,
|
||||||
|
pub apit_spans: Vec<Span>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Subdiagnostic for AddPreciseCapturingForOvercapture {
|
||||||
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
|
self,
|
||||||
|
diag: &mut Diag<'_, G>,
|
||||||
|
_f: &F,
|
||||||
|
) {
|
||||||
|
diag.multipart_suggestion_verbose(
|
||||||
|
fluent::trait_selection_precise_capturing_overcaptures,
|
||||||
|
self.suggs,
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
if !self.apit_spans.is_empty() {
|
||||||
|
diag.span_note(
|
||||||
|
self.apit_spans,
|
||||||
|
fluent::trait_selection_warn_removing_apit_params_for_overcapture,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1746,11 +1746,10 @@ mod prim_ref {}
|
|||||||
/// alignment, they might be passed in different registers and hence not be ABI-compatible.
|
/// alignment, they might be passed in different registers and hence not be ABI-compatible.
|
||||||
///
|
///
|
||||||
/// ABI compatibility as a concern only arises in code that alters the type of function pointers,
|
/// ABI compatibility as a concern only arises in code that alters the type of function pointers,
|
||||||
/// code that imports functions via `extern` blocks, and in code that combines `#[target_feature]`
|
/// and code that imports functions via `extern` blocks. Altering the type of function pointers is
|
||||||
/// with `extern fn`. Altering the type of function pointers is wildly unsafe (as in, a lot more
|
/// wildly unsafe (as in, a lot more unsafe than even [`transmute_copy`][mem::transmute_copy]), and
|
||||||
/// unsafe than even [`transmute_copy`][mem::transmute_copy]), and should only occur in the most
|
/// should only occur in the most exceptional circumstances. Most Rust code just imports functions
|
||||||
/// exceptional circumstances. Most Rust code just imports functions via `use`. `#[target_feature]`
|
/// via `use`. So, most likely you do not have to worry about ABI compatibility.
|
||||||
/// is also used rarely. So, most likely you do not have to worry about ABI compatibility.
|
|
||||||
///
|
///
|
||||||
/// But assuming such circumstances, what are the rules? For this section, we are only considering
|
/// But assuming such circumstances, what are the rules? For this section, we are only considering
|
||||||
/// the ABI of direct Rust-to-Rust calls (with both definition and callsite visible to the
|
/// the ABI of direct Rust-to-Rust calls (with both definition and callsite visible to the
|
||||||
@ -1762,9 +1761,8 @@ mod prim_ref {}
|
|||||||
/// types from `core::ffi` or `libc`**.
|
/// types from `core::ffi` or `libc`**.
|
||||||
///
|
///
|
||||||
/// For two signatures to be considered *ABI-compatible*, they must use a compatible ABI string,
|
/// For two signatures to be considered *ABI-compatible*, they must use a compatible ABI string,
|
||||||
/// must take the same number of arguments, the individual argument types and the return types must
|
/// must take the same number of arguments, and the individual argument types and the return types
|
||||||
/// be ABI-compatible, and the target feature requirements must be met (see the subsection below for
|
/// must be ABI-compatible. The ABI string is declared via `extern "ABI" fn(...) -> ...`; note that
|
||||||
/// the last point). The ABI string is declared via `extern "ABI" fn(...) -> ...`; note that
|
|
||||||
/// `fn name(...) -> ...` implicitly uses the `"Rust"` ABI string and `extern fn name(...) -> ...`
|
/// `fn name(...) -> ...` implicitly uses the `"Rust"` ABI string and `extern fn name(...) -> ...`
|
||||||
/// implicitly uses the `"C"` ABI string.
|
/// implicitly uses the `"C"` ABI string.
|
||||||
///
|
///
|
||||||
@ -1834,24 +1832,6 @@ mod prim_ref {}
|
|||||||
/// Behavior since transmuting `None::<NonZero<i32>>` to `NonZero<i32>` violates the non-zero
|
/// Behavior since transmuting `None::<NonZero<i32>>` to `NonZero<i32>` violates the non-zero
|
||||||
/// requirement.
|
/// requirement.
|
||||||
///
|
///
|
||||||
/// #### Requirements concerning target features
|
|
||||||
///
|
|
||||||
/// Under some conditions, the signature used by the caller and the callee can be ABI-incompatible
|
|
||||||
/// even if the exact same ABI string and types are being used. As an example, the
|
|
||||||
/// `std::arch::x86_64::__m256` type has a different `extern "C"` ABI when the `avx` feature is
|
|
||||||
/// enabled vs when it is not enabled.
|
|
||||||
///
|
|
||||||
/// Therefore, to ensure ABI compatibility when code using different target features is combined
|
|
||||||
/// (such as via `#[target_feature]`), we further require that one of the following conditions is
|
|
||||||
/// met:
|
|
||||||
///
|
|
||||||
/// - The function uses the `"Rust"` ABI string (which is the default without `extern`).
|
|
||||||
/// - Caller and callee are using the exact same set of target features. For the callee we consider
|
|
||||||
/// the features enabled (via `#[target_feature]` and `-C target-feature`/`-C target-cpu`) at the
|
|
||||||
/// declaration site; for the caller we consider the features enabled at the call site.
|
|
||||||
/// - Neither any argument nor the return value involves a SIMD type (`#[repr(simd)]`) that is not
|
|
||||||
/// behind a pointer indirection (i.e., `*mut __m256` is fine, but `(i32, __m256)` is not).
|
|
||||||
///
|
|
||||||
/// ### Trait implementations
|
/// ### Trait implementations
|
||||||
///
|
///
|
||||||
/// In this documentation the shorthand `fn(T₁, T₂, …, Tₙ)` is used to represent non-variadic
|
/// In this documentation the shorthand `fn(T₁, T₂, …, Tₙ)` is used to represent non-variadic
|
||||||
|
@ -187,4 +187,19 @@ fn returned() -> impl Sized {
|
|||||||
}
|
}
|
||||||
//~^ NOTE `x` dropped here while still borrowed
|
//~^ NOTE `x` dropped here while still borrowed
|
||||||
|
|
||||||
|
fn capture_apit(x: &impl Sized) -> impl Sized {}
|
||||||
|
//~^ NOTE you could use a `use<...>` bound to explicitly specify captures, but
|
||||||
|
|
||||||
|
fn test_apit() {
|
||||||
|
let x = String::new();
|
||||||
|
//~^ NOTE binding `x` declared here
|
||||||
|
let y = capture_apit(&x);
|
||||||
|
//~^ NOTE borrow of `x` occurs here
|
||||||
|
//~| NOTE this call may capture more lifetimes than intended
|
||||||
|
drop(x);
|
||||||
|
//~^ ERROR cannot move out of `x` because it is borrowed
|
||||||
|
//~| NOTE move out of `x` occurs here
|
||||||
|
}
|
||||||
|
//~^ NOTE borrow might be used here, when `y` is dropped
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
@ -30,7 +30,7 @@ note: this call may capture more lifetimes than intended, because Rust 2024 has
|
|||||||
|
|
|
|
||||||
LL | let a = display_len(&x);
|
LL | let a = display_len(&x);
|
||||||
| ^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^
|
||||||
help: add a precise capturing bound to avoid overcapturing
|
help: use the precise capturing `use<...>` syntax to make the captures explicit
|
||||||
|
|
|
|
||||||
LL | fn display_len<T>(x: &Vec<T>) -> impl Display + use<T> {
|
LL | fn display_len<T>(x: &Vec<T>) -> impl Display + use<T> {
|
||||||
| ++++++++
|
| ++++++++
|
||||||
@ -55,7 +55,7 @@ note: this call may capture more lifetimes than intended, because Rust 2024 has
|
|||||||
|
|
|
|
||||||
LL | let a = display_len(&x);
|
LL | let a = display_len(&x);
|
||||||
| ^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^
|
||||||
help: add a precise capturing bound to avoid overcapturing
|
help: use the precise capturing `use<...>` syntax to make the captures explicit
|
||||||
|
|
|
|
||||||
LL | fn display_len<T>(x: &Vec<T>) -> impl Display + use<T> {
|
LL | fn display_len<T>(x: &Vec<T>) -> impl Display + use<T> {
|
||||||
| ++++++++
|
| ++++++++
|
||||||
@ -80,7 +80,7 @@ note: this call may capture more lifetimes than intended, because Rust 2024 has
|
|||||||
|
|
|
|
||||||
LL | let a = display_len(&x);
|
LL | let a = display_len(&x);
|
||||||
| ^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^
|
||||||
help: add a precise capturing bound to avoid overcapturing
|
help: use the precise capturing `use<...>` syntax to make the captures explicit
|
||||||
|
|
|
|
||||||
LL | fn display_len<T>(x: &Vec<T>) -> impl Display + use<T> {
|
LL | fn display_len<T>(x: &Vec<T>) -> impl Display + use<T> {
|
||||||
| ++++++++
|
| ++++++++
|
||||||
@ -106,7 +106,7 @@ note: this call may capture more lifetimes than intended, because Rust 2024 has
|
|||||||
|
|
|
|
||||||
LL | let a = display_len_mut(&mut x);
|
LL | let a = display_len_mut(&mut x);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
help: add a precise capturing bound to avoid overcapturing
|
help: use the precise capturing `use<...>` syntax to make the captures explicit
|
||||||
|
|
|
|
||||||
LL | fn display_len_mut<T>(x: &mut Vec<T>) -> impl Display + use<T> {
|
LL | fn display_len_mut<T>(x: &mut Vec<T>) -> impl Display + use<T> {
|
||||||
| ++++++++
|
| ++++++++
|
||||||
@ -131,7 +131,7 @@ note: this call may capture more lifetimes than intended, because Rust 2024 has
|
|||||||
|
|
|
|
||||||
LL | let a = display_len_mut(&mut x);
|
LL | let a = display_len_mut(&mut x);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
help: add a precise capturing bound to avoid overcapturing
|
help: use the precise capturing `use<...>` syntax to make the captures explicit
|
||||||
|
|
|
|
||||||
LL | fn display_len_mut<T>(x: &mut Vec<T>) -> impl Display + use<T> {
|
LL | fn display_len_mut<T>(x: &mut Vec<T>) -> impl Display + use<T> {
|
||||||
| ++++++++
|
| ++++++++
|
||||||
@ -156,7 +156,7 @@ note: this call may capture more lifetimes than intended, because Rust 2024 has
|
|||||||
|
|
|
|
||||||
LL | let a = display_len_mut(&mut x);
|
LL | let a = display_len_mut(&mut x);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
help: add a precise capturing bound to avoid overcapturing
|
help: use the precise capturing `use<...>` syntax to make the captures explicit
|
||||||
|
|
|
|
||||||
LL | fn display_len_mut<T>(x: &mut Vec<T>) -> impl Display + use<T> {
|
LL | fn display_len_mut<T>(x: &mut Vec<T>) -> impl Display + use<T> {
|
||||||
| ++++++++
|
| ++++++++
|
||||||
@ -182,7 +182,7 @@ note: this call may capture more lifetimes than intended, because Rust 2024 has
|
|||||||
|
|
|
|
||||||
LL | let a = display_field(&s.f);
|
LL | let a = display_field(&s.f);
|
||||||
| ^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
help: add a precise capturing bound to avoid overcapturing
|
help: use the precise capturing `use<...>` syntax to make the captures explicit
|
||||||
|
|
|
|
||||||
LL | fn display_field<T: Copy + Display>(t: &T) -> impl Display + use<T> {
|
LL | fn display_field<T: Copy + Display>(t: &T) -> impl Display + use<T> {
|
||||||
| ++++++++
|
| ++++++++
|
||||||
@ -204,7 +204,7 @@ note: this call may capture more lifetimes than intended, because Rust 2024 has
|
|||||||
|
|
|
|
||||||
LL | let a = display_field(&mut s.f);
|
LL | let a = display_field(&mut s.f);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
help: add a precise capturing bound to avoid overcapturing
|
help: use the precise capturing `use<...>` syntax to make the captures explicit
|
||||||
|
|
|
|
||||||
LL | fn display_field<T: Copy + Display>(t: &T) -> impl Display + use<T> {
|
LL | fn display_field<T: Copy + Display>(t: &T) -> impl Display + use<T> {
|
||||||
| ++++++++
|
| ++++++++
|
||||||
@ -226,7 +226,7 @@ note: this call may capture more lifetimes than intended, because Rust 2024 has
|
|||||||
|
|
|
|
||||||
LL | let a = display_field(&mut s.f);
|
LL | let a = display_field(&mut s.f);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
help: add a precise capturing bound to avoid overcapturing
|
help: use the precise capturing `use<...>` syntax to make the captures explicit
|
||||||
|
|
|
|
||||||
LL | fn display_field<T: Copy + Display>(t: &T) -> impl Display + use<T> {
|
LL | fn display_field<T: Copy + Display>(t: &T) -> impl Display + use<T> {
|
||||||
| ++++++++
|
| ++++++++
|
||||||
@ -252,7 +252,7 @@ note: this call may capture more lifetimes than intended, because Rust 2024 has
|
|||||||
|
|
|
|
||||||
LL | x = display_len(&z.f);
|
LL | x = display_len(&z.f);
|
||||||
| ^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^
|
||||||
help: add a precise capturing bound to avoid overcapturing
|
help: use the precise capturing `use<...>` syntax to make the captures explicit
|
||||||
|
|
|
|
||||||
LL | fn display_len<T>(x: &Vec<T>) -> impl Display + use<T> {
|
LL | fn display_len<T>(x: &Vec<T>) -> impl Display + use<T> {
|
||||||
| ++++++++
|
| ++++++++
|
||||||
@ -273,12 +273,46 @@ note: this call may capture more lifetimes than intended, because Rust 2024 has
|
|||||||
LL | let x = { let x = display_len(&mut vec![0]); x };
|
LL | let x = { let x = display_len(&mut vec![0]); x };
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
= note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
help: add a precise capturing bound to avoid overcapturing
|
help: use the precise capturing `use<...>` syntax to make the captures explicit
|
||||||
|
|
|
|
||||||
LL | fn display_len<T>(x: &Vec<T>) -> impl Display + use<T> {
|
LL | fn display_len<T>(x: &Vec<T>) -> impl Display + use<T> {
|
||||||
| ++++++++
|
| ++++++++
|
||||||
|
|
||||||
error: aborting due to 12 previous errors
|
error[E0505]: cannot move out of `x` because it is borrowed
|
||||||
|
--> $DIR/migration-note.rs:199:10
|
||||||
|
|
|
||||||
|
LL | let x = String::new();
|
||||||
|
| - binding `x` declared here
|
||||||
|
LL |
|
||||||
|
LL | let y = capture_apit(&x);
|
||||||
|
| -- borrow of `x` occurs here
|
||||||
|
...
|
||||||
|
LL | drop(x);
|
||||||
|
| ^ move out of `x` occurs here
|
||||||
|
...
|
||||||
|
LL | }
|
||||||
|
| - borrow might be used here, when `y` is dropped and runs the destructor for type `impl Sized`
|
||||||
|
|
|
||||||
|
note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules
|
||||||
|
--> $DIR/migration-note.rs:196:13
|
||||||
|
|
|
||||||
|
LL | let y = capture_apit(&x);
|
||||||
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
note: you could use a `use<...>` bound to explicitly specify captures, but argument-position `impl Trait`s are not nameable
|
||||||
|
--> $DIR/migration-note.rs:190:21
|
||||||
|
|
|
||||||
|
LL | fn capture_apit(x: &impl Sized) -> impl Sized {}
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
help: use the precise capturing `use<...>` syntax to make the captures explicit
|
||||||
|
|
|
||||||
|
LL | fn capture_apit<T: Sized>(x: &T) -> impl Sized + use<T> {}
|
||||||
|
| ++++++++++ ~ ++++++++
|
||||||
|
help: consider cloning the value if the performance cost is acceptable
|
||||||
|
|
|
||||||
|
LL | let y = capture_apit(&x.clone());
|
||||||
|
| ++++++++
|
||||||
|
|
||||||
|
error: aborting due to 13 previous errors
|
||||||
|
|
||||||
Some errors have detailed explanations: E0499, E0502, E0503, E0505, E0506, E0597, E0716.
|
Some errors have detailed explanations: E0499, E0502, E0503, E0505, E0506, E0597, E0716.
|
||||||
For more information about an error, try `rustc --explain E0499`.
|
For more information about an error, try `rustc --explain E0499`.
|
||||||
|
@ -29,4 +29,12 @@ fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized + use<>> {}
|
|||||||
//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
|
//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
|
||||||
//~| WARN this changes meaning in Rust 2024
|
//~| WARN this changes meaning in Rust 2024
|
||||||
|
|
||||||
|
fn apit<T: Sized>(_: &T) -> impl Sized + use<T> {}
|
||||||
|
//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
|
||||||
|
//~| WARN this changes meaning in Rust 2024
|
||||||
|
|
||||||
|
fn apit2<U, T: Sized>(_: &T, _: U) -> impl Sized + use<U, T> {}
|
||||||
|
//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
|
||||||
|
//~| WARN this changes meaning in Rust 2024
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
@ -29,4 +29,12 @@ fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized> {}
|
|||||||
//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
|
//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
|
||||||
//~| WARN this changes meaning in Rust 2024
|
//~| WARN this changes meaning in Rust 2024
|
||||||
|
|
||||||
|
fn apit(_: &impl Sized) -> impl Sized {}
|
||||||
|
//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
|
||||||
|
//~| WARN this changes meaning in Rust 2024
|
||||||
|
|
||||||
|
fn apit2<U>(_: &impl Sized, _: U) -> impl Sized {}
|
||||||
|
//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
|
||||||
|
//~| WARN this changes meaning in Rust 2024
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
@ -79,5 +79,53 @@ help: use the precise capturing `use<...>` syntax to make the captures explicit
|
|||||||
LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized + use<>> {}
|
LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized + use<>> {}
|
||||||
| +++++++
|
| +++++++
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024
|
||||||
|
--> $DIR/overcaptures-2024.rs:32:28
|
||||||
|
|
|
||||||
|
LL | fn apit(_: &impl Sized) -> impl Sized {}
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= warning: this changes meaning in Rust 2024
|
||||||
|
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/rpit-lifetime-capture.html>
|
||||||
|
note: specifically, this lifetime is in scope but not mentioned in the type's bounds
|
||||||
|
--> $DIR/overcaptures-2024.rs:32:12
|
||||||
|
|
|
||||||
|
LL | fn apit(_: &impl Sized) -> impl Sized {}
|
||||||
|
| ^
|
||||||
|
= note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024
|
||||||
|
note: you could use a `use<...>` bound to explicitly specify captures, but argument-position `impl Trait`s are not nameable
|
||||||
|
--> $DIR/overcaptures-2024.rs:32:13
|
||||||
|
|
|
||||||
|
LL | fn apit(_: &impl Sized) -> impl Sized {}
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
help: use the precise capturing `use<...>` syntax to make the captures explicit
|
||||||
|
|
|
||||||
|
LL | fn apit<T: Sized>(_: &T) -> impl Sized + use<T> {}
|
||||||
|
| ++++++++++ ~ ++++++++
|
||||||
|
|
||||||
|
error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024
|
||||||
|
--> $DIR/overcaptures-2024.rs:36:38
|
||||||
|
|
|
||||||
|
LL | fn apit2<U>(_: &impl Sized, _: U) -> impl Sized {}
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= warning: this changes meaning in Rust 2024
|
||||||
|
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/rpit-lifetime-capture.html>
|
||||||
|
note: specifically, this lifetime is in scope but not mentioned in the type's bounds
|
||||||
|
--> $DIR/overcaptures-2024.rs:36:16
|
||||||
|
|
|
||||||
|
LL | fn apit2<U>(_: &impl Sized, _: U) -> impl Sized {}
|
||||||
|
| ^
|
||||||
|
= note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024
|
||||||
|
note: you could use a `use<...>` bound to explicitly specify captures, but argument-position `impl Trait`s are not nameable
|
||||||
|
--> $DIR/overcaptures-2024.rs:36:17
|
||||||
|
|
|
||||||
|
LL | fn apit2<U>(_: &impl Sized, _: U) -> impl Sized {}
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
help: use the precise capturing `use<...>` syntax to make the captures explicit
|
||||||
|
|
|
||||||
|
LL | fn apit2<U, T: Sized>(_: &T, _: U) -> impl Sized + use<U, T> {}
|
||||||
|
| ++++++++++ ~ +++++++++++
|
||||||
|
|
||||||
|
error: aborting due to 6 previous errors
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user