Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit e949b49

Browse files
committedMar 12, 2024
promotion: do not promote const-fn calls in const when that may fail without the entire const failing
1 parent 6554a56 commit e949b49

11 files changed

+193
-247
lines changed
 

‎compiler/rustc_mir_transform/src/lib.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -343,13 +343,6 @@ fn mir_promoted(
343343
body.tainted_by_errors = Some(error_reported);
344344
}
345345

346-
let mut required_consts = Vec::new();
347-
let mut required_consts_visitor = RequiredConstsVisitor::new(&mut required_consts);
348-
for (bb, bb_data) in traversal::reverse_postorder(&body) {
349-
required_consts_visitor.visit_basic_block_data(bb, bb_data);
350-
}
351-
body.required_consts = required_consts;
352-
353346
// What we need to run borrowck etc.
354347
let promote_pass = promote_consts::PromoteTemps::default();
355348
pm::run_passes(
@@ -359,6 +352,14 @@ fn mir_promoted(
359352
Some(MirPhase::Analysis(AnalysisPhase::Initial)),
360353
);
361354

355+
// Promotion generates new consts; we run this after promotion to ensure they are accounted for.
356+
let mut required_consts = Vec::new();
357+
let mut required_consts_visitor = RequiredConstsVisitor::new(&mut required_consts);
358+
for (bb, bb_data) in traversal::reverse_postorder(&body) {
359+
required_consts_visitor.visit_basic_block_data(bb, bb_data);
360+
}
361+
body.required_consts = required_consts;
362+
362363
let promoted = promote_pass.promoted_fragments.into_inner();
363364
(tcx.alloc_steal_mir(body), tcx.alloc_steal_promoted(promoted))
364365
}

‎compiler/rustc_mir_transform/src/promote_consts.rs

Lines changed: 79 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
//! move analysis runs after promotion on broken MIR.
1414
1515
use either::{Left, Right};
16+
use rustc_data_structures::fx::FxHashSet;
1617
use rustc_hir as hir;
1718
use rustc_middle::mir;
1819
use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
@@ -175,6 +176,12 @@ fn collect_temps_and_candidates<'tcx>(
175176
struct Validator<'a, 'tcx> {
176177
ccx: &'a ConstCx<'a, 'tcx>,
177178
temps: &'a mut IndexSlice<Local, TempState>,
179+
/// For backwards compatibility, we are promoting function calls in `const`/`static`
180+
/// initializers. But we want to avoid evaluating code that might panic and that otherwise would
181+
/// not have been evaluated, so we only promote such calls in basic blocks that are guaranteed
182+
/// to execute. In other words, we only promote such calls in basic blocks that are definitely
183+
/// not dead code. Here we cache the result of computing that set of basic blocks.
184+
promotion_safe_blocks: Option<FxHashSet<BasicBlock>>,
178185
}
179186

