Skip to content

Commit e6dc0de

Browse files
Some ordering and duplication checks
1 parent d4a6e7d commit e6dc0de

File tree

8 files changed

+141
-16
lines changed

8 files changed

+141
-16
lines changed

compiler/rustc_ast_lowering/src/index.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
390390
match arg {
391391
PreciseCapturingArg::Lifetime(_) => {
392392
// This is represented as a `Node::Lifetime`, intravisit will get to it below.
393-
},
393+
}
394394
PreciseCapturingArg::Param(param) => self.insert(
395395
param.ident.span,
396396
param.hir_id,

compiler/rustc_hir_analysis/messages.ftl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@ hir_analysis_drop_impl_on_wrong_item =
113113
114114
hir_analysis_drop_impl_reservation = reservation `Drop` impls are not supported
115115
116+
hir_analysis_duplicate_precise_capture = cannot capture parameter `{$name}` twice
117+
.label = parameter captured again here
118+
116119
hir_analysis_empty_specialization = specialization impl does not specialize any associated items
117120
.note = impl is a specialization of this impl
118121
@@ -216,6 +219,9 @@ hir_analysis_late_bound_lifetime_in_apit = `impl Trait` can only mention lifetim
216219
hir_analysis_late_bound_type_in_apit = `impl Trait` can only mention type parameters from an fn or impl
217220
.label = type parameter declared here
218221
222+
hir_analysis_lifetime_must_be_first = lifetime parameter `{$name}` must be listed before non-lifetime parameters
223+
.label = move the lifetime before this parameter
224+
219225
hir_analysis_lifetime_not_captured = `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list
220226
.label = lifetime captured due to being mentioned in the bounds of the `impl Trait`
221227
.param_label = this lifetime parameter is captured

compiler/rustc_hir_analysis/src/check/check.rs

Lines changed: 43 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use super::compare_impl_item::check_type_bounds;
44
use super::compare_impl_item::{compare_impl_method, compare_impl_ty};
55
use super::*;
66
use rustc_attr as attr;
7-
use rustc_data_structures::unord::UnordSet;
7+
use rustc_data_structures::unord::{UnordMap, UnordSet};
88
use rustc_errors::{codes::*, MultiSpan};
99
use rustc_hir as hir;
1010
use rustc_hir::def::{CtorKind, DefKind};
@@ -488,22 +488,51 @@ fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDe
488488
};
489489

490490
let mut expected_captures = UnordSet::default();
491+
let mut seen_params = UnordMap::default();
492+
let mut prev_non_lifetime_param = None;
491493
for arg in precise_capturing_args {
492-
match *arg {
493-
hir::PreciseCapturingArg::Lifetime(&hir::Lifetime { hir_id, .. })
494-
| hir::PreciseCapturingArg::Param(hir::PreciseCapturingNonLifetimeArg {
495-
hir_id, ..
496-
}) => match tcx.named_bound_var(hir_id) {
497-
Some(ResolvedArg::EarlyBound(def_id)) => {
498-
expected_captures.insert(def_id);
494+
let (hir_id, ident) = match *arg {
495+
hir::PreciseCapturingArg::Param(hir::PreciseCapturingNonLifetimeArg {
496+
hir_id,
497+
ident,
498+
..
499+
}) => {
500+
if prev_non_lifetime_param.is_none() {
501+
prev_non_lifetime_param = Some(ident);
499502
}
500-
_ => {
501-
tcx.dcx().span_delayed_bug(
502-
tcx.hir().span(hir_id),
503-
"parameter should have been resolved",
504-
);
503+
(hir_id, ident)
504+
}
505+
hir::PreciseCapturingArg::Lifetime(&hir::Lifetime { hir_id, ident, .. }) => {
506+
if let Some(prev_non_lifetime_param) = prev_non_lifetime_param {
507+
tcx.dcx().emit_err(errors::LifetimesMustBeFirst {
508+
lifetime_span: ident.span,
509+
name: ident.name,
510+
other_span: prev_non_lifetime_param.span,
511+
});
505512
}
506-
},
513+
(hir_id, ident)
514+
}
515+
};
516+
517+
let ident = ident.normalize_to_macros_2_0();
518+
if let Some(span) = seen_params.insert(ident, ident.span) {
519+
tcx.dcx().emit_err(errors::DuplicatePreciseCapture {
520+
name: ident.name,
521+
first_span: span,
522+
second_span: ident.span,
523+
});
524+
}
525+
526+
match tcx.named_bound_var(hir_id) {
527+
Some(ResolvedArg::EarlyBound(def_id)) => {
528+
expected_captures.insert(def_id);
529+
}
530+
_ => {
531+
tcx.dcx().span_delayed_bug(
532+
tcx.hir().span(hir_id),
533+
"parameter should have been resolved",
534+
);
535+
}
507536
}
508537
}
509538

compiler/rustc_hir_analysis/src/errors/precise_captures.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use rustc_macros::Diagnostic;
2-
use rustc_span::Span;
2+
use rustc_span::{Span, Symbol};
33

44
#[derive(Diagnostic)]
55
#[diag(hir_analysis_param_not_captured)]
@@ -31,3 +31,23 @@ pub struct BadPreciseCapture {
3131
pub kind: &'static str,
3232
pub found: String,
3333
}
34+
35+
#[derive(Diagnostic)]
36+
#[diag(hir_analysis_duplicate_precise_capture)]
37+
pub struct DuplicatePreciseCapture {
38+
#[primary_span]
39+
pub first_span: Span,
40+
pub name: Symbol,
41+
#[label]
42+
pub second_span: Span,
43+
}
44+
45+
#[derive(Diagnostic)]
46+
#[diag(hir_analysis_lifetime_must_be_first)]
47+
pub struct LifetimesMustBeFirst {
48+
#[primary_span]
49+
pub lifetime_span: Span,
50+
pub name: Symbol,
51+
#[label]
52+
pub other_span: Span,
53+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
fn hello() -> impl use<> Sized {}
2+
//~^ ERROR precise captures on `impl Trait` are experimental
3+
4+
fn main() {}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error[E0658]: precise captures on `impl Trait` are experimental
2+
--> $DIR/feature-gate-precise-capturing.rs:1:20
3+
|
4+
LL | fn hello() -> impl use<> Sized {}
5+
| ^^^
6+
|
7+
= note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
8+
= help: add `#![feature(precise_capturing)]` to the crate attributes to enable
9+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
10+
11+
error: aborting due to 1 previous error
12+
13+
For more information about this error, try `rustc --explain E0658`.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#![feature(precise_capturing)]
2+
//~^ WARN the feature `precise_capturing` is incomplete
3+
4+
fn lt<'a>() -> impl use<'a, 'a> Sized {}
5+
//~^ ERROR cannot capture parameter `'a` twice
6+
7+
fn ty<T>() -> impl use<T, T> Sized {}
8+
//~^ ERROR cannot capture parameter `T` twice
9+
10+
fn ct<const N: usize>() -> impl use<N, N> Sized {}
11+
//~^ ERROR cannot capture parameter `N` twice
12+
13+
fn ordering<'a, T>() -> impl use<T, 'a> Sized {}
14+
//~^ ERROR lifetime parameter `'a` must be listed before non-lifetime parameters
15+
16+
fn main() {}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/ordering.rs:1:12
3+
|
4+
LL | #![feature(precise_capturing)]
5+
| ^^^^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
8+
= note: `#[warn(incomplete_features)]` on by default
9+
10+
error: cannot capture parameter `'a` twice
11+
--> $DIR/ordering.rs:4:25
12+
|
13+
LL | fn lt<'a>() -> impl use<'a, 'a> Sized {}
14+
| ^^ -- parameter captured again here
15+
16+
error: cannot capture parameter `T` twice
17+
--> $DIR/ordering.rs:7:24
18+
|
19+
LL | fn ty<T>() -> impl use<T, T> Sized {}
20+
| ^ - parameter captured again here
21+
22+
error: cannot capture parameter `N` twice
23+
--> $DIR/ordering.rs:10:37
24+
|
25+
LL | fn ct<const N: usize>() -> impl use<N, N> Sized {}
26+
| ^ - parameter captured again here
27+
28+
error: lifetime parameter `'a` must be listed before non-lifetime parameters
29+
--> $DIR/ordering.rs:13:37
30+
|
31+
LL | fn ordering<'a, T>() -> impl use<T, 'a> Sized {}
32+
| - ^^
33+
| |
34+
| move the lifetime before this parameter
35+
36+
error: aborting due to 4 previous errors; 1 warning emitted
37+

0 commit comments

Comments
 (0)