Skip to content

Commit

Permalink
stop promoting union field accesses in 'const'
Browse files Browse the repository at this point in the history
  • Loading branch information
RalfJung committed Oct 4, 2020
1 parent 0d37dca commit d727f64
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 21 deletions.
34 changes: 14 additions & 20 deletions compiler/rustc_mir/src/transform/promote_consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,17 +294,6 @@ impl std::ops::Deref for Validator<'a, 'tcx> {
struct Unpromotable;

impl<'tcx> Validator<'_, 'tcx> {
/// Determines if this code could be executed at runtime and thus is subject to codegen.
/// That means even unused constants need to be evaluated.
///
/// `const_kind` should not be used in this file other than through this method!
fn maybe_runtime(&self) -> bool {
match self.const_kind {
None | Some(hir::ConstContext::ConstFn) => true,
Some(hir::ConstContext::Static(_) | hir::ConstContext::Const) => false,
}
}

fn validate_candidate(&self, candidate: Candidate) -> Result<(), Unpromotable> {
match candidate {
Candidate::Ref(loc) => {
Expand Down Expand Up @@ -555,14 +544,12 @@ impl<'tcx> Validator<'_, 'tcx> {
}

ProjectionElem::Field(..) => {
if self.maybe_runtime() {
let base_ty =
Place::ty_from(place.local, proj_base, self.body, self.tcx).ty;
if let Some(def) = base_ty.ty_adt_def() {
// No promotion of union field accesses.
if def.is_union() {
return Err(Unpromotable);
}
let base_ty =
Place::ty_from(place.local, proj_base, self.body, self.tcx).ty;
if let Some(def) = base_ty.ty_adt_def() {
// No promotion of union field accesses.
if def.is_union() {
return Err(Unpromotable);
}
}
}
Expand Down Expand Up @@ -744,7 +731,14 @@ impl<'tcx> Validator<'_, 'tcx> {
) -> Result<(), Unpromotable> {
let fn_ty = callee.ty(self.body, self.tcx);

if !self.explicit && self.maybe_runtime() {
// When doing explicit promotion and inside const/static items, we promote all (eligible) function calls.
// Everywhere else, we require `#[rustc_promotable]` on the callee.
let promote_all_const_fn = self.explicit
|| matches!(
self.const_kind,
Some(hir::ConstContext::Static(_) | hir::ConstContext::Const)
);
if !promote_all_const_fn {
if let ty::FnDef(def_id, _) = *fn_ty.kind() {
// Never promote runtime `const fn` calls of
// functions without `#[rustc_promotable]`.
Expand Down
5 changes: 5 additions & 0 deletions src/test/ui/consts/promote-not.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,9 @@ pub const fn promote_union() {
let _x: &'static i32 = &unsafe { U { x: 0 }.x }; //~ ERROR temporary value dropped while borrowed
}

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

fn main() {}
12 changes: 11 additions & 1 deletion src/test/ui/consts/promote-not.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ LL | let _x: &'static i32 = &unsafe { U { x: 0 }.x };
LL | }
| - temporary value is freed at the end of this statement

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

error: aborting due to 5 previous errors

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

0 comments on commit d727f64

Please sign in to comment.