180187
impl<'a, 'tcx> std::ops::Deref for Validator<'a, 'tcx> {
@@ -260,7 +267,9 @@ impl<'tcx> Validator<'_, 'tcx> {
260267
self.validate_rvalue(rhs)
261268
}
262269
Right(terminator) => match &terminator.kind {
263-
TerminatorKind::Call { func, args, .. } => self.validate_call(func, args),
270+
TerminatorKind::Call { func, args, .. } => {
271+
self.validate_call(func, args, loc.block)
272+
}
264273
TerminatorKind::Yield { .. } => Err(Unpromotable),
265274
kind => {
266275
span_bug!(terminator.source_info.span, "{:?} not promotable", kind);
@@ -587,42 +596,93 @@ impl<'tcx> Validator<'_, 'tcx> {
587596
Ok(())
588597
}
589598

599+
/// Computes the sets of blocks of this MIR that are definitely going to be executed
600+
/// if the function returns successfully. That makes it safe to promote calls in them
601+
/// that might fail.
602+
fn promotion_safe_blocks(body: &mir::Body<'tcx>) -> FxHashSet<BasicBlock> {
603+
let mut safe_blocks = FxHashSet::default();
604+
let mut safe_block = START_BLOCK;
605+
loop {
606+
safe_blocks.insert(safe_block);
607+
// Let's see if we can find another safe block.
608+
safe_block = match body.basic_blocks[safe_block].terminator().kind {
609+
TerminatorKind::Goto { target } => target,
610+
TerminatorKind::Call { target: Some(target), .. }
611+
| TerminatorKind::Drop { target, .. } => {
612+
// This calls a function or the destructor. `target` does not get executed if
613+
// the callee loops or panics. But in both cases the const already fails to
614+
// evaluate, so we are fine considering `target` a safe block for promotion.
615+
target
616+
}
617+
TerminatorKind::Assert { target, .. } => {
618+
// Similar to above, we only consider successful execution.
619+
target
620+
}
621+
_ => {
622+
// No next safe block.
623+
break;
624+
}
625+
};
626+
}
627+
safe_blocks
628+
}
629+
630+
/// Returns whether the block is "safe" for promotion, which means it cannot be dead code.
631+
/// We use this to avoid promoting operations that can fail in dead code.
632+
fn is_promotion_safe_block(&mut self, block: BasicBlock) -> bool {
633+
let body = self.body;
634+
let safe_blocks =
635+
self.promotion_safe_blocks.get_or_insert_with(|| Self::promotion_safe_blocks(body));
636+
safe_blocks.contains(&block)
637+
}
638+
590639
fn validate_call(
591640
&mut self,
592641
callee: &Operand<'tcx>,
593642
args: &[Spanned<Operand<'tcx>>],
643+
block: BasicBlock,
594644
) -> Result<(), Unpromotable> {
645+
// Validate the operands. If they fail, there's no question -- we cannot promote.
646+
self.validate_operand(callee)?;
647+
for arg in args {
648+
self.validate_operand(&arg.node)?;
649+
}
650+
651+
// Functions marked `#[rustc_promotable]` are explicitly allowed to be promoted, so we can
652+
// accept them at this point.
595653
let fn_ty = callee.ty(self.body, self.tcx);
654+
if let ty::FnDef(def_id, _) = *fn_ty.kind() {
655+
if self.tcx.is_promotable_const_fn(def_id) {
656+
return Ok(());
657+
}
658+
}
596659

597-
// Inside const/static items, we promote all (eligible) function calls.
598-
// Everywhere else, we require `#[rustc_promotable]` on the callee.
599-
let promote_all_const_fn = matches!(
660+
// Ideally, we'd stop here and reject the rest.
661+
// But for backward compatibility, we have to accept some promotion in const/static
662+
// initializers. Inline consts are explicitly excluded, they are more recent so we have no
663+
// backwards compatibility reason to allow more promotion inside of them.
664+
let promote_all_fn = matches!(
600665
self.const_kind,
601666
Some(hir::ConstContext::Static(_) | hir::ConstContext::Const { inline: false })
602667
);
603-
if !promote_all_const_fn {
604-
if let ty::FnDef(def_id, _) = *fn_ty.kind() {
605-
// Never promote runtime `const fn` calls of
606-
// functions without `#[rustc_promotable]`.
607-
if !self.tcx.is_promotable_const_fn(def_id) {
608-
return Err(Unpromotable);
609-
}
610-
}
668+
if !promote_all_fn {
669+
return Err(Unpromotable);
611670
}
612-
671+
// Make sure the callee is a `const fn`.
613672
let is_const_fn = match *fn_ty.kind() {
614673
ty::FnDef(def_id, _) => self.tcx.is_const_fn_raw(def_id),
615674
_ => false,
616675
};
617676
if !is_const_fn {
618677
return Err(Unpromotable);
619678
}
620-
621-
self.validate_operand(callee)?;
622-
for arg in args {
623-
self.validate_operand(&arg.node)?;
679+
// The problem is, this may promote calls to functions that panic.
680+
// We don't want to introduce compilation errors if there's a panic in a call in dead code.
681+
// So we ensure that this is not dead code.
682+
if !self.is_promotion_safe_block(block) {
683+
return Err(Unpromotable);
624684
}
625-
685+
// This passed all checks, so let's accept.
626686
Ok(())
627687
}
628688
}
@@ -633,7 +693,7 @@ fn validate_candidates(
633693
temps: &mut IndexSlice<Local, TempState>,
634694
candidates: &[Candidate],
635695
) -> Vec<Candidate> {
636-
let mut validator = Validator { ccx, temps };
696+
let mut validator = Validator { ccx, temps, promotion_safe_blocks: None };
637697

638698
candidates
639699
.iter()

‎tests/ui/consts/const-eval/promoted_errors.noopt.stderr

Lines changed: 0 additions & 44 deletions
This file was deleted.

‎tests/ui/consts/const-eval/promoted_errors.opt.stderr

Lines changed: 0 additions & 44 deletions
This file was deleted.

‎tests/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr

Lines changed: 0 additions & 44 deletions
This file was deleted.

‎tests/ui/consts/const-eval/promoted_errors.rs

Lines changed: 0 additions & 52 deletions
This file was deleted.

‎tests/ui/consts/promote-not.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,15 @@ const TEST_DROP_NOT_PROMOTE: &String = {
5151
};
5252

5353

54+
// We do not promote function calls in `const` initializers in dead code.
55+
const fn mk_panic() -> u32 { panic!() }
56+
const fn mk_false() -> bool { false }
57+
const Y: () = {
58+
if mk_false() {
59+
let _x: &'static u32 = &mk_panic(); //~ ERROR temporary value dropped while borrowed
60+
}
61+
};
62+
5463
fn main() {
5564
// We must not promote things with interior mutability. Not even if we "project it away".
5665
let _val: &'static _ = &(Cell::new(1), 2).0; //~ ERROR temporary value dropped while borrowed

‎tests/ui/consts/promote-not.stderr

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,16 @@ LL | let x = &String::new();
4747
LL | };
4848
| - value is dropped here
4949

50+
error[E0716]: temporary value dropped while borrowed
51+
--> $DIR/promote-not.rs:59:33
52+
|
53+
LL | let _x: &'static u32 = &mk_panic();
54+
| ------------ ^^^^^^^^^^ creates a temporary value which is freed while still in use
55+
| |
56+
| type annotation requires that borrow lasts for `'static`
57+
LL | }
58+
| - temporary value is freed at the end of this statement
59+
5060
error[E0716]: temporary value dropped while borrowed
5161
--> $DIR/promote-not.rs:21:32
5262
|
@@ -68,7 +78,7 @@ LL | }
6878
| - temporary value is freed at the end of this statement
6979

7080
error[E0716]: temporary value dropped while borrowed
71-
--> $DIR/promote-not.rs:56:29
81+
--> $DIR/promote-not.rs:65:29
7282
|
7383
LL | let _val: &'static _ = &(Cell::new(1), 2).0;
7484
| ---------- ^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -79,7 +89,7 @@ LL | }
7989
| - temporary value is freed at the end of this statement
8090

8191
error[E0716]: temporary value dropped while borrowed
82-
--> $DIR/promote-not.rs:57:29
92+
--> $DIR/promote-not.rs:66:29
8393
|
8494
LL | let _val: &'static _ = &(Cell::new(1), 2).1;
8595
| ---------- ^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -90,7 +100,7 @@ LL | }
90100
| - temporary value is freed at the end of this statement
91101

92102
error[E0716]: temporary value dropped while borrowed
93-
--> $DIR/promote-not.rs:60:29
103+
--> $DIR/promote-not.rs:69:29
94104
|
95105
LL | let _val: &'static _ = &(1/0);
96106
| ---------- ^^^^^ creates a temporary value which is freed while still in use
@@ -101,7 +111,7 @@ LL | }
101111
| - temporary value is freed at the end of this statement
102112

