Skip to content

Commit 36a7494

Browse files
committed
Auto merge of #77526 - RalfJung:dont-promote-unions, r=lcnr
stop promoting union field accesses in 'const' Turns out that promotion of union field accesses is the only difference between "promotion in `const`/`static` bodies" and "explicit promotion". So if we can remove this, we have finally achieved what I thought to already be the case -- that the bodies of `const`/`static` initializers behave the same as explicit promotion contexts. The reason we do not want to promote union field accesses is that they can introduce UB, i.e., they can go wrong. We want to [minimize the ways promoteds can fail to evaluate](rust-lang/const-eval#53). Also this change makes things more consistent overall, removing a special case that was added without much consideration (as far as I can tell). Cc `@rust-lang/wg-const-eval`
2 parents 7c533c8 + d727f64 commit 36a7494

File tree

3 files changed

+30
-21
lines changed

3 files changed

+30
-21
lines changed

compiler/rustc_mir/src/transform/promote_consts.rs

+14-20
Original file line numberDiff line numberDiff line change
@@ -301,17 +301,6 @@ impl std::ops::Deref for Validator<'a, 'tcx> {
301301
struct Unpromotable;
302302

303303
impl<'tcx> Validator<'_, 'tcx> {
304-
/// Determines if this code could be executed at runtime and thus is subject to codegen.
305-
/// That means even unused constants need to be evaluated.
306-
///
307-
/// `const_kind` should not be used in this file other than through this method!
308-
fn maybe_runtime(&self) -> bool {
309-
match self.const_kind {
310-
None | Some(hir::ConstContext::ConstFn) => true,
311-
Some(hir::ConstContext::Static(_) | hir::ConstContext::Const) => false,
312-
}
313-
}
314-
315304
fn validate_candidate(&self, candidate: Candidate) -> Result<(), Unpromotable> {
316305
match candidate {
317306
Candidate::Ref(loc) => {
@@ -562,14 +551,12 @@ impl<'tcx> Validator<'_, 'tcx> {
562551
}
563552

564553
ProjectionElem::Field(..) => {
565-
if self.maybe_runtime() {
566-
let base_ty =
567-
Place::ty_from(place.local, proj_base, self.body, self.tcx).ty;
568-
if let Some(def) = base_ty.ty_adt_def() {
569-
// No promotion of union field accesses.
570-
if def.is_union() {
571-
return Err(Unpromotable);
572-
}
554+
let base_ty =
555+
Place::ty_from(place.local, proj_base, self.body, self.tcx).ty;
556+
if let Some(def) = base_ty.ty_adt_def() {
557+
// No promotion of union field accesses.
558+
if def.is_union() {
559+
return Err(Unpromotable);
573560
}
574561
}
575562
}
@@ -751,7 +738,14 @@ impl<'tcx> Validator<'_, 'tcx> {
751738
) -> Result<(), Unpromotable> {
752739
let fn_ty = callee.ty(self.body, self.tcx);
753740

754-
if !self.explicit && self.maybe_runtime() {
741+
// When doing explicit promotion and inside const/static items, we promote all (eligible) function calls.
742+
// Everywhere else, we require `#[rustc_promotable]` on the callee.
743+
let promote_all_const_fn = self.explicit
744+
|| matches!(
745+
self.const_kind,
746+
Some(hir::ConstContext::Static(_) | hir::ConstContext::Const)
747+
);
748+
if !promote_all_const_fn {
755749
if let ty::FnDef(def_id, _) = *fn_ty.kind() {
756750
// Never promote runtime `const fn` calls of
757751
// functions without `#[rustc_promotable]`.

src/test/ui/consts/promote-not.rs

+5
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,9 @@ pub const fn promote_union() {
2727
let _x: &'static i32 = &unsafe { U { x: 0 }.x }; //~ ERROR temporary value dropped while borrowed
2828
}
2929

30+
// We do not promote union field accesses in `const`, either.
31+
const TEST_UNION: () = {
32+
let _x: &'static i32 = &unsafe { U { x: 0 }.x }; //~ ERROR temporary value dropped while borrowed
33+
};
34+
3035
fn main() {}

src/test/ui/consts/promote-not.stderr

+11-1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,16 @@ LL | let _x: &'static i32 = &unsafe { U { x: 0 }.x };
3838
LL | }
3939
| - temporary value is freed at the end of this statement
4040

41-
error: aborting due to 4 previous errors
41+
error[E0716]: temporary value dropped while borrowed
42+
--> $DIR/promote-not.rs:32:29
43+
|
44+
LL | let _x: &'static i32 = &unsafe { U { x: 0 }.x };
45+
| ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
46+
| |
47+
| type annotation requires that borrow lasts for `'static`
48+
LL | };
49+
| - temporary value is freed at the end of this statement
50+
51+
error: aborting due to 5 previous errors
4252

4353
For more information about this error, try `rustc --explain E0716`.

0 commit comments

Comments
 (0)