stop promoting union field accesses in 'const'

This commit is contained in:
Ralf Jung 2020-10-04 15:25:26 +02:00
parent 0d37dca25a
commit d727f642b9
3 changed files with 30 additions and 21 deletions

View file

@ -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) => {
@ -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);
}
}
}
@ -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]`.

View file

@ -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() {}

View file

@ -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`.