Auto merge of #123468 - compiler-errors:precise-capturing, r=oli-obk

Implement syntax for `impl Trait` to specify its captures explicitly (`feature(precise_capturing)`)

Implements `impl use<'a, 'b, T, U> Sized` syntax that allows users to explicitly list the captured parameters for an opaque, rather than inferring it from the opaque's bounds (or capturing *all* lifetimes under 2024-edition capture rules). This allows us to exclude some implicit captures, so this syntax may be used as a migration strategy for changes due to #117587.

We represent this list of captured params as `PreciseCapturingArg` in AST and HIR, resolving them between `rustc_resolve` and `resolve_bound_vars`. Later on, we validate that the opaques only capture the parameters in this list.

We artificially limit the feature to *require* mentioning all type and const parameters, since we don't currently have support for non-lifetime bivariant generics. This can be relaxed in the future.

We also may need to limit this to require naming *all* lifetime parameters for RPITIT, since GATs have no variance. I have to investigate this. This can also be relaxed in the future.

r? `@oli-obk`

Tracking issue:

- https://github.com/rust-lang/rust/issues/123432
This commit is contained in:
bors 2024-04-16 11:22:35 +00:00
commit 4e1f5d90bc
55 changed files with 1033 additions and 71 deletions

View file

@ -63,7 +63,7 @@ impl fmt::Debug for Label {
/// A "Lifetime" is an annotation of the scope in which variable /// A "Lifetime" is an annotation of the scope in which variable
/// can be used, e.g. `'a` in `&'a i32`. /// can be used, e.g. `'a` in `&'a i32`.
#[derive(Clone, Encodable, Decodable, Copy, PartialEq, Eq)] #[derive(Clone, Encodable, Decodable, Copy, PartialEq, Eq, Hash)]
pub struct Lifetime { pub struct Lifetime {
pub id: NodeId, pub id: NodeId,
pub ident: Ident, pub ident: Ident,
@ -2132,7 +2132,7 @@ pub enum TyKind {
/// The `NodeId` exists to prevent lowering from having to /// The `NodeId` exists to prevent lowering from having to
/// generate `NodeId`s on the fly, which would complicate /// generate `NodeId`s on the fly, which would complicate
/// the generation of opaque `type Foo = impl Trait` items significantly. /// the generation of opaque `type Foo = impl Trait` items significantly.
ImplTrait(NodeId, GenericBounds), ImplTrait(NodeId, GenericBounds, Option<P<(ThinVec<PreciseCapturingArg>, Span)>>),
/// No-op; kept solely so that we can pretty-print faithfully. /// No-op; kept solely so that we can pretty-print faithfully.
Paren(P<Ty>), Paren(P<Ty>),
/// Unused for now. /// Unused for now.
@ -2188,6 +2188,14 @@ pub enum TraitObjectSyntax {
None, None,
} }
#[derive(Clone, Encodable, Decodable, Debug)]
pub enum PreciseCapturingArg {
/// Lifetime parameter
Lifetime(Lifetime),
/// Type or const parameter
Arg(Path, NodeId),
}
/// Inline assembly operand explicit register or register class. /// Inline assembly operand explicit register or register class.
/// ///
/// E.g., `"eax"` as in `asm!("mov eax, 2", out("eax") result)`. /// E.g., `"eax"` as in `asm!("mov eax, 2", out("eax") result)`.

View file

@ -259,6 +259,10 @@ pub trait MutVisitor: Sized {
noop_visit_param_bound(tpb, self); noop_visit_param_bound(tpb, self);
} }
fn visit_precise_capturing_arg(&mut self, arg: &mut PreciseCapturingArg) {
noop_visit_precise_capturing_arg(arg, self);
}
fn visit_mt(&mut self, mt: &mut MutTy) { fn visit_mt(&mut self, mt: &mut MutTy) {
noop_visit_mt(mt, self); noop_visit_mt(mt, self);
} }
@ -518,9 +522,14 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
TyKind::TraitObject(bounds, _syntax) => { TyKind::TraitObject(bounds, _syntax) => {
visit_vec(bounds, |bound| vis.visit_param_bound(bound)) visit_vec(bounds, |bound| vis.visit_param_bound(bound))
} }
TyKind::ImplTrait(id, bounds) => { TyKind::ImplTrait(id, bounds, precise_capturing) => {
vis.visit_id(id); vis.visit_id(id);
visit_vec(bounds, |bound| vis.visit_param_bound(bound)); visit_vec(bounds, |bound| vis.visit_param_bound(bound));
if let Some((precise_capturing, _span)) = precise_capturing.as_deref_mut() {
for arg in precise_capturing {
vis.visit_precise_capturing_arg(arg);
}
}
} }
TyKind::MacCall(mac) => vis.visit_mac_call(mac), TyKind::MacCall(mac) => vis.visit_mac_call(mac),
TyKind::AnonStruct(id, fields) | TyKind::AnonUnion(id, fields) => { TyKind::AnonStruct(id, fields) | TyKind::AnonUnion(id, fields) => {
@ -914,6 +923,18 @@ pub fn noop_visit_param_bound<T: MutVisitor>(pb: &mut GenericBound, vis: &mut T)
} }
} }
pub fn noop_visit_precise_capturing_arg<T: MutVisitor>(arg: &mut PreciseCapturingArg, vis: &mut T) {
match arg {
PreciseCapturingArg::Lifetime(lt) => {
vis.visit_lifetime(lt);
}
PreciseCapturingArg::Arg(path, id) => {
vis.visit_path(path);
vis.visit_id(id);
}
}
}
pub fn noop_flat_map_generic_param<T: MutVisitor>( pub fn noop_flat_map_generic_param<T: MutVisitor>(
mut param: GenericParam, mut param: GenericParam,
vis: &mut T, vis: &mut T,

View file

@ -184,6 +184,9 @@ pub trait Visitor<'ast>: Sized {
fn visit_param_bound(&mut self, bounds: &'ast GenericBound, _ctxt: BoundKind) -> Self::Result { fn visit_param_bound(&mut self, bounds: &'ast GenericBound, _ctxt: BoundKind) -> Self::Result {
walk_param_bound(self, bounds) walk_param_bound(self, bounds)
} }
fn visit_precise_capturing_arg(&mut self, arg: &'ast PreciseCapturingArg) {
walk_precise_capturing_arg(self, arg);
}
fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef) -> Self::Result { fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef) -> Self::Result {
walk_poly_trait_ref(self, t) walk_poly_trait_ref(self, t)
} }
@ -457,8 +460,13 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result {
TyKind::TraitObject(bounds, ..) => { TyKind::TraitObject(bounds, ..) => {
walk_list!(visitor, visit_param_bound, bounds, BoundKind::TraitObject); walk_list!(visitor, visit_param_bound, bounds, BoundKind::TraitObject);
} }
TyKind::ImplTrait(_, bounds) => { TyKind::ImplTrait(_, bounds, precise_capturing) => {
walk_list!(visitor, visit_param_bound, bounds, BoundKind::Impl); walk_list!(visitor, visit_param_bound, bounds, BoundKind::Impl);
if let Some((precise_capturing, _span)) = precise_capturing.as_deref() {
for arg in precise_capturing {
try_visit!(visitor.visit_precise_capturing_arg(arg));
}
}
} }
TyKind::Typeof(expression) => try_visit!(visitor.visit_anon_const(expression)), TyKind::Typeof(expression) => try_visit!(visitor.visit_anon_const(expression)),
TyKind::Infer | TyKind::ImplicitSelf | TyKind::Dummy | TyKind::Err(_) => {} TyKind::Infer | TyKind::ImplicitSelf | TyKind::Dummy | TyKind::Err(_) => {}
@ -637,6 +645,20 @@ pub fn walk_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a GenericB
} }
} }
pub fn walk_precise_capturing_arg<'a, V: Visitor<'a>>(
visitor: &mut V,
arg: &'a PreciseCapturingArg,
) {
match arg {
PreciseCapturingArg::Lifetime(lt) => {
visitor.visit_lifetime(lt, LifetimeCtxt::GenericArg);
}
PreciseCapturingArg::Arg(path, id) => {
visitor.visit_path(path, *id);
}
}
}
pub fn walk_generic_param<'a, V: Visitor<'a>>( pub fn walk_generic_param<'a, V: Visitor<'a>>(
visitor: &mut V, visitor: &mut V,
param: &'a GenericParam, param: &'a GenericParam,

View file

@ -127,6 +127,8 @@ ast_lowering_never_pattern_with_guard =
a guard on a never pattern will never be run a guard on a never pattern will never be run
.suggestion = remove this guard .suggestion = remove this guard
ast_lowering_no_precise_captures_on_apit = `use<...>` precise capturing syntax not allowed on argument-position `impl Trait`
ast_lowering_previously_used_here = previously used here ast_lowering_previously_used_here = previously used here
ast_lowering_register1 = register `{$reg1_name}` ast_lowering_register1 = register `{$reg1_name}`

View file

@ -414,3 +414,10 @@ pub(crate) struct AsyncBoundOnlyForFnTraits {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
} }
#[derive(Diagnostic)]
#[diag(ast_lowering_no_precise_captures_on_apit)]
pub(crate) struct NoPreciseCapturesOnApit {
#[primary_span]
pub span: Span,
}

View file

@ -385,4 +385,21 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
fn visit_pattern_type_pattern(&mut self, p: &'hir hir::Pat<'hir>) { fn visit_pattern_type_pattern(&mut self, p: &'hir hir::Pat<'hir>) {
self.visit_pat(p) self.visit_pat(p)
} }
fn visit_precise_capturing_arg(
&mut self,
arg: &'hir PreciseCapturingArg<'hir>,
) -> Self::Result {
match arg {
PreciseCapturingArg::Lifetime(_) => {
// This is represented as a `Node::Lifetime`, intravisit will get to it below.
}
PreciseCapturingArg::Param(param) => self.insert(
param.ident.span,
param.hir_id,
Node::PreciseCapturingNonLifetimeArg(param),
),
}
intravisit::walk_precise_capturing_arg(self, arg);
}
} }

