Skip to content

Commit 5b76e77

Browse files
committed
Report a specialized error when a 'static obligation comes from an impl dyn Trait
```text error: lifetime may not live long enough --> $DIR/static-impl-obligation.rs:8:27 | LL | fn bar<'a>(x: &'a &'a u32) { | -- lifetime `'a` defined here LL | let y: &dyn Foo = x; | ^ cast requires that `'a` must outlive `'static` LL | y.hello(); | --------- calling this method introduces a `'static` lifetime requirement | help: relax the implicit `'static` bound on the impl | LL | impl dyn Foo + '_ { | ++++ ``` ```text error: lifetime may not live long enough --> $DIR/static-impl-obligation.rs:173:27 | LL | fn bar<'a>(x: &'a &'a u32) { | -- lifetime `'a` defined here LL | let y: &dyn Foo = x; | ^ cast requires that `'a` must outlive `'static` LL | y.hello(); | --------- calling this method introduces a `'static` lifetime requirement | note: the `impl` on `(dyn p::Foo + 'static)` has `'static` lifetime requirements --> $DIR/static-impl-obligation.rs:169:20 | LL | impl dyn Foo + 'static where Self: 'static { | ^^^^^^^ ^^^^^^^ LL | fn hello(&self) where Self: 'static {} | ^^^^^^^ ```
1 parent 8a49772 commit 5b76e77

File tree

18 files changed

+834
-73
lines changed

18 files changed

+834
-73
lines changed

compiler/rustc_borrowck/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ edition = "2021"
88
either = "1.5.0"
99
itertools = "0.11"
1010
polonius-engine = "0.13.0"
11+
rustc_ast = { path = "../rustc_ast" }
1112
rustc_data_structures = { path = "../rustc_data_structures" }
1213
rustc_errors = { path = "../rustc_errors" }
1314
rustc_fluent_macro = { path = "../rustc_fluent_macro" }

compiler/rustc_borrowck/src/diagnostics/region_errors.rs

+262-44
Large diffs are not rendered by default.

compiler/rustc_borrowck/src/region_infer/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -2051,6 +2051,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
20512051
CRATE_DEF_ID.to_def_id(),
20522052
predicate_span,
20532053
))
2054+
} else if let ConstraintCategory::CallArgument(Some(fn_def)) = constraint.category {
2055+
Some(ObligationCauseCode::MethodCallConstraint(fn_def, constraint.span))
20542056
} else {
20552057
None
20562058
}

compiler/rustc_borrowck/src/type_check/canonical.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
100100
locations: Locations,
101101
) {
102102
for (predicate, span) in instantiated_predicates {
103-
debug!(?predicate);
103+
debug!(?span, ?predicate);
104104
let category = ConstraintCategory::Predicate(span);
105105
let predicate = self.normalize_with_category(predicate, locations, category);
106106
self.prove_predicate(predicate, locations, category);

compiler/rustc_borrowck/src/type_check/constraint_conversion.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc_middle::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, Const
88
use rustc_middle::traits::query::NoSolution;
99
use rustc_middle::traits::ObligationCause;
1010
use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
11-
use rustc_span::{Span, DUMMY_SP};
11+
use rustc_span::Span;
1212
use rustc_trait_selection::solve::deeply_normalize;
1313
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
1414
use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
@@ -183,7 +183,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
183183

184184
// we don't actually use this for anything, but
185185
// the `TypeOutlives` code needs an origin.
186-
let origin = infer::RelateParamBound(DUMMY_SP, t1, None);
186+
let origin = infer::RelateParamBound(self.span, t1, None);
187187

188188
TypeOutlives::new(
189189
&mut *self,

compiler/rustc_borrowck/src/type_check/free_region_relations.rs

+10-6
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use rustc_middle::mir::ConstraintCategory;
1010
use rustc_middle::traits::query::OutlivesBound;
1111
use rustc_middle::traits::ObligationCause;
1212
use rustc_middle::ty::{self, RegionVid, Ty, TypeVisitableExt};
13-
use rustc_span::{ErrorGuaranteed, DUMMY_SP};
13+
use rustc_span::{ErrorGuaranteed, Span};
1414
use rustc_trait_selection::solve::deeply_normalize;
1515
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
1616
use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
@@ -269,7 +269,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
269269
debug!("build: input_or_output={:?}", ty);
270270
// We add implied bounds from both the unnormalized and normalized ty.
271271
// See issue #87748
272-
let constraints_unnorm = self.add_implied_bounds(ty);
272+
let constraints_unnorm = self.add_implied_bounds(ty, span);
273273
if let Some(c) = constraints_unnorm {
274274
constraints.push(c)
275275
}
@@ -299,7 +299,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
299299
// ```
300300
// Both &Self::Bar and &() are WF
301301
if ty != norm_ty {
302-
let constraints_norm = self.add_implied_bounds(norm_ty);
302+
let constraints_norm = self.add_implied_bounds(norm_ty, span);
303303
if let Some(c) = constraints_norm {
304304
constraints.push(c)
305305
}
@@ -323,7 +323,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
323323

324324
// We currently add implied bounds from the normalized ty only.
325325
// This is more conservative and matches wfcheck behavior.
326-
let c = self.add_implied_bounds(norm_ty);
326+
let c = self.add_implied_bounds(norm_ty, span);
327327
constraints.extend(c);
328328
}
329329
}
@@ -361,11 +361,15 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
361361
/// the same time, compute and add any implied bounds that come
362362
/// from this local.
363363
#[instrument(level = "debug", skip(self))]
364-
fn add_implied_bounds(&mut self, ty: Ty<'tcx>) -> Option<&'tcx QueryRegionConstraints<'tcx>> {
364+
fn add_implied_bounds(
365+
&mut self,
366+
ty: Ty<'tcx>,
367+
span: Span,
368+
) -> Option<&'tcx QueryRegionConstraints<'tcx>> {
365369
let TypeOpOutput { output: bounds, constraints, .. } = self
366370
.param_env
367371
.and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
368-
.fully_perform(self.infcx, DUMMY_SP)
372+
.fully_perform(self.infcx, span)
369373
.map_err(|_: ErrorGuaranteed| debug!("failed to compute implied bounds {:?}", ty))
370374
.ok()?;
371375
debug!(?bounds, ?constraints);

compiler/rustc_borrowck/src/type_check/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ use rustc_mir_dataflow::points::DenseLocationMap;
3737
use rustc_span::def_id::CRATE_DEF_ID;
3838
use rustc_span::source_map::Spanned;
3939
use rustc_span::symbol::sym;
40-
use rustc_span::{Span, DUMMY_SP};
40+
use rustc_span::Span;
4141
use rustc_target::abi::{FieldIdx, FIRST_VARIANT};
4242
use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints;
4343
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
@@ -1014,7 +1014,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
10141014
) -> Self {
10151015
let mut checker = Self {
10161016
infcx,
1017-
last_span: DUMMY_SP,
1017+
last_span: body.span,
10181018
body,
10191019
user_type_annotations: &body.user_type_annotations,
10201020
param_env,
@@ -2766,7 +2766,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
27662766
self.param_env,
27672767
self.known_type_outlives_obligations,
27682768
locations,
2769-
DUMMY_SP, // irrelevant; will be overridden.
2769+
self.body.span, // irrelevant; will be overridden.
27702770
ConstraintCategory::Boring, // same as above.
27712771
self.borrowck_context.constraints,
27722772
)

compiler/rustc_hir_analysis/src/collect.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1630,7 +1630,7 @@ fn early_bound_lifetimes_from_generics<'a, 'tcx: 'a>(
16301630
#[instrument(level = "debug", skip(tcx))]
16311631
fn predicates_defined_on(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
16321632
let mut result = tcx.explicit_predicates_of(def_id);
1633-
debug!("predicates_defined_on: explicit_predicates_of({:?}) = {:?}", def_id, result,);
1633+
debug!("predicates_defined_on: explicit_predicates_of({:?}) = {:?}", def_id, result);
16341634
let inferred_outlives = tcx.inferred_outlives_of(def_id);
16351635
if !inferred_outlives.is_empty() {
16361636
debug!(

compiler/rustc_infer/src/infer/canonical/query_response.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,7 @@ impl<'tcx> InferCtxt<'tcx> {
405405
/// will instantiate fresh inference variables for each canonical
406406
/// variable instead. Therefore, the result of this method must be
407407
/// properly unified
408-
#[instrument(level = "debug", skip(self, cause, param_env))]
408+
#[instrument(level = "debug", skip(self, param_env))]
409409
fn query_response_instantiation_guess<R>(
410410
&self,
411411
cause: &ObligationCause<'tcx>,

compiler/rustc_middle/src/traits/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,9 @@ pub enum ObligationCauseCode<'tcx> {
451451

452452
/// Obligations emitted during the normalization of a weak type alias.
453453
TypeAlias(InternedObligationCauseCode<'tcx>, Span, DefId),
454+
455+
/// During borrowck we've found a method call that could have introduced a lifetime requirement.
456+
MethodCallConstraint(Ty<'tcx>, Span),
454457
}
455458

456459
/// Whether a value can be extracted into a const.

compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2683,6 +2683,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
26832683
| ObligationCauseCode::MethodReceiver
26842684
| ObligationCauseCode::ReturnNoExpression
26852685
| ObligationCauseCode::UnifyReceiver(..)
2686+
| ObligationCauseCode::MethodCallConstraint(..)
26862687
| ObligationCauseCode::MiscObligation
26872688
| ObligationCauseCode::WellFormed(..)
26882689
| ObligationCauseCode::MatchImpl(..)

compiler/rustc_trait_selection/src/traits/outlives_bounds.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,10 @@ fn implied_outlives_bounds<'a, 'tcx>(
6262
};
6363

6464
let mut constraints = QueryRegionConstraints::default();
65+
let span = infcx.tcx.def_span(body_id);
6566
let Ok(InferOk { value: mut bounds, obligations }) = infcx
6667
.instantiate_nll_query_response_and_region_obligations(
67-
&ObligationCause::dummy(),
68+
&ObligationCause::dummy_with_span(span),
6869
param_env,
6970
&canonical_var_values,
7071
canonical_result,
@@ -80,8 +81,6 @@ fn implied_outlives_bounds<'a, 'tcx>(
8081
bounds.retain(|bound| !bound.has_placeholders());
8182

8283
if !constraints.is_empty() {
83-
let span = infcx.tcx.def_span(body_id);
84-
8584
debug!(?constraints);
8685
if !constraints.member_constraints.is_empty() {
8786
span_bug!(span, "{:#?}", constraints.member_constraints);
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
error: internal compiler error: error performing ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing }, value: ImpliedOutlivesBounds { ty: &'?2 mut StateContext<'?3, usize> } }
2+
--> $DIR/issue-80409.rs:48:30
23
|
3-
= query stack during panic:
4+
LL | builder.state().on_entry(|_| {});
5+
| ^^^
6+
|
7+
note: delayed at /home/gh-estebank/rust/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs:164:29 - disabled backtrace
8+
--> $DIR/issue-80409.rs:48:30
9+
|
10+
LL | builder.state().on_entry(|_| {});
11+
| ^^^
12+
13+
query stack during panic:
414
end of query stack
515
error: aborting due to 1 previous error
616

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
mod a {
2+
trait Foo {}
3+
impl<'a> Foo for &'a u32 {}
4+
impl dyn Foo { //~ HELP consider relaxing the implicit `'static` requirement
5+
fn hello(&self) {}
6+
}
7+
fn bar<'a>(x: &'a &'a u32) {
8+
let y: &dyn Foo = x; //~ ERROR lifetime may not live long enough
9+
y.hello();
10+
}
11+
}
12+
mod b {
13+
trait Foo {}
14+
impl<'a> Foo for &'a u32 {}
15+
impl dyn Foo {
16+
fn hello(&'static self) {}
17+
}
18+
fn bar<'a>(x: &'a &'a u32) {
19+
let y: &dyn Foo = x; //~ ERROR lifetime may not live long enough
20+
y.hello();
21+
}
22+
}
23+
mod c {
24+
trait Foo {}
25+
impl<'a> Foo for &'a u32 {}
26+
impl dyn Foo {
27+
fn hello(&'static self) where Self: 'static {}
28+
}
29+
fn bar<'a>(x: &'a &'a u32) {
30+
let y: &dyn Foo = x; //~ ERROR lifetime may not live long enough
31+
y.hello();
32+
}
33+
}
34+
mod d {
35+
trait Foo {}
36+
impl<'a> Foo for &'a u32 {}
37+
impl dyn Foo {
38+
fn hello(&self) where Self: 'static {}
39+
}
40+
fn bar<'a>(x: &'a &'a u32) {
41+
let y: &dyn Foo = x; //~ ERROR lifetime may not live long enough
42+
y.hello();
43+
}
44+
}
45+
mod e {
46+
trait Foo {}
47+
impl<'a> Foo for &'a u32 {}
48+
impl dyn Foo + 'static { //~ HELP consider replacing this `'static` requirement
49+
fn hello(&self) {}
50+
}
51+
fn bar<'a>(x: &'a &'a u32) {
52+
let y: &dyn Foo = x; //~ ERROR lifetime may not live long enough
53+
y.hello();
54+
}
55+
}
56+
mod f {
57+
trait Foo {}
58+
impl<'a> Foo for &'a u32 {}
59+
impl dyn Foo + 'static {
60+
fn hello(&'static self) {}
61+
}
62+
fn bar<'a>(x: &'a &'a u32) {
63+
let y: &dyn Foo = x; //~ ERROR lifetime may not live long enough
64+
y.hello();
65+
}
66+
}
67+
mod g {
68+
trait Foo {}
69+
impl<'a> Foo for &'a u32 {}
70+
impl dyn Foo + 'static {
71+
fn hello(&'static self) where Self: 'static {}
72+
}
73+
fn bar<'a>(x: &'a &'a u32) {
74+
let y: &dyn Foo = x; //~ ERROR lifetime may not live long enough
75+
y.hello();
76+
}
77+
}
78+
mod h {
79+
trait Foo {}
80+
impl<'a> Foo for &'a u32 {}
81+
impl dyn Foo + 'static {
82+
fn hello(&self) where Self: 'static {}
83+
}
84+
fn bar<'a>(x: &'a &'a u32) {
85+
let y: &dyn Foo = x; //~ ERROR lifetime may not live long enough
86+
y.hello();
87+
}
88+
}
89+
mod i {
90+
trait Foo {}
91+
impl<'a> Foo for &'a u32 {}
92+
impl dyn Foo where Self: 'static {
93+
fn hello(&self) {}
94+
}
95+
fn bar<'a>(x: &'a &'a u32) {
96+
let y: &dyn Foo = x; //~ ERROR lifetime may not live long enough
97+
y.hello();
98+
}
99+
}
100+
mod j {
101+
trait Foo {}
102+
impl<'a> Foo for &'a u32 {}
103+
impl dyn Foo where Self: 'static {
104+
fn hello(&'static self) {}
105+
}
106+
fn bar<'a>(x: &'a &'a u32) {
107+
let y: &dyn Foo = x; //~ ERROR lifetime may not live long enough
108+
y.hello();
109+
}
110+
}
111+
mod k {
112+
trait Foo {}
113+
impl<'a> Foo for &'a u32 {}
114+
impl dyn Foo where Self: 'static {
115+
fn hello(&'static self) where Self: 'static {}
116+
}
117+
fn bar<'a>(x: &'a &'a u32) {
118+
let y: &dyn Foo = x; //~ ERROR lifetime may not live long enough
119+
y.hello();
120+
}
121+
}
122+
mod l {
123+
trait Foo {}
124+
impl<'a> Foo for &'a u32 {}
125+
impl dyn Foo where Self: 'static {
126+
fn hello(&self) where Self: 'static {}
127+
}
128+
fn bar<'a>(x: &'a &'a u32) {
129+
let y: &dyn Foo = x; //~ ERROR lifetime may not live long enough
130+
y.hello();
131+
}
132+
}
133+
mod m {
134+
trait Foo {}
135+
impl<'a> Foo for &'a u32 {}
136+
impl dyn Foo + 'static where Self: 'static {
137+
fn hello(&self) {}
138+
}
139+
fn bar<'a>(x: &'a &'a u32) {
140+
let y: &dyn Foo = x; //~ ERROR lifetime may not live long enough
141+
y.hello();
142+
}
143+
}
144+
mod n {
145+
trait Foo {}
146+
impl<'a> Foo for &'a u32 {}
147+
impl dyn Foo + 'static where Self: 'static {
148+
fn hello(&'static self) {}
149+
}
150+
fn bar<'a>(x: &'a &'a u32) {
151+
let y: &dyn Foo = x; //~ ERROR lifetime may not live long enough
152+
y.hello();
153+
}
154+
}
155+
mod o {
156+
trait Foo {}
157+
impl<'a> Foo for &'a u32 {}
158+
impl dyn Foo + 'static where Self: 'static {
159+
fn hello(&'static self) where Self: 'static {}
160+
}
161+
fn bar<'a>(x: &'a &'a u32) {
162+
let y: &dyn Foo = x; //~ ERROR lifetime may not live long enough
163+
y.hello();
164+
}
165+
}
166+
mod p {
167+
trait Foo {}
168+
impl<'a> Foo for &'a u32 {}
169+
impl dyn Foo + 'static where Self: 'static {
170+
fn hello(&self) where Self: 'static {}
171+
}
172+
fn bar<'a>(x: &'a &'a u32) {
173+
let y: &dyn Foo = x; //~ ERROR lifetime may not live long enough
174+
y.hello();
175+
}
176+
}
177+
mod q {
178+
struct Foo {}
179+
impl Foo {
180+
fn hello(&'static self) {}
181+
}
182+
fn bar<'a>(x: &'a &'a Foo) {
183+
x.hello(); //~ ERROR borrowed data escapes outside of function
184+
}
185+
}
186+
mod r {
187+
struct Foo {}
188+
impl Foo {
189+
fn hello(&'static self) where Self: 'static {}
190+
}
191+
fn bar<'a>(x: &'a &'a Foo) {
192+
x.hello(); //~ ERROR borrowed data escapes outside of function
193+
}
194+
}
195+
fn main() {}

0 commit comments

Comments
 (0)