From 2e03130e112d86c693076ddba3f957542632d7e1 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 5 Jun 2024 16:43:25 -0400 Subject: [PATCH] Detect duplicates --- compiler/rustc_ast_lowering/src/lib.rs | 11 ++++++---- compiler/rustc_ast_passes/messages.ftl | 7 +++++-- .../rustc_ast_passes/src/ast_validation.rs | 20 +++++++++++++++++-- compiler/rustc_ast_passes/src/errors.rs | 9 +++++++++ .../duplicated-use.pre_expansion.stderr | 11 ++++++++++ .../duplicated-use.real.stderr | 17 ++++++++++++++++ .../precise-capturing/duplicated-use.rs | 11 ++++++++++ 7 files changed, 78 insertions(+), 8 deletions(-) create mode 100644 tests/ui/impl-trait/precise-capturing/duplicated-use.pre_expansion.stderr create mode 100644 tests/ui/impl-trait/precise-capturing/duplicated-use.real.stderr create mode 100644 tests/ui/impl-trait/precise-capturing/duplicated-use.rs diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 1fc6a9699157..b998912bf6d9 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1531,10 +1531,13 @@ fn lower_opaque_impl_trait( let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None); let captured_lifetimes_to_duplicate = if let Some(args) = - bounds.iter().find_map(|bound| match bound { - ast::GenericBound::Use(a, _) => Some(a), - _ => None, - }) { + // We only look for one `use<...>` syntax since we syntactially reject more than one. + bounds.iter().find_map( + |bound| match bound { + ast::GenericBound::Use(a, _) => Some(a), + _ => None, + }, + ) { // We'll actually validate these later on; all we need is the list of // lifetimes to duplicate during this portion of lowering. args.iter() diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 518ac9256a1e..2626631d8004 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -14,8 +14,6 @@ ast_passes_assoc_type_without_body = associated type in `impl` without body .suggestion = provide a definition for the type -ast_passes_precise_capturing_not_allowed_here = `use<...>` precise capturing syntax not allowed in {$loc} - ast_passes_at_least_one_trait = at least one trait must be specified ast_passes_auto_generic = auto traits cannot have generic parameters @@ -217,6 +215,11 @@ ast_passes_pattern_in_fn_pointer = patterns aren't allowed in function pointer t ast_passes_pattern_in_foreign = patterns aren't allowed in foreign function declarations .label = pattern not allowed in foreign function +ast_passes_precise_capturing_duplicated = duplicate `use<...>` precise capturing syntax + .label = second `use<...>` here + +ast_passes_precise_capturing_not_allowed_here = `use<...>` precise capturing syntax not allowed in {$loc} + ast_passes_show_span = {$msg} ast_passes_stability_outside_std = stability attributes may not be used outside of the standard library diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index de96bdd557f4..93abe36a2dbf 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -193,8 +193,24 @@ fn with_impl_trait(&mut self, outer: Option, f: impl FnOnce(&mut Self)) { // Mirrors `visit::walk_ty`, but tracks relevant state. fn walk_ty(&mut self, t: &'a Ty) { match &t.kind { - TyKind::ImplTrait(..) => { - self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t)) + TyKind::ImplTrait(_, bounds) => { + self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t)); + + // FIXME(precise_capturing): If we were to allow `use` in other positions + // (e.g. GATs), then we must validate those as well. However, we don't have + // a good way of doing this with the current `Visitor` structure. + let mut use_bounds = bounds + .iter() + .filter_map(|bound| match bound { + GenericBound::Use(_, span) => Some(span), + _ => None, + }) + .copied(); + if let Some(bound1) = use_bounds.next() + && let Some(bound2) = use_bounds.next() + { + self.dcx().emit_err(errors::DuplicatePreciseCapturing { bound1, bound2 }); + } } TyKind::TraitObject(..) => self .with_tilde_const(Some(DisallowTildeConstContext::TraitObject), |this| { diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index cb95b7bce919..601910ded208 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -852,3 +852,12 @@ pub struct PreciseCapturingNotAllowedHere { pub span: Span, pub loc: &'static str, } + +#[derive(Diagnostic)] +#[diag(ast_passes_precise_capturing_duplicated)] +pub struct DuplicatePreciseCapturing { + #[primary_span] + pub bound1: Span, + #[label] + pub bound2: Span, +} diff --git a/tests/ui/impl-trait/precise-capturing/duplicated-use.pre_expansion.stderr b/tests/ui/impl-trait/precise-capturing/duplicated-use.pre_expansion.stderr new file mode 100644 index 000000000000..4ecec0143d6a --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/duplicated-use.pre_expansion.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/duplicated-use.rs:4:12 + | +LL | #![feature(precise_capturing)] + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #123432 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/impl-trait/precise-capturing/duplicated-use.real.stderr b/tests/ui/impl-trait/precise-capturing/duplicated-use.real.stderr new file mode 100644 index 000000000000..08367373d5ac --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/duplicated-use.real.stderr @@ -0,0 +1,17 @@ +error: duplicate `use<...>` precise capturing syntax + --> $DIR/duplicated-use.rs:8:32 + | +LL | fn hello<'a>() -> impl Sized + use<'a> + use<'a> {} + | ^^^^^^^ ------- second `use<...>` here + +warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/duplicated-use.rs:4:12 + | +LL | #![feature(precise_capturing)] + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #123432 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: aborting due to 1 previous error; 1 warning emitted + diff --git a/tests/ui/impl-trait/precise-capturing/duplicated-use.rs b/tests/ui/impl-trait/precise-capturing/duplicated-use.rs new file mode 100644 index 000000000000..36ccc104ea19 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/duplicated-use.rs @@ -0,0 +1,11 @@ +//@ revisions: real pre_expansion +//@[pre_expansion] check-pass + +#![feature(precise_capturing)] +//~^ WARN the feature `precise_capturing` is incomplete + +#[cfg(real)] +fn hello<'a>() -> impl Sized + use<'a> + use<'a> {} +//[real]~^ ERROR duplicate `use<...>` precise capturing syntax + +fn main() {}