103113
error[E0716]: temporary value dropped while borrowed
104-
--> $DIR/promote-not.rs:61:29
114+
--> $DIR/promote-not.rs:70:29
105115
|
106116
LL | let _val: &'static _ = &(1/(1-1));
107117
| ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -112,7 +122,7 @@ LL | }
112122
| - temporary value is freed at the end of this statement
113123

114124
error[E0716]: temporary value dropped while borrowed
115-
--> $DIR/promote-not.rs:62:29
125+
--> $DIR/promote-not.rs:71:29
116126
|
117127
LL | let _val: &'static _ = &((1+1)/(1-1));
118128
| ---------- ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -123,7 +133,7 @@ LL | }
123133
| - temporary value is freed at the end of this statement
124134

125135
error[E0716]: temporary value dropped while borrowed
126-
--> $DIR/promote-not.rs:63:29
136+
--> $DIR/promote-not.rs:72:29
127137
|
128138
LL | let _val: &'static _ = &(i32::MIN/-1);
129139
| ---------- ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -134,7 +144,7 @@ LL | }
134144
| - temporary value is freed at the end of this statement
135145

136146
error[E0716]: temporary value dropped while borrowed
137-
--> $DIR/promote-not.rs:64:29
147+
--> $DIR/promote-not.rs:73:29
138148
|
139149
LL | let _val: &'static _ = &(i32::MIN/(0-1));
140150
| ---------- ^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -145,7 +155,7 @@ LL | }
145155
| - temporary value is freed at the end of this statement
146156

