about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2024-06-05 16:43:25 -0400
committerMichael Goulet <michael@errs.io>2024-06-17 22:35:25 -0400
commit2e03130e112d86c693076ddba3f957542632d7e1 (patch)
tree85770a342f3c802070cc51d3fc5ce888bacdf4b1
parentf66558d2bfe2bbfac14f8c0472a300bbd5234ce2 (diff)
downloadrust-2e03130e112d86c693076ddba3f957542632d7e1.tar.gz
rust-2e03130e112d86c693076ddba3f957542632d7e1.zip
Detect duplicates
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs11
-rw-r--r--compiler/rustc_ast_passes/messages.ftl7
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs20
-rw-r--r--compiler/rustc_ast_passes/src/errors.rs9
-rw-r--r--tests/ui/impl-trait/precise-capturing/duplicated-use.pre_expansion.stderr11
-rw-r--r--tests/ui/impl-trait/precise-capturing/duplicated-use.real.stderr17
-rw-r--r--tests/ui/impl-trait/precise-capturing/duplicated-use.rs11
7 files changed, 78 insertions, 8 deletions
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 1fc6a969915..b998912bf6d 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1531,10 +1531,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         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 518ac9256a1..2626631d800 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 de96bdd557f..93abe36a2db 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -193,8 +193,24 @@ impl<'a> AstValidator<'a> {
     // 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 cb95b7bce91..601910ded20 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 00000000000..4ecec0143d6
--- /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 <https://github.com/rust-lang/rust/issues/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 00000000000..08367373d5a
--- /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 <https://github.com/rust-lang/rust/issues/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 00000000000..36ccc104ea1
--- /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() {}