View file

@ -48,6 +48,7 @@ use rustc_ast::{self as ast, *};
use rustc_ast_pretty::pprust; use rustc_ast_pretty::pprust;
use rustc_data_structures::captures::Captures; use rustc_data_structures::captures::Captures;
use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::sorted_map::SortedMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::Lrc; use rustc_data_structures::sync::Lrc;
@ -1398,7 +1399,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}); });
hir::TyKind::TraitObject(bounds, lifetime_bound, *kind) hir::TyKind::TraitObject(bounds, lifetime_bound, *kind)
} }
TyKind::ImplTrait(def_node_id, bounds) => { TyKind::ImplTrait(def_node_id, bounds, precise_capturing) => {
let span = t.span; let span = t.span;
match itctx { match itctx {
ImplTraitContext::OpaqueTy { origin, fn_kind } => self.lower_opaque_impl_trait( ImplTraitContext::OpaqueTy { origin, fn_kind } => self.lower_opaque_impl_trait(
@ -1408,8 +1409,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
bounds, bounds,
fn_kind, fn_kind,
itctx, itctx,
precise_capturing.as_deref().map(|(args, _)| args.as_slice()),
), ),
ImplTraitContext::Universal => { ImplTraitContext::Universal => {
if let Some(&(_, span)) = precise_capturing.as_deref() {
self.tcx.dcx().emit_err(errors::NoPreciseCapturesOnApit { span });
};
let span = t.span; let span = t.span;
// HACK: pprust breaks strings with newlines when the type // HACK: pprust breaks strings with newlines when the type
@ -1520,6 +1525,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
bounds: &GenericBounds, bounds: &GenericBounds,
fn_kind: Option<FnDeclKind>, fn_kind: Option<FnDeclKind>,
itctx: ImplTraitContext, itctx: ImplTraitContext,
precise_capturing_args: Option<&[PreciseCapturingArg]>,
) -> hir::TyKind<'hir> { ) -> hir::TyKind<'hir> {
// Make sure we know that some funky desugaring has been going on here. // Make sure we know that some funky desugaring has been going on here.
// This is a first: there is code in other places like for loop // This is a first: there is code in other places like for loop
@ -1528,7 +1534,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// frequently opened issues show. // frequently opened issues show.
let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None); let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);
let captured_lifetimes_to_duplicate = match origin { let captured_lifetimes_to_duplicate =
if let Some(precise_capturing) = precise_capturing_args {
// We'll actually validate these later on; all we need is the list of
// lifetimes to duplicate during this portion of lowering.
precise_capturing
.iter()
.filter_map(|arg| match arg {
PreciseCapturingArg::Lifetime(lt) => Some(*lt),
PreciseCapturingArg::Arg(..) => None,
})
// Add in all the lifetimes mentioned in the bounds. We will error
// them out later, but capturing them here is important to make sure
// they actually get resolved in resolve_bound_vars.
.chain(lifetime_collector::lifetimes_in_bounds(self.resolver, bounds))
.collect()
} else {
match origin {
hir::OpaqueTyOrigin::TyAlias { .. } => { hir::OpaqueTyOrigin::TyAlias { .. } => {
// type alias impl trait and associated type position impl trait were // type alias impl trait and associated type position impl trait were
// decided to capture all in-scope lifetimes, which we collect for // decided to capture all in-scope lifetimes, which we collect for
@ -1563,6 +1585,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
hir::OpaqueTyOrigin::AsyncFn(..) => { hir::OpaqueTyOrigin::AsyncFn(..) => {
unreachable!("should be using `lower_async_fn_ret_ty`") unreachable!("should be using `lower_async_fn_ret_ty`")
} }
}
}; };
debug!(?captured_lifetimes_to_duplicate); debug!(?captured_lifetimes_to_duplicate);
@ -1573,6 +1596,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
captured_lifetimes_to_duplicate, captured_lifetimes_to_duplicate,
span, span,
opaque_ty_span, opaque_ty_span,
precise_capturing_args,
|this| this.lower_param_bounds(bounds, itctx), |this| this.lower_param_bounds(bounds, itctx),
) )
} }
@ -1582,9 +1606,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
opaque_ty_node_id: NodeId, opaque_ty_node_id: NodeId,
origin: hir::OpaqueTyOrigin, origin: hir::OpaqueTyOrigin,
in_trait: bool, in_trait: bool,
captured_lifetimes_to_duplicate: Vec<Lifetime>, captured_lifetimes_to_duplicate: FxIndexSet<Lifetime>,
span: Span, span: Span,
opaque_ty_span: Span, opaque_ty_span: Span,
precise_capturing_args: Option<&[PreciseCapturingArg]>,
lower_item_bounds: impl FnOnce(&mut Self) -> &'hir [hir::GenericBound<'hir>], lower_item_bounds: impl FnOnce(&mut Self) -> &'hir [hir::GenericBound<'hir>],
) -> hir::TyKind<'hir> { ) -> hir::TyKind<'hir> {
let opaque_ty_def_id = self.create_def( let opaque_ty_def_id = self.create_def(
@ -1671,8 +1696,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// Install the remapping from old to new (if any). This makes sure that // Install the remapping from old to new (if any). This makes sure that
// any lifetimes that would have resolved to the def-id of captured // any lifetimes that would have resolved to the def-id of captured
// lifetimes are remapped to the new *synthetic* lifetimes of the opaque. // lifetimes are remapped to the new *synthetic* lifetimes of the opaque.
let bounds = this let (bounds, precise_capturing_args) =
.with_remapping(captured_to_synthesized_mapping, |this| lower_item_bounds(this)); this.with_remapping(captured_to_synthesized_mapping, |this| {
(
lower_item_bounds(this),
precise_capturing_args.map(|precise_capturing| {
this.lower_precise_capturing_args(precise_capturing)
}),
)
});
let generic_params = let generic_params =
this.arena.alloc_from_iter(synthesized_lifetime_definitions.iter().map( this.arena.alloc_from_iter(synthesized_lifetime_definitions.iter().map(
@ -1717,6 +1749,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
origin, origin,
lifetime_mapping, lifetime_mapping,
in_trait, in_trait,
precise_capturing_args,
}; };
// Generate an `type Foo = impl Trait;` declaration. // Generate an `type Foo = impl Trait;` declaration.
@ -1749,6 +1782,30 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
) )
} }
fn lower_precise_capturing_args(
&mut self,
precise_capturing_args: &[PreciseCapturingArg],
) -> &'hir [hir::PreciseCapturingArg<'hir>] {
self.arena.alloc_from_iter(precise_capturing_args.iter().map(|arg| match arg {
PreciseCapturingArg::Lifetime(lt) => {
hir::PreciseCapturingArg::Lifetime(self.lower_lifetime(lt))
}
PreciseCapturingArg::Arg(path, id) => {
let [segment] = path.segments.as_slice() else {
panic!();
};
let res = self.resolver.get_partial_res(*id).map_or(Res::Err, |partial_res| {
partial_res.full_res().expect("no partial res expected for precise capture arg")
});
hir::PreciseCapturingArg::Param(hir::PreciseCapturingNonLifetimeArg {
hir_id: self.lower_node_id(*id),
ident: self.lower_ident(segment.ident),
res: self.lower_res(res),
})
}
}))
}
fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Ident] { fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Ident] {
self.arena.alloc_from_iter(decl.inputs.iter().map(|param| match param.pat.kind { self.arena.alloc_from_iter(decl.inputs.iter().map(|param| match param.pat.kind {
PatKind::Ident(_, ident, _) => self.lower_ident(ident), PatKind::Ident(_, ident, _) => self.lower_ident(ident),
@ -1889,7 +1946,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let opaque_ty_span = let opaque_ty_span =
self.mark_span_with_reason(DesugaringKind::Async, span, allowed_features); self.mark_span_with_reason(DesugaringKind::Async, span, allowed_features);
let captured_lifetimes: Vec<_> = self let captured_lifetimes = self
.resolver .resolver
.take_extra_lifetime_params(opaque_ty_node_id) .take_extra_lifetime_params(opaque_ty_node_id)
.into_iter() .into_iter()
@ -1903,6 +1960,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
captured_lifetimes, captured_lifetimes,
span, span,
opaque_ty_span, opaque_ty_span,
None,
|this| { |this| {
let bound = this.lower_coroutine_fn_output_type_to_bound( let bound = this.lower_coroutine_fn_output_type_to_bound(
output, output,

View file

@ -1,6 +1,7 @@
use super::ResolverAstLoweringExt; use super::ResolverAstLoweringExt;
use rustc_ast::visit::{self, BoundKind, LifetimeCtxt, Visitor}; use rustc_ast::visit::{self, BoundKind, LifetimeCtxt, Visitor};
use rustc_ast::{GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind}; use rustc_ast::{GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind};
use rustc_data_structures::fx::FxIndexSet;
use rustc_hir::def::{DefKind, LifetimeRes, Res}; use rustc_hir::def::{DefKind, LifetimeRes, Res};
use rustc_middle::span_bug; use rustc_middle::span_bug;
use rustc_middle::ty::ResolverAstLowering; use rustc_middle::ty::ResolverAstLowering;
@ -10,27 +11,23 @@ use rustc_span::Span;
struct LifetimeCollectVisitor<'ast> { struct LifetimeCollectVisitor<'ast> {
resolver: &'ast ResolverAstLowering, resolver: &'ast ResolverAstLowering,
current_binders: Vec<NodeId>, current_binders: Vec<NodeId>,
collected_lifetimes: Vec<Lifetime>, collected_lifetimes: FxIndexSet<Lifetime>,
} }
impl<'ast> LifetimeCollectVisitor<'ast> { impl<'ast> LifetimeCollectVisitor<'ast> {
fn new(resolver: &'ast ResolverAstLowering) -> Self { fn new(resolver: &'ast ResolverAstLowering) -> Self {
Self { resolver, current_binders: Vec::new(), collected_lifetimes: Vec::new() } Self { resolver, current_binders: Vec::new(), collected_lifetimes: FxIndexSet::default() }
} }
fn record_lifetime_use(&mut self, lifetime: Lifetime) { fn record_lifetime_use(&mut self, lifetime: Lifetime) {
match self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error) { match self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error) {
LifetimeRes::Param { binder, .. } | LifetimeRes::Fresh { binder, .. } => { LifetimeRes::Param { binder, .. } | LifetimeRes::Fresh { binder, .. } => {
if !self.current_binders.contains(&binder) { if !self.current_binders.contains(&binder) {
if !self.collected_lifetimes.contains(&lifetime) { self.collected_lifetimes.insert(lifetime);
self.collected_lifetimes.push(lifetime);
}
} }
} }
LifetimeRes::Static | LifetimeRes::Error => { LifetimeRes::Static | LifetimeRes::Error => {
if !self.collected_lifetimes.contains(&lifetime) { self.collected_lifetimes.insert(lifetime);
self.collected_lifetimes.push(lifetime);
}
} }
LifetimeRes::Infer => {} LifetimeRes::Infer => {}
res => { res => {
@ -111,7 +108,7 @@ impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> {
pub(crate) fn lifetimes_in_bounds( pub(crate) fn lifetimes_in_bounds(
resolver: &ResolverAstLowering, resolver: &ResolverAstLowering,
bounds: &GenericBounds, bounds: &GenericBounds,
) -> Vec<Lifetime> { ) -> FxIndexSet<Lifetime> {
let mut visitor = LifetimeCollectVisitor::new(resolver); let mut visitor = LifetimeCollectVisitor::new(resolver);
for bound in bounds { for bound in bounds {
visitor.visit_param_bound(bound, BoundKind::Bound); visitor.visit_param_bound(bound, BoundKind::Bound);

View file

@ -737,7 +737,7 @@ impl<'a> AstValidator<'a> {
} }
} }
} }
TyKind::ImplTrait(_, bounds) => { TyKind::ImplTrait(_, bounds, _) => {
if self.is_impl_trait_banned { if self.is_impl_trait_banned {
self.dcx().emit_err(errors::ImplTraitPath { span: ty.span }); self.dcx().emit_err(errors::ImplTraitPath { span: ty.span });
} }

View file

@ -569,6 +569,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
gate_all!(fn_delegation, "functions delegation is not yet fully implemented"); gate_all!(fn_delegation, "functions delegation is not yet fully implemented");
gate_all!(postfix_match, "postfix match is experimental"); gate_all!(postfix_match, "postfix match is experimental");
gate_all!(mut_ref, "mutable by-reference bindings are experimental"); gate_all!(mut_ref, "mutable by-reference bindings are experimental");
gate_all!(precise_capturing, "precise captures on `impl Trait` are experimental");
if !visitor.features.never_patterns { if !visitor.features.never_patterns {
if let Some(spans) = spans.get(&sym::never_patterns) { if let Some(spans) = spans.get(&sym::never_patterns) {

View file

@ -1150,8 +1150,17 @@ impl<'a> State<'a> {
} }
self.print_type_bounds(bounds); self.print_type_bounds(bounds);
} }
ast::TyKind::ImplTrait(_, bounds) => { ast::TyKind::ImplTrait(_, bounds, precise_capturing_args) => {
self.word_nbsp("impl"); self.word_nbsp("impl");
if let Some((precise_capturing_args, ..)) = precise_capturing_args.as_deref() {
self.word("use");
self.word("<");
self.commasep(Inconsistent, precise_capturing_args, |s, arg| match arg {
ast::PreciseCapturingArg::Arg(p, _) => s.print_path(p, false, 0),
ast::PreciseCapturingArg::Lifetime(lt) => s.print_lifetime(*lt),
});
self.word(">")
}
self.print_type_bounds(bounds); self.print_type_bounds(bounds);
} }
ast::TyKind::Array(ty, length) => { ast::TyKind::Array(ty, length) => {

View file

@ -567,6 +567,8 @@ declare_features! (
(unstable, optimize_attribute, "1.34.0", Some(54882)), (unstable, optimize_attribute, "1.34.0", Some(54882)),
/// Allows postfix match `expr.match { ... }` /// Allows postfix match `expr.match { ... }`
(unstable, postfix_match, "CURRENT_RUSTC_VERSION", Some(121618)), (unstable, postfix_match, "CURRENT_RUSTC_VERSION", Some(121618)),
/// Allows `use<'a, 'b, A, B>` in `impl use<...> Trait` for precise capture of generic args.
(incomplete, precise_capturing, "CURRENT_RUSTC_VERSION", Some(123432)),
/// Allows macro attributes on expressions, statements and non-inline modules. /// Allows macro attributes on expressions, statements and non-inline modules.
(unstable, proc_macro_hygiene, "1.30.0", Some(54727)), (unstable, proc_macro_hygiene, "1.30.0", Some(54727)),
/// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions. /// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions.

View file

@ -2557,6 +2557,27 @@ pub struct OpaqueTy<'hir> {
/// originating from a trait method. This makes it so that the opaque is /// originating from a trait method. This makes it so that the opaque is
/// lowered as an associated type. /// lowered as an associated type.
pub in_trait: bool, pub in_trait: bool,
/// List of arguments captured via `impl use<'a, P, ...> Trait` syntax.
pub precise_capturing_args: Option<&'hir [PreciseCapturingArg<'hir>]>,
}
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum PreciseCapturingArg<'hir> {
Lifetime(&'hir Lifetime),
/// Non-lifetime argument (type or const)
Param(PreciseCapturingNonLifetimeArg),
}
/// We need to have a [`Node`] for the [`HirId`] that we attach the type/const param
/// resolution to. Lifetimes don't have this problem, and for them, it's actually
/// kind of detrimental to use a custom node type versus just using [`Lifetime`],
/// since resolve_bound_vars operates on `Lifetime`s.
// FIXME(precise_capturing): Investigate storing this as a path instead?
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct PreciseCapturingNonLifetimeArg {
pub hir_id: HirId,
pub ident: Ident,
pub res: Res,
} }
/// From whence the opaque type came. /// From whence the opaque type came.
@ -3535,6 +3556,7 @@ pub enum Node<'hir> {
WhereBoundPredicate(&'hir WhereBoundPredicate<'hir>), WhereBoundPredicate(&'hir WhereBoundPredicate<'hir>),
// FIXME: Merge into `Node::Infer`. // FIXME: Merge into `Node::Infer`.
ArrayLenInfer(&'hir InferArg), ArrayLenInfer(&'hir InferArg),
PreciseCapturingNonLifetimeArg(&'hir PreciseCapturingNonLifetimeArg),
// Created by query feeding // Created by query feeding
Synthetic, Synthetic,
// Span by reference to minimize `Node`'s size // Span by reference to minimize `Node`'s size
@ -3571,6 +3593,7 @@ impl<'hir> Node<'hir> {
Node::TypeBinding(b) => Some(b.ident), Node::TypeBinding(b) => Some(b.ident),
Node::PatField(f) => Some(f.ident), Node::PatField(f) => Some(f.ident),
Node::ExprField(f) => Some(f.ident), Node::ExprField(f) => Some(f.ident),
Node::PreciseCapturingNonLifetimeArg(a) => Some(a.ident),
Node::Param(..) Node::Param(..)
| Node::AnonConst(..) | Node::AnonConst(..)
| Node::ConstBlock(..) | Node::ConstBlock(..)

View file

@ -413,6 +413,9 @@ pub trait Visitor<'v>: Sized {
fn visit_param_bound(&mut self, bounds: &'v GenericBound<'v>) -> Self::Result { fn visit_param_bound(&mut self, bounds: &'v GenericBound<'v>) -> Self::Result {
walk_param_bound(self, bounds) walk_param_bound(self, bounds)
} }
fn visit_precise_capturing_arg(&mut self, arg: &'v PreciseCapturingArg<'v>) -> Self::Result {
walk_precise_capturing_arg(self, arg)
}
fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef<'v>) -> Self::Result { fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef<'v>) -> Self::Result {
walk_poly_trait_ref(self, t) walk_poly_trait_ref(self, t)
} }
@ -526,10 +529,15 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
try_visit!(visitor.visit_ty(ty)); try_visit!(visitor.visit_ty(ty));
try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_generics(generics));
} }
ItemKind::OpaqueTy(&OpaqueTy { generics, bounds, .. }) => { ItemKind::OpaqueTy(&OpaqueTy { generics, bounds, precise_capturing_args, .. }) => {
try_visit!(visitor.visit_id(item.hir_id())); try_visit!(visitor.visit_id(item.hir_id()));
try_visit!(walk_generics(visitor, generics)); try_visit!(walk_generics(visitor, generics));
walk_list!(visitor, visit_param_bound, bounds); walk_list!(visitor, visit_param_bound, bounds);
if let Some(precise_capturing_args) = precise_capturing_args {
for arg in precise_capturing_args {
try_visit!(visitor.visit_precise_capturing_arg(arg));
}
}
} }
ItemKind::Enum(ref enum_definition, ref generics) => { ItemKind::Enum(ref enum_definition, ref generics) => {
try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_generics(generics));
@ -1137,6 +1145,16 @@ pub fn walk_param_bound<'v, V: Visitor<'v>>(
} }
} }
pub fn walk_precise_capturing_arg<'v, V: Visitor<'v>>(
visitor: &mut V,
arg: &'v PreciseCapturingArg<'v>,
) -> V::Result {
match *arg {
PreciseCapturingArg::Lifetime(lt) => visitor.visit_lifetime(lt),
PreciseCapturingArg::Param(param) => visitor.visit_id(param.hir_id),
}
}
pub fn walk_poly_trait_ref<'v, V: Visitor<'v>>( pub fn walk_poly_trait_ref<'v, V: Visitor<'v>>(
visitor: &mut V, visitor: &mut V,
trait_ref: &'v PolyTraitRef<'v>, trait_ref: &'v PolyTraitRef<'v>,

View file

@ -37,6 +37,8 @@ hir_analysis_auto_deref_reached_recursion_limit = reached the recursion limit wh
.label = deref recursion limit reached .label = deref recursion limit reached
.help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`) .help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`)
hir_analysis_bad_precise_capture = expected {$kind} parameter in `use<...>` precise captures list, found {$found}
hir_analysis_cannot_capture_late_bound_const = hir_analysis_cannot_capture_late_bound_const =
cannot capture late-bound const parameter in {$what} cannot capture late-bound const parameter in {$what}
.label = parameter defined here .label = parameter defined here
@ -111,6 +113,9 @@ hir_analysis_drop_impl_on_wrong_item =
hir_analysis_drop_impl_reservation = reservation `Drop` impls are not supported hir_analysis_drop_impl_reservation = reservation `Drop` impls are not supported
hir_analysis_duplicate_precise_capture = cannot capture parameter `{$name}` twice
.label = parameter captured again here
hir_analysis_empty_specialization = specialization impl does not specialize any associated items hir_analysis_empty_specialization = specialization impl does not specialize any associated items
.note = impl is a specialization of this impl .note = impl is a specialization of this impl
@ -214,6 +219,13 @@ hir_analysis_late_bound_lifetime_in_apit = `impl Trait` can only mention lifetim
hir_analysis_late_bound_type_in_apit = `impl Trait` can only mention type parameters from an fn or impl hir_analysis_late_bound_type_in_apit = `impl Trait` can only mention type parameters from an fn or impl
.label = type parameter declared here .label = type parameter declared here
hir_analysis_lifetime_must_be_first = lifetime parameter `{$name}` must be listed before non-lifetime parameters
.label = move the lifetime before this parameter
hir_analysis_lifetime_not_captured = `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list
.label = lifetime captured due to being mentioned in the bounds of the `impl Trait`
.param_label = this lifetime parameter is captured
hir_analysis_lifetimes_or_bounds_mismatch_on_trait = hir_analysis_lifetimes_or_bounds_mismatch_on_trait =
lifetime parameters or bounds on {$item_kind} `{$ident}` do not match the trait declaration lifetime parameters or bounds on {$item_kind} `{$ident}` do not match the trait declaration
.label = lifetimes do not match {$item_kind} in trait .label = lifetimes do not match {$item_kind} in trait
@ -339,6 +351,10 @@ hir_analysis_param_in_ty_of_assoc_const_binding =
*[normal] the {$param_def_kind} `{$param_name}` is defined here *[normal] the {$param_def_kind} `{$param_name}` is defined here
} }
hir_analysis_param_not_captured = `impl Trait` must mention all {$kind} parameters in scope
.label = {$kind} parameter is implicitly captured by this `impl Trait`
.note = currently, all {$kind} parameters are required to be mentioned in the precise captures list
hir_analysis_paren_sugar_attribute = the `#[rustc_paren_sugar]` attribute is a temporary means of controlling which traits can use parenthetical notation hir_analysis_paren_sugar_attribute = the `#[rustc_paren_sugar]` attribute is a temporary means of controlling which traits can use parenthetical notation
.help = add `#![feature(unboxed_closures)]` to the crate attributes to use it .help = add `#![feature(unboxed_closures)]` to the crate attributes to use it
@ -355,6 +371,9 @@ hir_analysis_pattern_type_wild_pat = "wildcard patterns are not permitted for pa
hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind} hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind}
.label = not allowed in type signatures .label = not allowed in type signatures
hir_analysis_precise_capture_self_alias = `Self` can't be captured in `use<...>` precise captures list, since it is an alias
.label = `Self` is not a generic argument, but an alias to the type of the {$what}
hir_analysis_redundant_lifetime_args = unnecessary lifetime parameter `{$victim}` hir_analysis_redundant_lifetime_args = unnecessary lifetime parameter `{$victim}`
.note = you can use the `{$candidate}` lifetime directly, in place of `{$victim}` .note = you can use the `{$candidate}` lifetime directly, in place of `{$victim}`

View file

@ -1,10 +1,10 @@
use crate::check::intrinsicck::InlineAsmCtxt; use crate::check::intrinsicck::InlineAsmCtxt;
use crate::errors::LinkageType;
use super::compare_impl_item::check_type_bounds; use super::compare_impl_item::check_type_bounds;
use super::compare_impl_item::{compare_impl_method, compare_impl_ty}; use super::compare_impl_item::{compare_impl_method, compare_impl_ty};
use super::*; use super::*;
use rustc_attr as attr; use rustc_attr as attr;
use rustc_data_structures::unord::{UnordMap, UnordSet};
use rustc_errors::{codes::*, MultiSpan}; use rustc_errors::{codes::*, MultiSpan};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::def::{CtorKind, DefKind};
@ -12,6 +12,7 @@ use rustc_hir::Node;
use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt}; use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
use rustc_infer::traits::{Obligation, TraitEngineExt as _}; use rustc_infer::traits::{Obligation, TraitEngineExt as _};
use rustc_lint_defs::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS; use rustc_lint_defs::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
use rustc_middle::middle::stability::EvalResult; use rustc_middle::middle::stability::EvalResult;
use rustc_middle::traits::ObligationCauseCode; use rustc_middle::traits::ObligationCauseCode;
use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::fold::BottomUpFolder;
@ -474,6 +475,133 @@ fn sanity_check_found_hidden_type<'tcx>(
} }
} }
/// Check that the opaque's precise captures list is valid (if present).
/// We check this for regular `impl Trait`s and also RPITITs, even though the latter
/// are technically GATs.
///
/// This function is responsible for:
/// 1. Checking that all type/const params are mention in the captures list.
/// 2. Checking that all lifetimes that are implicitly captured are mentioned.
/// 3. Asserting that all parameters mentioned in the captures list are invariant.
fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDefId) {
let hir::OpaqueTy { precise_capturing_args, .. } =
*tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty();
let Some(precise_capturing_args) = precise_capturing_args else {
// No precise capturing args; nothing to validate
return;
};
let mut expected_captures = UnordSet::default();
let mut seen_params = UnordMap::default();
let mut prev_non_lifetime_param = None;
for arg in precise_capturing_args {
let (hir_id, ident) = match *arg {
hir::PreciseCapturingArg::Param(hir::PreciseCapturingNonLifetimeArg {
hir_id,
ident,
..
}) => {
if prev_non_lifetime_param.is_none() {
prev_non_lifetime_param = Some(ident);
}
(hir_id, ident)
}
hir::PreciseCapturingArg::Lifetime(&hir::Lifetime { hir_id, ident, .. }) => {
if let Some(prev_non_lifetime_param) = prev_non_lifetime_param {
tcx.dcx().emit_err(errors::LifetimesMustBeFirst {
lifetime_span: ident.span,
name: ident.name,
other_span: prev_non_lifetime_param.span,
});
}
(hir_id, ident)
}
};
let ident = ident.normalize_to_macros_2_0();
if let Some(span) = seen_params.insert(ident, ident.span) {
tcx.dcx().emit_err(errors::DuplicatePreciseCapture {
name: ident.name,
first_span: span,
second_span: ident.span,
});
}
match tcx.named_bound_var(hir_id) {
Some(ResolvedArg::EarlyBound(def_id)) => {
expected_captures.insert(def_id);
}
_ => {
tcx.dcx().span_delayed_bug(
tcx.hir().span(hir_id),
"parameter should have been resolved",
);
}
}
}
let variances = tcx.variances_of(opaque_def_id);
let mut def_id = Some(opaque_def_id.to_def_id());
while let Some(generics) = def_id {
let generics = tcx.generics_of(generics);
def_id = generics.parent;
for param in &generics.params {
if expected_captures.contains(&param.def_id) {
assert_eq!(
variances[param.index as usize],
ty::Invariant,
"precise captured param should be invariant"
);
continue;
}
match param.kind {
ty::GenericParamDefKind::Lifetime => {
// Check if the lifetime param was captured but isn't named in the precise captures list.
if variances[param.index as usize] == ty::Invariant {
let param_span =
if let ty::ReEarlyParam(ty::EarlyParamRegion { def_id, .. })
| ty::ReLateParam(ty::LateParamRegion {
bound_region: ty::BoundRegionKind::BrNamed(def_id, _),
..
}) = *tcx
.map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local())
{
Some(tcx.def_span(def_id))
} else {
None
};
// FIXME(precise_capturing): Structured suggestion for this would be useful
tcx.dcx().emit_err(errors::LifetimeNotCaptured {
use_span: tcx.def_span(param.def_id),
param_span,
opaque_span: tcx.def_span(opaque_def_id),
});
continue;
}
}
ty::GenericParamDefKind::Type { .. } => {
// FIXME(precise_capturing): Structured suggestion for this would be useful
tcx.dcx().emit_err(errors::ParamNotCaptured {
param_span: tcx.def_span(param.def_id),
opaque_span: tcx.def_span(opaque_def_id),
kind: "type",
});
}
ty::GenericParamDefKind::Const { .. } => {
// FIXME(precise_capturing): Structured suggestion for this would be useful
tcx.dcx().emit_err(errors::ParamNotCaptured {
param_span: tcx.def_span(param.def_id),
opaque_span: tcx.def_span(opaque_def_id),
kind: "const",
});
}
}
}
}
}
fn is_enum_of_nonnullable_ptr<'tcx>( fn is_enum_of_nonnullable_ptr<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
adt_def: AdtDef<'tcx>, adt_def: AdtDef<'tcx>,
@ -499,7 +627,7 @@ fn check_static_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) {
ty::Adt(adt_def, args) => !is_enum_of_nonnullable_ptr(tcx, *adt_def, *args), ty::Adt(adt_def, args) => !is_enum_of_nonnullable_ptr(tcx, *adt_def, *args),
_ => true, _ => true,
} { } {
tcx.dcx().emit_err(LinkageType { span: tcx.def_span(def_id) }); tcx.dcx().emit_err(errors::LinkageType { span: tcx.def_span(def_id) });
} }
} }
} }
@ -566,6 +694,8 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
check_union(tcx, def_id); check_union(tcx, def_id);
} }
DefKind::OpaqueTy => { DefKind::OpaqueTy => {
check_opaque_precise_captures(tcx, def_id);
let origin = tcx.opaque_type_origin(def_id); let origin = tcx.opaque_type_origin(def_id);
if let hir::OpaqueTyOrigin::FnReturn(fn_def_id) if let hir::OpaqueTyOrigin::FnReturn(fn_def_id)
| hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = origin | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = origin

View file

@ -557,6 +557,50 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
} }
} }
fn visit_precise_capturing_arg(
&mut self,
arg: &'tcx hir::PreciseCapturingArg<'tcx>,
) -> Self::Result {
match *arg {
hir::PreciseCapturingArg::Lifetime(lt) => match lt.res {
LifetimeName::Param(def_id) => {
self.resolve_lifetime_ref(def_id, lt);
}
LifetimeName::Error => {}
LifetimeName::ImplicitObjectLifetimeDefault
| LifetimeName::Infer
| LifetimeName::Static => {
self.tcx.dcx().emit_err(errors::BadPreciseCapture {
span: lt.ident.span,
kind: "lifetime",
found: format!("`{}`", lt.ident.name),
});
}
},
hir::PreciseCapturingArg::Param(param) => match param.res {
Res::Def(DefKind::TyParam | DefKind::ConstParam, def_id)
| Res::SelfTyParam { trait_: def_id } => {
self.resolve_type_ref(def_id.expect_local(), param.hir_id);
}
Res::Err => {}
Res::SelfTyAlias { alias_to, .. } => {
self.tcx.dcx().emit_err(errors::PreciseCaptureSelfAlias {
span: param.ident.span,
self_span: self.tcx.def_span(alias_to),
what: self.tcx.def_descr(alias_to),
});
}
res => {
self.tcx.dcx().emit_err(errors::BadPreciseCapture {
span: param.ident.span,
kind: "type or const",
found: res.descr().to_string(),
});
}
},
}
}
fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
match item.kind { match item.kind {
hir::ForeignItemKind::Fn(_, _, generics) => { hir::ForeignItemKind::Fn(_, _, generics) => {

View file

@ -10,6 +10,9 @@ use rustc_span::{symbol::Ident, Span, Symbol};
mod pattern_types; mod pattern_types;
pub use pattern_types::*; pub use pattern_types::*;
mod precise_captures;
pub(crate) use precise_captures::*;
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(hir_analysis_ambiguous_assoc_item)] #[diag(hir_analysis_ambiguous_assoc_item)]
pub struct AmbiguousAssocItem<'a> { pub struct AmbiguousAssocItem<'a> {

View file

@ -0,0 +1,63 @@
use rustc_macros::Diagnostic;
use rustc_span::{Span, Symbol};
#[derive(Diagnostic)]
#[diag(hir_analysis_param_not_captured)]
#[note]
pub struct ParamNotCaptured {
#[primary_span]
pub param_span: Span,
#[label]
pub opaque_span: Span,
pub kind: &'static str,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_lifetime_not_captured)]
pub struct LifetimeNotCaptured {
#[primary_span]
pub use_span: Span,
#[label(hir_analysis_param_label)]
pub param_span: Option<Span>,
#[label]
pub opaque_span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_bad_precise_capture)]
pub struct BadPreciseCapture {
#[primary_span]
pub span: Span,
pub kind: &'static str,
pub found: String,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_precise_capture_self_alias)]
pub struct PreciseCaptureSelfAlias {
#[primary_span]
pub span: Span,
#[label]
pub self_span: Span,
pub what: &'static str,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_duplicate_precise_capture)]
pub struct DuplicatePreciseCapture {
#[primary_span]
pub first_span: Span,
pub name: Symbol,
#[label]
pub second_span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_lifetime_must_be_first)]
pub struct LifetimesMustBeFirst {
#[primary_span]
pub lifetime_span: Span,
pub name: Symbol,
#[label]
pub other_span: Span,
}

View file

@ -95,6 +95,7 @@ impl<'a> State<'a> {
Node::PatField(a) => self.print_patfield(a), Node::PatField(a) => self.print_patfield(a),
Node::Arm(a) => self.print_arm(a), Node::Arm(a) => self.print_arm(a),
Node::Infer(_) => self.word("_"), Node::Infer(_) => self.word("_"),
Node::PreciseCapturingNonLifetimeArg(param) => self.print_ident(param.ident),
Node::Block(a) => { Node::Block(a) => {
// Containing cbox, will be closed by print-block at `}`. // Containing cbox, will be closed by print-block at `}`.
self.cbox(INDENT_UNIT); self.cbox(INDENT_UNIT);

View file

@ -283,6 +283,7 @@ pub fn suggest_new_region_bound(
continue; continue;
} }
match fn_return.kind { match fn_return.kind {
// FIXME(precise_captures): Suggest adding to `use<...>` list instead.
TyKind::OpaqueDef(item_id, _, _) => { TyKind::OpaqueDef(item_id, _, _) => {
let item = tcx.hir().item(item_id); let item = tcx.hir().item(item_id);
let ItemKind::OpaqueTy(opaque) = &item.kind else { let ItemKind::OpaqueTy(opaque) = &item.kind else {

View file

@ -1235,7 +1235,7 @@ impl EarlyLintPass for UnusedParens {
ast::TyKind::TraitObject(..) => {} ast::TyKind::TraitObject(..) => {}
ast::TyKind::BareFn(b) ast::TyKind::BareFn(b)
if self.with_self_ty_parens && b.generic_params.len() > 0 => {} if self.with_self_ty_parens && b.generic_params.len() > 0 => {}
ast::TyKind::ImplTrait(_, bounds) if bounds.len() > 1 => {} ast::TyKind::ImplTrait(_, bounds, _) if bounds.len() > 1 => {}
_ => { _ => {
let spans = if !ty.span.from_expansion() { let spans = if !ty.span.from_expansion() {
r.span r.span

View file

@ -910,6 +910,7 @@ impl<'hir> Map<'hir> {
Node::Crate(item) => item.spans.inner_span, Node::Crate(item) => item.spans.inner_span,
Node::WhereBoundPredicate(pred) => pred.span, Node::WhereBoundPredicate(pred) => pred.span,
Node::ArrayLenInfer(inf) => inf.span, Node::ArrayLenInfer(inf) => inf.span,
Node::PreciseCapturingNonLifetimeArg(param) => param.ident.span,
Node::Synthetic => unreachable!(), Node::Synthetic => unreachable!(),
Node::Err(span) => *span, Node::Err(span) => *span,
} }
@ -1183,6 +1184,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
Node::ArrayLenInfer(_) => node_str("array len infer"), Node::ArrayLenInfer(_) => node_str("array len infer"),
Node::Synthetic => unreachable!(), Node::Synthetic => unreachable!(),
Node::Err(_) => node_str("error"), Node::Err(_) => node_str("error"),
Node::PreciseCapturingNonLifetimeArg(_param) => node_str("parameter"),
} }
} }

View file

@ -62,7 +62,7 @@ impl<'a> Parser<'a> {
let snapshot = self.create_snapshot_for_diagnostic(); let snapshot = self.create_snapshot_for_diagnostic();
match self.parse_ty() { match self.parse_ty() {
Ok(p) => { Ok(p) => {
if let TyKind::ImplTrait(_, bounds) = &p.kind { if let TyKind::ImplTrait(_, bounds, None) = &p.kind {
let span = impl_span.to(self.token.span.shrink_to_lo()); let span = impl_span.to(self.token.span.shrink_to_lo());
let mut err = self.dcx().struct_span_err( let mut err = self.dcx().struct_span_err(
span, span,

View file

@ -625,7 +625,7 @@ impl<'a> Parser<'a> {
// This notably includes paths passed through `ty` macro fragments (#46438). // This notably includes paths passed through `ty` macro fragments (#46438).
TyKind::Path(None, path) => path, TyKind::Path(None, path) => path,
other => { other => {
if let TyKind::ImplTrait(_, bounds) = other if let TyKind::ImplTrait(_, bounds, None) = other
&& let [bound] = bounds.as_slice() && let [bound] = bounds.as_slice()
{ {
// Suggest removing extra `impl` keyword: // Suggest removing extra `impl` keyword:

View file

@ -1,4 +1,4 @@
use super::{Parser, PathStyle, TokenType, Trailing}; use super::{Parser, PathStyle, SeqSep, TokenType, Trailing};
use crate::errors::{ use crate::errors::{
self, DynAfterMut, ExpectedFnPathFoundFnKeyword, ExpectedMutOrConstInRawPointerType, self, DynAfterMut, ExpectedFnPathFoundFnKeyword, ExpectedMutOrConstInRawPointerType,
@ -14,7 +14,7 @@ use rustc_ast::util::case::Case;
use rustc_ast::{ use rustc_ast::{
self as ast, BareFnTy, BoundAsyncness, BoundConstness, BoundPolarity, FnRetTy, GenericBound, self as ast, BareFnTy, BoundAsyncness, BoundConstness, BoundPolarity, FnRetTy, GenericBound,
GenericBounds, GenericParam, Generics, Lifetime, MacCall, MutTy, Mutability, PolyTraitRef, GenericBounds, GenericParam, Generics, Lifetime, MacCall, MutTy, Mutability, PolyTraitRef,
TraitBoundModifiers, TraitObjectSyntax, Ty, TyKind, DUMMY_NODE_ID, PreciseCapturingArg, TraitBoundModifiers, TraitObjectSyntax, Ty, TyKind, DUMMY_NODE_ID,
}; };
use rustc_errors::{Applicability, PResult}; use rustc_errors::{Applicability, PResult};
use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::symbol::{kw, sym, Ident};
@ -316,7 +316,7 @@ impl<'a> Parser<'a> {
TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn) TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn)
} }
(TyKind::TraitObject(bounds, _), kw::Impl) => { (TyKind::TraitObject(bounds, _), kw::Impl) => {
TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds) TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds, None)
} }
_ => return Err(err), _ => return Err(err),
}; };
@ -655,7 +655,6 @@ impl<'a> Parser<'a> {
/// Parses an `impl B0 + ... + Bn` type. /// Parses an `impl B0 + ... + Bn` type.
fn parse_impl_ty(&mut self, impl_dyn_multi: &mut bool) -> PResult<'a, TyKind> { fn parse_impl_ty(&mut self, impl_dyn_multi: &mut bool) -> PResult<'a, TyKind> {
// Always parse bounds greedily for better error recovery.
if self.token.is_lifetime() { if self.token.is_lifetime() {
self.look_ahead(1, |t| { self.look_ahead(1, |t| {
if let token::Ident(sym, _) = t.kind { if let token::Ident(sym, _) = t.kind {
@ -669,9 +668,53 @@ impl<'a> Parser<'a> {
} }
}) })
} }
// parse precise captures, if any. This is `use<'lt, 'lt, P, P>`; a list of
// lifetimes and ident params (including SelfUpper). These are validated later
// for order, duplication, and whether they actually reference params.
let precise_capturing = if self.eat_keyword(kw::Use) {
let use_span = self.prev_token.span;
self.psess.gated_spans.gate(sym::precise_capturing, use_span);
let args = self.parse_precise_capturing_args()?;
Some(P((args, use_span)))
} else {
None
};
// Always parse bounds greedily for better error recovery.
let bounds = self.parse_generic_bounds()?; let bounds = self.parse_generic_bounds()?;
*impl_dyn_multi = bounds.len() > 1 || self.prev_token.kind == TokenKind::BinOp(token::Plus); *impl_dyn_multi = bounds.len() > 1 || self.prev_token.kind == TokenKind::BinOp(token::Plus);
Ok(TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds))
Ok(TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds, precise_capturing))
}
fn parse_precise_capturing_args(&mut self) -> PResult<'a, ThinVec<PreciseCapturingArg>> {
Ok(self
.parse_unspanned_seq(
&TokenKind::Lt,
&TokenKind::Gt,
SeqSep::trailing_allowed(token::Comma),
|self_| {
if self_.check_keyword(kw::SelfUpper) {
self_.bump();
Ok(PreciseCapturingArg::Arg(
ast::Path::from_ident(self_.prev_token.ident().unwrap().0),
DUMMY_NODE_ID,
))
} else if self_.check_ident() {
Ok(PreciseCapturingArg::Arg(
ast::Path::from_ident(self_.parse_ident()?),
DUMMY_NODE_ID,
))
} else if self_.check_lifetime() {
Ok(PreciseCapturingArg::Lifetime(self_.expect_lifetime()))
} else {
self_.unexpected_any()
}
},
)?
.0)
} }
/// Is a `dyn B0 + ... + Bn` type allowed here? /// Is a `dyn B0 + ... + Bn` type allowed here?
@ -957,7 +1000,7 @@ impl<'a> Parser<'a> {
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
) )
} }
TyKind::ImplTrait(_, bounds) TyKind::ImplTrait(_, bounds, None)
if let [GenericBound::Trait(tr, ..), ..] = bounds.as_slice() => if let [GenericBound::Trait(tr, ..), ..] = bounds.as_slice() =>
{ {
( (

View file

@ -793,7 +793,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
self.r.record_partial_res(ty.id, PartialRes::new(res)); self.r.record_partial_res(ty.id, PartialRes::new(res));
visit::walk_ty(self, ty) visit::walk_ty(self, ty)
} }
TyKind::ImplTrait(node_id, _) => { TyKind::ImplTrait(node_id, _, _) => {
let candidates = self.lifetime_elision_candidates.take(); let candidates = self.lifetime_elision_candidates.take();
visit::walk_ty(self, ty); visit::walk_ty(self, ty);
self.record_lifetime_params_for_impl_trait(*node_id); self.record_lifetime_params_for_impl_trait(*node_id);
@ -1047,10 +1047,39 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
}); });
self.diag_metadata.current_function = previous_value; self.diag_metadata.current_function = previous_value;
} }
fn visit_lifetime(&mut self, lifetime: &'ast Lifetime, use_ctxt: visit::LifetimeCtxt) { fn visit_lifetime(&mut self, lifetime: &'ast Lifetime, use_ctxt: visit::LifetimeCtxt) {
self.resolve_lifetime(lifetime, use_ctxt) self.resolve_lifetime(lifetime, use_ctxt)
} }
fn visit_precise_capturing_arg(&mut self, arg: &'ast PreciseCapturingArg) {
match arg {
// Lower the lifetime regularly; we'll resolve the lifetime and check
// it's a parameter later on in HIR lowering.
PreciseCapturingArg::Lifetime(_) => {}
PreciseCapturingArg::Arg(path, id) => {
// we want `impl use<C>` to try to resolve `C` as both a type parameter or
// a const parameter. Since the resolver specifically doesn't allow having
// two generic params with the same name, even if they're a different namespace,
// it doesn't really matter which we try resolving first, but just like
// `Ty::Param` we just fall back to the value namespace only if it's missing
// from the type namespace.
let mut check_ns = |ns| {
self.maybe_resolve_ident_in_lexical_scope(path.segments[0].ident, ns).is_some()
};
// Like `Ty::Param`, we try resolving this as both a const and a type.
if !check_ns(TypeNS) && check_ns(ValueNS) {
self.smart_resolve_path(*id, &None, path, PathSource::Expr(None));
} else {
self.smart_resolve_path(*id, &None, path, PathSource::Type);
}
}
}
visit::walk_precise_capturing_arg(self, arg)
}
fn visit_generics(&mut self, generics: &'ast Generics) { fn visit_generics(&mut self, generics: &'ast Generics) {
self.visit_generic_params(&generics.params, self.diag_metadata.current_self_item.is_some()); self.visit_generic_params(&generics.params, self.diag_metadata.current_self_item.is_some());
for p in &generics.where_clause.predicates { for p in &generics.where_clause.predicates {

View file

@ -3121,7 +3121,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
.inputs .inputs
.iter() .iter()
.filter_map(|param| match &param.ty.kind { .filter_map(|param| match &param.ty.kind {
TyKind::ImplTrait(_, bounds) => Some(bounds), TyKind::ImplTrait(_, bounds, _) => Some(bounds),
_ => None, _ => None,
}) })
.flat_map(|bounds| bounds.into_iter()) .flat_map(|bounds| bounds.into_iter())

View file

@ -1375,6 +1375,7 @@ symbols! {
powif32, powif32,
powif64, powif64,
pre_dash_lto: "pre-lto", pre_dash_lto: "pre-lto",
precise_capturing,
precise_pointer_size_matching, precise_pointer_size_matching,
pref_align_of, pref_align_of,
prefetch_read_data, prefetch_read_data,

View file

@ -709,7 +709,8 @@ pub fn eq_ty(l: &Ty, r: &Ty) -> bool {
(Tup(l), Tup(r)) => over(l, r, |l, r| eq_ty(l, r)), (Tup(l), Tup(r)) => over(l, r, |l, r| eq_ty(l, r)),
(Path(lq, lp), Path(rq, rp)) => both(lq, rq, eq_qself) && eq_path(lp, rp), (Path(lq, lp), Path(rq, rp)) => both(lq, rq, eq_qself) && eq_path(lp, rp),
(TraitObject(lg, ls), TraitObject(rg, rs)) => ls == rs && over(lg, rg, eq_generic_bound), (TraitObject(lg, ls), TraitObject(rg, rs)) => ls == rs && over(lg, rg, eq_generic_bound),
(ImplTrait(_, lg), ImplTrait(_, rg)) => over(lg, rg, eq_generic_bound), (ImplTrait(_, lg, lc), ImplTrait(_, rg, rc)) =>
over(lg, rg, eq_generic_bound) && both(lc, rc, |lc, rc| over(lc.0.as_slice(), rc.0.as_slice(), eq_precise_capture)),
(Typeof(l), Typeof(r)) => eq_expr(&l.value, &r.value), (Typeof(l), Typeof(r)) => eq_expr(&l.value, &r.value),
(MacCall(l), MacCall(r)) => eq_mac_call(l, r), (MacCall(l), MacCall(r)) => eq_mac_call(l, r),
_ => false, _ => false,
@ -770,6 +771,14 @@ pub fn eq_generic_bound(l: &GenericBound, r: &GenericBound) -> bool {
} }
} }
pub fn eq_precise_capture(l: &PreciseCapturingArg, r: &PreciseCapturingArg) -> bool {
match (l, r) {
(PreciseCapturingArg::Lifetime(l), PreciseCapturingArg::Lifetime(r)) => l.ident == r.ident,
(PreciseCapturingArg::Arg(l, _), PreciseCapturingArg::Arg(r, _)) => l.segments[0].ident == r.segments[0].ident,
_ => false,
}
}
fn eq_term(l: &Term, r: &Term) -> bool { fn eq_term(l: &Term, r: &Term) -> bool {
match (l, r) { match (l, r) {
(Term::Ty(l), Term::Ty(r)) => eq_ty(l, r), (Term::Ty(l), Term::Ty(r)) => eq_ty(l, r),

View file

@ -843,7 +843,11 @@ impl Rewrite for ast::Ty {
rewrite_macro(mac, None, context, shape, MacroPosition::Expression) rewrite_macro(mac, None, context, shape, MacroPosition::Expression)
} }
ast::TyKind::ImplicitSelf => Some(String::from("")), ast::TyKind::ImplicitSelf => Some(String::from("")),
ast::TyKind::ImplTrait(_, ref it) => { ast::TyKind::ImplTrait(_, ref it, ref captures) => {
// FIXME(precise_capturing): Implement formatting.
if captures.is_some() {
return None;
}
// Empty trait is not a parser error. // Empty trait is not a parser error.
if it.is_empty() { if it.is_empty() {
return Some("impl".to_owned()); return Some("impl".to_owned());
@ -1106,7 +1110,8 @@ fn join_bounds_inner(
pub(crate) fn opaque_ty(ty: &Option<ptr::P<ast::Ty>>) -> Option<&ast::GenericBounds> { pub(crate) fn opaque_ty(ty: &Option<ptr::P<ast::Ty>>) -> Option<&ast::GenericBounds> {
ty.as_ref().and_then(|t| match &t.kind { ty.as_ref().and_then(|t| match &t.kind {
ast::TyKind::ImplTrait(_, bounds) => Some(bounds), // FIXME(precise_capturing): Implement support here
ast::TyKind::ImplTrait(_, bounds, _) => Some(bounds),
_ => None, _ => None,
}) })
} }

View file

@ -0,0 +1,4 @@
fn hello() -> impl use<> Sized {}
//~^ ERROR precise captures on `impl Trait` are experimental
fn main() {}

View file

@ -0,0 +1,13 @@
error[E0658]: precise captures on `impl Trait` are experimental
--> $DIR/feature-gate-precise-capturing.rs:1:20
|
LL | fn hello() -> impl use<> Sized {}
| ^^^
|
= note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
= help: add `#![feature(precise_capturing)]` 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
For more information about this error, try `rustc --explain E0658`.

View file

@ -0,0 +1,7 @@
#![feature(precise_capturing)]
//~^ WARN the feature `precise_capturing` is incomplete
fn hello(_: impl use<> Sized) {}
//~^ ERROR `use<...>` precise capturing syntax not allowed on argument-position `impl Trait`
fn main() {}

View file

@ -0,0 +1,17 @@
warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/apit.rs:1:12
|
LL | #![feature(precise_capturing)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
= note: `#[warn(incomplete_features)]` on by default
error: `use<...>` precise capturing syntax not allowed on argument-position `impl Trait`
--> $DIR/apit.rs:4:18
|
LL | fn hello(_: impl use<> Sized) {}
| ^^^
error: aborting due to 1 previous error; 1 warning emitted

View file

@ -0,0 +1,14 @@
#![feature(precise_capturing)]
//~^ WARN the feature `precise_capturing` is incomplete
fn no_elided_lt() -> impl use<'_> Sized {}
//~^ ERROR missing lifetime specifier
//~| ERROR expected lifetime parameter in `use<...>` precise captures list, found `'_`
fn static_lt() -> impl use<'static> Sized {}
//~^ ERROR expected lifetime parameter in `use<...>` precise captures list, found `'static`
fn missing_lt() -> impl use<'missing> Sized {}
//~^ ERROR use of undeclared lifetime name `'missing`
fn main() {}

View file

@ -0,0 +1,45 @@
error[E0106]: missing lifetime specifier
--> $DIR/bad-lifetimes.rs:4:31
|
LL | fn no_elided_lt() -> impl use<'_> Sized {}
| ^^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`, or if you will only have owned values
|
LL | fn no_elided_lt() -> impl use<'static> Sized {}
| ~~~~~~~
error[E0261]: use of undeclared lifetime name `'missing`
--> $DIR/bad-lifetimes.rs:11:29
|
LL | fn missing_lt() -> impl use<'missing> Sized {}
| - ^^^^^^^^ undeclared lifetime
| |
| help: consider introducing lifetime `'missing` here: `<'missing>`
warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/bad-lifetimes.rs:1:12
|
LL | #![feature(precise_capturing)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
= note: `#[warn(incomplete_features)]` on by default
error: expected lifetime parameter in `use<...>` precise captures list, found `'_`
--> $DIR/bad-lifetimes.rs:4:31
|
LL | fn no_elided_lt() -> impl use<'_> Sized {}
| ^^
error: expected lifetime parameter in `use<...>` precise captures list, found `'static`
--> $DIR/bad-lifetimes.rs:8:28
|
LL | fn static_lt() -> impl use<'static> Sized {}
| ^^^^^^^
error: aborting due to 4 previous errors; 1 warning emitted
Some errors have detailed explanations: E0106, E0261.
For more information about an error, try `rustc --explain E0106`.

View file

@ -0,0 +1,19 @@
#![feature(precise_capturing)]
//~^ WARN the feature `precise_capturing` is incomplete
fn missing() -> impl use<T> Sized {}
//~^ ERROR cannot find type `T` in this scope
fn missing_self() -> impl use<Self> Sized {}
//~^ ERROR cannot find type `Self` in this scope
struct MyType;
impl MyType {
fn self_is_not_param() -> impl use<Self> Sized {}
//~^ ERROR `Self` can't be captured in `use<...>` precise captures list, since it is an alias
}
fn hello() -> impl use<hello> Sized {}
//~^ ERROR expected type or const parameter in `use<...>` precise captures list, found function
fn main() {}

View file

@ -0,0 +1,46 @@
error[E0412]: cannot find type `T` in this scope
--> $DIR/bad-params.rs:4:26
|
LL | fn missing() -> impl use<T> Sized {}
| ^ not found in this scope
|
help: you might be missing a type parameter
|
LL | fn missing<T>() -> impl use<T> Sized {}
| +++
error[E0411]: cannot find type `Self` in this scope
--> $DIR/bad-params.rs:7:31
|
LL | fn missing_self() -> impl use<Self> Sized {}
| ------------ ^^^^ `Self` is only available in impls, traits, and type definitions
| |
| `Self` not allowed in a function
warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/bad-params.rs:1:12
|
LL | #![feature(precise_capturing)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
= note: `#[warn(incomplete_features)]` on by default
error: `Self` can't be captured in `use<...>` precise captures list, since it is an alias
--> $DIR/bad-params.rs:12:40
|
LL | impl MyType {
| ----------- `Self` is not a generic argument, but an alias to the type of the implementation
LL | fn self_is_not_param() -> impl use<Self> Sized {}
| ^^^^
error: expected type or const parameter in `use<...>` precise captures list, found function
--> $DIR/bad-params.rs:16:24
|
LL | fn hello() -> impl use<hello> Sized {}
| ^^^^^
error: aborting due to 4 previous errors; 1 warning emitted
Some errors have detailed explanations: E0411, E0412.
For more information about an error, try `rustc --explain E0411`.

View file

@ -0,0 +1,8 @@
//@ check-pass
#![feature(precise_capturing)]
//~^ WARN the feature `precise_capturing` is incomplete
fn elided(x: &()) -> impl use<'_> Sized { x }
fn main() {}

View file

@ -0,0 +1,11 @@
warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/elided.rs:3:12
|
LL | #![feature(precise_capturing)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
= note: `#[warn(incomplete_features)]` on by default
warning: 1 warning emitted

View file

@ -0,0 +1,7 @@
#![feature(precise_capturing)]
//~^ WARN the feature `precise_capturing` is incomplete
fn constant<const C: usize>() -> impl use<> Sized {}
//~^ ERROR `impl Trait` must mention all const parameters in scope
fn main() {}

View file

@ -0,0 +1,19 @@
warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/forgot-to-capture-const.rs:1:12
|
LL | #![feature(precise_capturing)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
= note: `#[warn(incomplete_features)]` on by default
error: `impl Trait` must mention all const parameters in scope
--> $DIR/forgot-to-capture-const.rs:4:13
|
LL | fn constant<const C: usize>() -> impl use<> Sized {}
| ^^^^^^^^^^^^^^ ---------------- const parameter is implicitly captured by this `impl Trait`
|
= note: currently, all const parameters are required to be mentioned in the precise captures list
error: aborting due to 1 previous error; 1 warning emitted

View file

@ -0,0 +1,10 @@
#![feature(precise_capturing)]
//~^ WARN the feature `precise_capturing` is incomplete
fn lifetime_in_bounds<'a>(x: &'a ()) -> impl use<> Into<&'a ()> { x }
//~^ ERROR `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list
fn lifetime_in_hidden<'a>(x: &'a ()) -> impl use<> Sized { x }
//~^ ERROR hidden type for `impl Sized` captures lifetime that does not appear in bounds
fn main() {}

View file

@ -0,0 +1,35 @@
warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/forgot-to-capture-lifetime.rs:1:12
|
LL | #![feature(precise_capturing)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
= note: `#[warn(incomplete_features)]` on by default
error: `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list
--> $DIR/forgot-to-capture-lifetime.rs:4:58
|
LL | fn lifetime_in_bounds<'a>(x: &'a ()) -> impl use<> Into<&'a ()> { x }
| -- -----------------^^----
| | |
| | lifetime captured due to being mentioned in the bounds of the `impl Trait`
| this lifetime parameter is captured
error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds
--> $DIR/forgot-to-capture-lifetime.rs:7:60
|
LL | fn lifetime_in_hidden<'a>(x: &'a ()) -> impl use<> Sized { x }
| -- ---------------- ^
| | |
| | opaque type defined here
| hidden type `&'a ()` captures the lifetime `'a` as defined here
|
help: to declare that `impl Sized` captures `'a`, you can add an explicit `'a` lifetime bound
|
LL | fn lifetime_in_hidden<'a>(x: &'a ()) -> impl use<> Sized + 'a { x }
| ++++
error: aborting due to 2 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0700`.

View file

@ -0,0 +1,12 @@
#![feature(precise_capturing)]
//~^ WARN the feature `precise_capturing` is incomplete
fn type_param<T>() -> impl use<> Sized {}
//~^ ERROR `impl Trait` must mention all type parameters in scope
trait Foo {
//~^ ERROR `impl Trait` must mention all type parameters in scope
fn bar() -> impl use<> Sized;
}
fn main() {}

View file

@ -0,0 +1,30 @@
warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/forgot-to-capture-type.rs:1:12
|
LL | #![feature(precise_capturing)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
= note: `#[warn(incomplete_features)]` on by default
error: `impl Trait` must mention all type parameters in scope
--> $DIR/forgot-to-capture-type.rs:4:15
|
LL | fn type_param<T>() -> impl use<> Sized {}
| ^ ---------------- type parameter is implicitly captured by this `impl Trait`
|
= note: currently, all type parameters are required to be mentioned in the precise captures list
error: `impl Trait` must mention all type parameters in scope
--> $DIR/forgot-to-capture-type.rs:7:1
|
LL | trait Foo {
| ^^^^^^^^^
LL |
LL | fn bar() -> impl use<> Sized;
| ---------------- type parameter is implicitly captured by this `impl Trait`
|
= note: currently, all type parameters are required to be mentioned in the precise captures list
error: aborting due to 2 previous errors; 1 warning emitted

View file

@ -0,0 +1,18 @@
//@ check-pass
// Show how precise captures allow us to skip capturing a higher-ranked lifetime
#![feature(lifetime_capture_rules_2024, precise_capturing)]
//~^ WARN the feature `precise_capturing` is incomplete
trait Trait<'a> {
type Item;
}
impl Trait<'_> for () {
type Item = Vec<()>;
}
fn hello() -> impl for<'a> Trait<'a, Item = impl use<> IntoIterator> {}
fn main() {}

View file

@ -0,0 +1,11 @@
warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/higher-ranked.rs:5:41
|
LL | #![feature(lifetime_capture_rules_2024, precise_capturing)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
= note: `#[warn(incomplete_features)]` on by default
warning: 1 warning emitted

View file

@ -0,0 +1,16 @@
#![feature(precise_capturing)]
//~^ WARN the feature `precise_capturing` is incomplete
fn lt<'a>() -> impl use<'a, 'a> Sized {}
//~^ ERROR cannot capture parameter `'a` twice
fn ty<T>() -> impl use<T, T> Sized {}
//~^ ERROR cannot capture parameter `T` twice
fn ct<const N: usize>() -> impl use<N, N> Sized {}
//~^ ERROR cannot capture parameter `N` twice
fn ordering<'a, T>() -> impl use<T, 'a> Sized {}
//~^ ERROR lifetime parameter `'a` must be listed before non-lifetime parameters
fn main() {}

View file

@ -0,0 +1,37 @@
warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/ordering.rs:1:12
|
LL | #![feature(precise_capturing)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
= note: `#[warn(incomplete_features)]` on by default
error: cannot capture parameter `'a` twice
--> $DIR/ordering.rs:4:25
|
LL | fn lt<'a>() -> impl use<'a, 'a> Sized {}
| ^^ -- parameter captured again here
error: cannot capture parameter `T` twice
--> $DIR/ordering.rs:7:24
|
LL | fn ty<T>() -> impl use<T, T> Sized {}
| ^ - parameter captured again here
error: cannot capture parameter `N` twice
--> $DIR/ordering.rs:10:37
|
LL | fn ct<const N: usize>() -> impl use<N, N> Sized {}
| ^ - parameter captured again here
error: lifetime parameter `'a` must be listed before non-lifetime parameters
--> $DIR/ordering.rs:13:37
|
LL | fn ordering<'a, T>() -> impl use<T, 'a> Sized {}
| - ^^
| |
| move the lifetime before this parameter
error: aborting due to 4 previous errors; 1 warning emitted

View file

@ -0,0 +1,16 @@
//@ check-pass
// Show that precise captures allow us to skip a lifetime param for outlives
#![feature(lifetime_capture_rules_2024, precise_capturing)]
//~^ WARN the feature `precise_capturing` is incomplete
fn hello<'a: 'a, 'b: 'b>() -> impl use<'a> Sized { }
fn outlives<'a, T: 'a>(_: T) {}
fn test<'a, 'b>() {
outlives::<'a, _>(hello::<'a, 'b>());
}
fn main() {}

View file

@ -0,0 +1,11 @@
warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/outlives.rs:5:41
|
LL | #![feature(lifetime_capture_rules_2024, precise_capturing)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
= note: `#[warn(incomplete_features)]` on by default
warning: 1 warning emitted

View file

@ -0,0 +1,10 @@
//@ check-pass
#![feature(precise_capturing)]
//~^ WARN the feature `precise_capturing` is incomplete
trait Foo {
fn bar<'a>() -> impl use<Self> Sized;
}
fn main() {}

View file

@ -0,0 +1,11 @@
warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/self-capture.rs:3:12
|
LL | #![feature(precise_capturing)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
= note: `#[warn(incomplete_features)]` on by default
warning: 1 warning emitted