Skip to content

Commit 94d6245

Browse files
author
Lukas Markeffsky
committed
Fix explicit_outlives_requirements lint in macros
Show the suggestion if and only if the bounds are from the same source context.
1 parent 2d8651a commit 94d6245

File tree

4 files changed

+98
-38
lines changed

4 files changed

+98
-38
lines changed

compiler/rustc_ast_lowering/src/item.rs

+2-15
Original file line numberDiff line numberDiff line change
@@ -1377,21 +1377,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
13771377

13781378
let ident = self.lower_ident(ident);
13791379
let param_span = ident.span;
1380-
let span = bounds
1381-
.iter()
1382-
.fold(Some(param_span.shrink_to_hi()), |span: Option<Span>, bound| {
1383-
let bound_span = bound.span();
1384-
// We include bounds that come from a `#[derive(_)]` but point at the user's code,
1385-
// as we use this method to get a span appropriate for suggestions.
1386-
if !bound_span.can_be_used_for_suggestions() {
1387-
None
1388-
} else if let Some(span) = span {
1389-
Some(span.to(bound_span))
1390-
} else {
1391-
Some(bound_span)
1392-
}
1393-
})
1394-
.unwrap_or(param_span.shrink_to_hi());
1380+
let span =
1381+
bounds.iter().fold(param_span.shrink_to_hi(), |span, bound| span.to(bound.span()));
13951382
match kind {
13961383
GenericParamKind::Const { .. } => None,
13971384
GenericParamKind::Type { .. } => {

compiler/rustc_lint/src/builtin.rs

+30-20
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ use rustc_session::lint::{BuiltinLintDiagnostics, FutureIncompatibilityReason};
5555
use rustc_span::edition::Edition;
5656
use rustc_span::source_map::Spanned;
5757
use rustc_span::symbol::{kw, sym, Ident, Symbol};
58-
use rustc_span::{BytePos, InnerSpan, Span};
58+
use rustc_span::{BytePos, InnerSpan, Span, SyntaxContext};
5959
use rustc_target::abi::{Abi, VariantIdx};
6060
use rustc_trait_selection::infer::{InferCtxtExt, TyCtxtInferExt};
6161
use rustc_trait_selection::traits::{self, misc::can_type_implement_copy, EvaluationResult};
@@ -2184,30 +2184,36 @@ impl ExplicitOutlivesRequirements {
21842184
tcx: TyCtxt<'tcx>,
21852185
bounds: &hir::GenericBounds<'_>,
21862186
inferred_outlives: &[ty::Region<'tcx>],
2187+
span_cx: SyntaxContext,
21872188
) -> Vec<(usize, Span)> {
21882189
use rustc_middle::middle::resolve_lifetime::Region;
21892190

21902191
bounds
21912192
.iter()
21922193
.enumerate()
21932194
.filter_map(|(i, bound)| {
2194-
if let hir::GenericBound::Outlives(lifetime) = bound {
2195-
let is_inferred = match tcx.named_region(lifetime.hir_id) {
2196-
Some(Region::EarlyBound(def_id)) => inferred_outlives.iter().any(|r| {
2197-
if let ty::ReEarlyBound(ebr) = **r {
2198-
ebr.def_id == def_id
2199-
} else {
2200-
false
2201-
}
2202-
}),
2203-
_ => false,
2204-
};
2205-
is_inferred.then_some((i, bound.span()))
2206-
} else {
2207-
None
2195+
let hir::GenericBound::Outlives(lifetime) = bound else {
2196+
return None;
2197+
};
2198+
2199+
let is_inferred = match tcx.named_region(lifetime.hir_id) {
2200+
Some(Region::EarlyBound(def_id)) => inferred_outlives
2201+
.iter()
2202+
.any(|r| matches!(**r, ty::ReEarlyBound(ebr) if { ebr.def_id == def_id })),
2203+
_ => false,
2204+
};
2205+
2206+
if !is_inferred {
2207+
return None;
2208+
}
2209+
2210+
let span = bound.span();
2211+
if span.ctxt() != span_cx || in_external_macro(tcx.sess, span) {
2212+
return None;
22082213
}
2214+
2215+
Some((i, span))
22092216
})
2210-
.filter(|(_, span)| !in_external_macro(tcx.sess, *span))
22112217
.collect()
22122218
}
22132219

@@ -2312,9 +2318,9 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
23122318
// FIXME we can also infer bounds on associated types,
23132319
// and should check for them here.
23142320
match predicate.bounded_ty.kind {
2315-
hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => {
2321+
hir::TyKind::Path(hir::QPath::Resolved(None, path)) => {
23162322
let Res::Def(DefKind::TyParam, def_id) = path.res else {
2317-
continue
2323+
continue;
23182324
};
23192325
let index = ty_generics.param_def_id_to_index[&def_id];
23202326
(
@@ -2335,8 +2341,12 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
23352341
continue;
23362342
}
23372343

2338-
let bound_spans =
2339-
self.collect_outlives_bound_spans(cx.tcx, bounds, &relevant_lifetimes);
2344+
let bound_spans = self.collect_outlives_bound_spans(
2345+
cx.tcx,
2346+
bounds,
2347+
&relevant_lifetimes,
2348+
span.ctxt(),
2349+
);
23402350
bound_count += bound_spans.len();
23412351

23422352
let drop_predicate = bound_spans.len() == bounds.len();

src/test/ui/rust-2018/edition-lint-infer-outlives-macro.rs

+42-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@ macro_rules! make_foo {
1515
struct Foo<$a, 'b> where 'b: $a {
1616
foo: &$a &'b (),
1717
}
18-
}
18+
19+
struct Foo2<$a, 'b: $a> {
20+
foo: &$a &'b (),
21+
}
22+
};
1923
}
2024

2125
gimme_a! {make_foo!}
@@ -25,4 +29,41 @@ struct Bar<'a, 'b: 'a> {
2529
bar: &'a &'b (),
2630
}
2731

32+
macro_rules! make_quux {
33+
() => {
34+
struct Quux<'a, 'b> where 'b: 'a {
35+
//~^ ERROR: outlives requirements can be inferred
36+
baz: &'a &'b (),
37+
}
38+
39+
struct Quux2<'a, 'b: 'a> {
40+
//~^ ERROR: outlives requirements can be inferred
41+
baz: &'a &'b (),
42+
}
43+
};
44+
}
45+
46+
make_quux!{}
47+
48+
macro_rules! make_baz {
49+
() => {
50+
make_baz!{ 'a }
51+
};
52+
($a:lifetime) => {
53+
struct Baz<$a, 'b> where 'b: $a {
54+
baz: &$a &'b (),
55+
}
56+
57+
struct Baz2<$a, 'b: $a> {
58+
baz: &$a &'b (),
59+
}
60+
};
61+
}
62+
63+
make_baz!{ 'a }
64+
65+
mod baz {
66+
make_baz!{}
67+
}
68+
2869
fn main() {}

src/test/ui/rust-2018/edition-lint-infer-outlives-macro.stderr

+24-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: outlives requirements can be inferred
2-
--> $DIR/edition-lint-infer-outlives-macro.rs:23:18
2+
--> $DIR/edition-lint-infer-outlives-macro.rs:27:18
33
|
44
LL | struct Bar<'a, 'b: 'a> {
55
| ^^^^ help: remove this bound
@@ -10,5 +10,27 @@ note: the lint level is defined here
1010
LL | #![deny(explicit_outlives_requirements)]
1111
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1212

13-
error: aborting due to previous error
13+
error: outlives requirements can be inferred
14+
--> $DIR/edition-lint-infer-outlives-macro.rs:34:28
15+
|
16+
LL | struct Quux<'a, 'b> where 'b: 'a {
17+
| ^^^^^^^^^^^^^ help: remove this bound
18+
...
19+
LL | make_quux!{}
20+
| ------------ in this macro invocation
21+
|
22+
= note: this error originates in the macro `make_quux` (in Nightly builds, run with -Z macro-backtrace for more info)
23+
24+
error: outlives requirements can be inferred
25+
--> $DIR/edition-lint-infer-outlives-macro.rs:39:28
26+
|
27+
LL | struct Quux2<'a, 'b: 'a> {
28+
| ^^^^ help: remove this bound
29+
...
30+
LL | make_quux!{}
31+
| ------------ in this macro invocation
32+
|
33+
= note: this error originates in the macro `make_quux` (in Nightly builds, run with -Z macro-backtrace for more info)
34+
35+
error: aborting due to 3 previous errors
1436

0 commit comments

Comments
 (0)