147157
error[E0716]: temporary value dropped while borrowed
148-
--> $DIR/promote-not.rs:65:29
158+
--> $DIR/promote-not.rs:74:29
149159
|
150160
LL | let _val: &'static _ = &(-128i8/-1);
151161
| ---------- ^^^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -156,7 +166,7 @@ LL | }
156166
| - temporary value is freed at the end of this statement
157167

158168
error[E0716]: temporary value dropped while borrowed
159-
--> $DIR/promote-not.rs:66:29
169+
--> $DIR/promote-not.rs:75:29
160170
|
161171
LL | let _val: &'static _ = &(1%0);
162172
| ---------- ^^^^^ creates a temporary value which is freed while still in use
@@ -167,7 +177,7 @@ LL | }
167177
| - temporary value is freed at the end of this statement
168178

169179
error[E0716]: temporary value dropped while borrowed
170-
--> $DIR/promote-not.rs:67:29
180+
--> $DIR/promote-not.rs:76:29
171181
|
172182
LL | let _val: &'static _ = &(1%(1-1));
173183
| ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -178,7 +188,7 @@ LL | }
178188
| - temporary value is freed at the end of this statement
179189

180190
error[E0716]: temporary value dropped while borrowed
181-
--> $DIR/promote-not.rs:68:29
191+
--> $DIR/promote-not.rs:77:29
182192
|
183193
LL | let _val: &'static _ = &([1,2,3][4]+1);
184194
| ---------- ^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -189,7 +199,7 @@ LL | }
189199
| - temporary value is freed at the end of this statement
190200

191201
error[E0716]: temporary value dropped while borrowed
192-
--> $DIR/promote-not.rs:72:29
202+
--> $DIR/promote-not.rs:81:29
193203
|
194204
LL | let _val: &'static _ = &TEST_DROP;
195205
| ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -200,7 +210,7 @@ LL | }
200210
| - temporary value is freed at the end of this statement
201211

202212
error[E0716]: temporary value dropped while borrowed
203-
--> $DIR/promote-not.rs:74:29
213+
--> $DIR/promote-not.rs:83:29
204214
|
205215
LL | let _val: &'static _ = &&TEST_DROP;
206216
| ---------- ^^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -211,7 +221,7 @@ LL | }
211221
| - temporary value is freed at the end of this statement
212222

213223
error[E0716]: temporary value dropped while borrowed
214-
--> $DIR/promote-not.rs:74:30
224+
--> $DIR/promote-not.rs:83:30
215225
|
216226
LL | let _val: &'static _ = &&TEST_DROP;
217227
| ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -222,7 +232,7 @@ LL | }
222232
| - temporary value is freed at the end of this statement
223233

