diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 9fe66df179a98..be78180df9d32 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2568,6 +2568,11 @@ pub enum PreciseCapturingArg<'hir> { 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, diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 5a67bf4b9c9fb..a280ee9d798b1 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -39,9 +39,6 @@ hir_analysis_auto_deref_reached_recursion_limit = reached the recursion limit wh hir_analysis_bad_precise_capture = expected {$kind} parameter in `use<...>` precise captures list, found {$found} -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_cannot_capture_late_bound_const = cannot capture late-bound const parameter in {$what} .label = parameter defined here @@ -371,6 +368,9 @@ hir_analysis_pass_to_variadic_function = can't pass `{$ty}` to variadic function 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 +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_requires_note = the `{$trait_name}` impl for `{$ty}` requires that `{$error_predicate}` hir_analysis_return_type_notation_equality_bound = diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index df5933c5049a7..216dfdb158328 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -479,6 +479,14 @@ 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(); diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index fe70b631cdb82..0bbabefaf9540 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -283,6 +283,7 @@ pub fn suggest_new_region_bound( continue; } match fn_return.kind { + // FIXME(precise_captures): Suggest adding to `use<...>` list instead. TyKind::OpaqueDef(item_id, _, _) => { let item = tcx.hir().item(item_id); let ItemKind::OpaqueTy(opaque) = &item.kind else { diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index f78a039394b84..a6195fa769383 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -669,7 +669,9 @@ impl<'a> Parser<'a> { }) } - // parse precise captures, if any. + // 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); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index e02275d887748..0d177a6e2b06e 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1062,6 +1062,12 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, PreciseCapturingArg::Lifetime(_) => {} PreciseCapturingArg::Arg(path, id) => { + // we want `impl use` 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() }; diff --git a/tests/ui/impl-trait/precise-capturing/apit.rs b/tests/ui/impl-trait/precise-capturing/apit.rs new file mode 100644 index 0000000000000..efcac9ebb0b84 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/apit.rs @@ -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() {} diff --git a/tests/ui/impl-trait/precise-capturing/apit.stderr b/tests/ui/impl-trait/precise-capturing/apit.stderr new file mode 100644 index 0000000000000..36bf80d9e2f96 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/apit.stderr @@ -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 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 + diff --git a/tests/ui/impl-trait/precise-capturing/bad-params.rs b/tests/ui/impl-trait/precise-capturing/bad-params.rs index 195bd1b67aebd..7970d49bf7c07 100644 --- a/tests/ui/impl-trait/precise-capturing/bad-params.rs +++ b/tests/ui/impl-trait/precise-capturing/bad-params.rs @@ -13,4 +13,7 @@ impl MyType { //~^ ERROR `Self` can't be captured in `use<...>` precise captures list, since it is an alias } +fn hello() -> impl use Sized {} +//~^ ERROR expected type or const parameter in `use<...>` precise captures list, found function + fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/bad-params.stderr b/tests/ui/impl-trait/precise-capturing/bad-params.stderr index 09694a800c41c..27bf05302f9b1 100644 --- a/tests/ui/impl-trait/precise-capturing/bad-params.stderr +++ b/tests/ui/impl-trait/precise-capturing/bad-params.stderr @@ -34,7 +34,13 @@ LL | impl MyType { LL | fn self_is_not_param() -> impl use Sized {} | ^^^^ -error: aborting due to 3 previous errors; 1 warning emitted +error: expected type or const parameter in `use<...>` precise captures list, found function + --> $DIR/bad-params.rs:16:24 + | +LL | fn hello() -> impl use 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`. diff --git a/tests/ui/impl-trait/precise-capturing/elided.rs b/tests/ui/impl-trait/precise-capturing/elided.rs new file mode 100644 index 0000000000000..de80e8a5d581b --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/elided.rs @@ -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() {} diff --git a/tests/ui/impl-trait/precise-capturing/elided.stderr b/tests/ui/impl-trait/precise-capturing/elided.stderr new file mode 100644 index 0000000000000..38da0828de972 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/elided.stderr @@ -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 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted +