Skip to content

Commit 21b0e12

Browse files
authored
Rollup merge of #145277 - dingxiangfei2009:fold-coercion-into-const, r=nnethercote
Do not materialise X in [X; 0] when X is unsizing a const Fix #143671 It turns out that MIR builder materialise `X` in `[X; 0]` into a temporary local when `X` is unsizing a `const`. This led to a confusing call to destructor of `X` when such a destructor is declared. [Playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2024&gist=8dfc933af89efeb89c881bc77498ba63) This patch may miss out other cases that we should avoid materialisation in case of `[X; 0]`. Suggestions to include is most welcome!
2 parents 2acd80c + b77de83 commit 21b0e12

File tree

2 files changed

+69
-1
lines changed

2 files changed

+69
-1
lines changed

compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use rustc_middle::middle::region;
88
use rustc_middle::mir::interpret::Scalar;
99
use rustc_middle::mir::*;
1010
use rustc_middle::thir::*;
11+
use rustc_middle::ty::adjustment::PointerCoercion;
1112
use rustc_middle::ty::cast::{CastTy, mir_cast_kind};
1213
use rustc_middle::ty::util::IntTypeExt;
1314
use rustc_middle::ty::{self, Ty, UpvarArgs};
@@ -656,6 +657,27 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
656657
block.and(rvalue)
657658
}
658659

660+
/// Recursively inspect a THIR expression and probe through unsizing
661+
/// operations that can be const-folded today.
662+
fn check_constness(&self, mut kind: &'a ExprKind<'tcx>) -> bool {
663+
loop {
664+
debug!(?kind, "check_constness");
665+
match kind {
666+
&ExprKind::ValueTypeAscription { source: eid, user_ty: _, user_ty_span: _ }
667+
| &ExprKind::Use { source: eid }
668+
| &ExprKind::PointerCoercion {
669+
cast: PointerCoercion::Unsize,
670+
source: eid,
671+
is_from_as_cast: _,
672+
}
673+
| &ExprKind::Scope { region_scope: _, lint_level: _, value: eid } => {
674+
kind = &self.thir[eid].kind
675+
}
676+
_ => return matches!(Category::of(&kind), Some(Category::Constant)),
677+
}
678+
}
679+
}
680+
659681
fn build_zero_repeat(
660682
&mut self,
661683
mut block: BasicBlock,
@@ -666,7 +688,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
666688
let this = self;
667689
let value_expr = &this.thir[value];
668690
let elem_ty = value_expr.ty;
669-
if let Some(Category::Constant) = Category::of(&value_expr.kind) {
691+
if this.check_constness(&value_expr.kind) {
670692
// Repeating a const does nothing
671693
} else {
672694
// For a non-const, we may need to generate an appropriate `Drop`
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//@ run-pass
2+
3+
#![feature(unsize)]
4+
#![feature(coerce_unsized)]
5+
6+
use std::fmt::Display;
7+
use std::marker::Unsize;
8+
use std::ops::CoerceUnsized;
9+
use std::rc::Weak;
10+
11+
#[repr(transparent)]
12+
struct X<'a, T: ?Sized> {
13+
f: &'a T,
14+
}
15+
16+
impl<'a, T: ?Sized> Drop for X<'a, T> {
17+
fn drop(&mut self) {
18+
panic!()
19+
}
20+
}
21+
22+
impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<X<'a, U>> for X<'a, T> where
23+
&'a T: CoerceUnsized<&'a U>
24+
{
25+
}
26+
27+
const Y: X<'static, i32> = X { f: &0 };
28+
29+
fn main() {
30+
let _: [X<'static, dyn Display>; 0] = [Y; 0];
31+
coercion_on_weak_in_const();
32+
coercion_on_weak_as_cast();
33+
}
34+
35+
fn coercion_on_weak_in_const() {
36+
const X: Weak<i32> = Weak::new();
37+
const Y: [Weak<dyn Send>; 0] = [X; 0];
38+
let _ = Y;
39+
}
40+
41+
fn coercion_on_weak_as_cast() {
42+
const Y: X<'static, i32> = X { f: &0 };
43+
// What happens in the following code is that
44+
// a constant is explicitly coerced into
45+
let _a: [X<'static, dyn Display>; 0] = [Y as X<'static, dyn Display>; 0];
46+
}

0 commit comments

Comments
 (0)