224234
error[E0716]: temporary value dropped while borrowed
225-
--> $DIR/promote-not.rs:77:29
235+
--> $DIR/promote-not.rs:86:29
226236
|
227237
LL | let _val: &'static _ = &(&TEST_DROP,);
228238
| ---------- ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -233,7 +243,7 @@ LL | }
233243
| - temporary value is freed at the end of this statement
234244

235245
error[E0716]: temporary value dropped while borrowed
236-
--> $DIR/promote-not.rs:77:31
246+
--> $DIR/promote-not.rs:86:31
237247
|
238248
LL | let _val: &'static _ = &(&TEST_DROP,);
239249
| ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -244,7 +254,7 @@ LL | }
244254
| - temporary value is freed at the end of this statement
245255

246256
error[E0716]: temporary value dropped while borrowed
247-
--> $DIR/promote-not.rs:80:29
257+
--> $DIR/promote-not.rs:89:29
248258
|
249259
LL | let _val: &'static _ = &[&TEST_DROP; 1];
250260
| ---------- ^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -255,7 +265,7 @@ LL | }
255265
| - temporary value is freed at the end of this statement
256266

257267
error[E0716]: temporary value dropped while borrowed
258-
--> $DIR/promote-not.rs:80:31
268+
--> $DIR/promote-not.rs:89:31
259269
|
260270
LL | let _val: &'static _ = &[&TEST_DROP; 1];
261271
| ---------- ^^^^^^^^^ - temporary value is freed at the end of this statement
@@ -264,7 +274,7 @@ LL | let _val: &'static _ = &[&TEST_DROP; 1];
264274
| type annotation requires that borrow lasts for `'static`
265275

266276
error[E0716]: temporary value dropped while borrowed
267-
--> $DIR/promote-not.rs:89:26
277+
--> $DIR/promote-not.rs:98:26
268278
|
269279
LL | let x: &'static _ = &UnionWithCell { f1: 0 };
270280
| ---------- ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -274,7 +284,7 @@ LL |
274284
LL | }
275285
| - temporary value is freed at the end of this statement
276286

277-
error: aborting due to 26 previous errors
287+
error: aborting due to 27 previous errors
278288

279289
Some errors have detailed explanations: E0493, E0716.
280290
For more information about an error, try `rustc --explain E0493`.

‎tests/ui/consts/promotion.rs

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,30 @@
55

66
//@ build-pass
77

8+
#![allow(arithmetic_overflow)]
9+
10+
use std::mem;
11+
812
const fn assert_static<T>(_: &'static T) {}
913

10-
#[allow(unconditional_panic)]
11-
const fn fail() -> i32 {
12-
1/0
13-
}
14-
const C: i32 = {
15-
// Promoted that fails to evaluate in dead code -- this must work
16-
// (for backwards compatibility reasons).
17-
if false {
18-
assert_static(&fail());
19-
}
14+
// Function calls in const on the "main path" (not inside conditionals)
15+
// do get promoted.
16+
const fn make_thing() -> i32 {
2017
42
18+
}
19+
const C: () = {
20+
assert_static(&make_thing());
21+
// Make sure this works even when there's other stuff (like function calls) above the relevant
22+
// call in the const initializer.
23+
assert_static(&make_thing());
2124
};
2225

2326
fn main() {
2427
assert_static(&["a", "b", "c"]);
2528
assert_static(&["d", "e", "f"]);
26-
assert_eq!(C, 42);
2729

2830
// make sure that this does not cause trouble despite overflowing
29-
assert_static(&(0-1));
31+
assert_static(&(0u32 - 1));
3032

3133
// div-by-non-0 (and also not MIN/-1) is okay
3234
assert_static(&(1/1));
@@ -36,12 +38,16 @@ fn main() {
3638
assert_static(&(1%1));
3739

3840
// in-bounds array access is okay
39-
assert_static(&([1,2,3][0] + 1));
40-
assert_static(&[[1,2][1]]);
41+
assert_static(&([1, 2, 3][0] + 1));
42+
assert_static(&[[1, 2][1]]);
4143

4244
// Top-level projections are not part of the promoted, so no error here.
4345
if false {
4446
#[allow(unconditional_panic)]
45-
assert_static(&[1,2,3][4]);
47+
assert_static(&[1, 2, 3][4]);
4648
}
49+
50+
// More complicated case involving control flow and a `#[rustc_promotable]` function
51+
let decision = std::hint::black_box(true);
52+
let x: &'static usize = if decision { &mem::size_of::<usize>() } else { &0 };
4753
}

‎tests/ui/rfcs/rfc-1623-static/rfc1623-2.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 {
44
a
55
}
66

7-
// The incorrect case without `for<'a>` is tested for in `rfc1623-2.rs`
7+
// The incorrect case without `for<'a>` is tested for in `rfc1623-3.rs`
88
static NON_ELIDABLE_FN: &for<'a> fn(&'a u8, &'a u8) -> &'a u8 =
99
&(non_elidable as for<'a> fn(&'a u8, &'a u8) -> &'a u8);
1010

@@ -28,6 +28,10 @@ static SOME_STRUCT: &SomeStruct = &SomeStruct {
2828
f: &id,
2929
//~^ ERROR mismatched types
3030
//~| ERROR mismatched types
31+
//~| ERROR mismatched types
32+
//~| ERROR mismatched types
33+
//~| ERROR implementation of `FnOnce` is not general enough
34+
//~| ERROR implementation of `FnOnce` is not general enough
3135
//~| ERROR implementation of `FnOnce` is not general enough
3236
//~| ERROR implementation of `FnOnce` is not general enough
3337
};

‎tests/ui/rfcs/rfc-1623-static/rfc1623-2.stderr

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,46 @@ LL | f: &id,
3535
= note: `fn(&Foo<'2>) -> &Foo<'2> {id::<&Foo<'2>>}` must implement `FnOnce<(&'a Foo<'1>,)>`, for any lifetime `'1`...
3636
= note: ...but it actually implements `FnOnce<(&Foo<'2>,)>`, for some specific lifetime `'2`
3737

38-
error: aborting due to 4 previous errors
38+
error[E0308]: mismatched types
39+
--> $DIR/rfc1623-2.rs:28:8
40+
|
41+
LL | f: &id,
42+
| ^^^ one type is more general than the other
43+
|
44+
= note: expected trait `for<'a, 'b> Fn(&'a Foo<'b>)`
45+
found trait `Fn(&Foo<'_>)`
46+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
47+
48+
error[E0308]: mismatched types
49+
--> $DIR/rfc1623-2.rs:28:8
50+
|
51+
LL | f: &id,
52+
| ^^^ one type is more general than the other
53+
|
54+
= note: expected trait `for<'a, 'b> Fn(&'a Foo<'b>)`
55+
found trait `Fn(&Foo<'_>)`
56+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
57+
58+
error: implementation of `FnOnce` is not general enough
59+
--> $DIR/rfc1623-2.rs:28:8
60+
|
61+
LL | f: &id,
62+
| ^^^ implementation of `FnOnce` is not general enough
63+
|
64+
= note: `fn(&'2 Foo<'_>) -> &'2 Foo<'_> {id::<&'2 Foo<'_>>}` must implement `FnOnce<(&'1 Foo<'b>,)>`, for any lifetime `'1`...
65+
= note: ...but it actually implements `FnOnce<(&'2 Foo<'_>,)>`, for some specific lifetime `'2`
66+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
67+
68+
error: implementation of `FnOnce` is not general enough
69+
--> $DIR/rfc1623-2.rs:28:8
70+
|
71+
LL | f: &id,
72+
| ^^^ implementation of `FnOnce` is not general enough
73+
|
74+
= note: `fn(&Foo<'2>) -> &Foo<'2> {id::<&Foo<'2>>}` must implement `FnOnce<(&'a Foo<'1>,)>`, for any lifetime `'1`...
75+
= note: ...but it actually implements `FnOnce<(&Foo<'2>,)>`, for some specific lifetime `'2`
76+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
77+
78+
error: aborting due to 8 previous errors
3979

4080
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)
Please sign in to comment.