Auto merge of #70820 - spastorino:replace-fragile-erroneous-const-sys, r=oli-obk

Replace fragile erroneous const sys

Closes #67191

r? @oli-obk
This commit is contained in:
bors 2020-04-24 09:14:47 +00:00
commit 0b958790b3
13 changed files with 133 additions and 82 deletions

View File

@ -1,6 +1,8 @@
use crate::base;
use crate::traits::*;
use rustc_errors::ErrorReported;
use rustc_middle::mir;
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt, TyAndLayout};
use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
use rustc_target::abi::call::{FnAbi, PassMode};
@ -189,6 +191,18 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info();
for const_ in &mir.required_consts {
if let Err(err) = fx.eval_mir_constant(const_) {
match err {
// errored or at least linted
ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted => {}
ErrorHandled::TooGeneric => {
span_bug!(const_.span, "codgen encountered polymorphic constant: {:?}", err)
}
}
}
}
let memory_locals = analyze::non_ssa_locals(&fx);
// Allocate variable and temp allocas

View File

@ -156,6 +156,10 @@ pub struct Body<'tcx> {
/// A span representing this MIR, for error reporting.
pub span: Span,
/// Constants that are required to evaluate successfully for this MIR to be well-formed.
/// We hold in this field all the constants we are not able to evaluate yet.
pub required_consts: Vec<Constant<'tcx>>,
/// The user may be writing e.g. &[(SOME_CELL, 42)][i].1 and this would get promoted, because
/// we'd statically know that no thing with interior mutability will ever be available to the
/// user without some serious unsafe code. Now this means that our promoted is actually
@ -203,6 +207,7 @@ impl<'tcx> Body<'tcx> {
spread_arg: None,
var_debug_info,
span,
required_consts: Vec::new(),
ignore_interior_mut_in_const_validation: false,
control_flow_destroyed,
predecessor_cache: PredecessorCache::new(),
@ -227,6 +232,7 @@ impl<'tcx> Body<'tcx> {
arg_count: 0,
spread_arg: None,
span: DUMMY_SP,
required_consts: Vec::new(),
control_flow_destroyed: Vec::new(),
generator_kind: None,
var_debug_info: Vec::new(),
@ -2395,7 +2401,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
/// this does not necessarily mean that they are "==" in Rust -- in
/// particular one must be wary of `NaN`!
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)]
#[derive(Clone, Copy, PartialEq, RustcEncodable, RustcDecodable, HashStable)]
pub struct Constant<'tcx> {
pub span: Span,

View File

@ -288,6 +288,11 @@ macro_rules! make_mir_visitor {
}
self.visit_span(&$($mutability)? body.span);
for const_ in &$($mutability)? body.required_consts {
let location = START_BLOCK.start_location();
self.visit_constant(const_, location);
}
}
fn super_basic_block_data(&mut self,

View File

@ -830,6 +830,12 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
self.tcx
}
fn visit_body(&mut self, body: &mut Body<'tcx>) {
for (bb, data) in body.basic_blocks_mut().iter_enumerated_mut() {
self.visit_basic_block_data(bb, data);
}
}
fn visit_constant(&mut self, constant: &mut Constant<'tcx>, location: Location) {
trace!("visit_constant: {:?}", constant);
self.super_constant(constant, location);

View File

@ -8,7 +8,7 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir::visit::*;
use rustc_middle::mir::*;
use rustc_middle::ty::subst::{Subst, SubstsRef};
use rustc_middle::ty::{self, Instance, InstanceDef, ParamEnv, Ty, TyCtxt};
use rustc_middle::ty::{self, ConstKind, Instance, InstanceDef, ParamEnv, Ty, TyCtxt};
use rustc_session::config::Sanitizer;
use rustc_target::spec::abi::Abi;
@ -123,6 +123,16 @@ impl Inliner<'tcx> {
continue;
};
// Copy only unevaluated constants from the callee_body into the caller_body.
// Although we are only pushing `ConstKind::Unevaluated` consts to
// `required_consts`, here we may not only have `ConstKind::Unevaluated`
// because we are calling `subst_and_normalize_erasing_regions`.
caller_body.required_consts.extend(
callee_body.required_consts.iter().copied().filter(|&constant| {
matches!(constant.literal.val, ConstKind::Unevaluated(_, _, _))
}),
);
let start = caller_body.basic_blocks().len();
debug!("attempting to inline callsite {:?} - body={:?}", callsite, callee_body);
if !self.inline_call(callsite, caller_body, callee_body) {

View File

@ -1,10 +1,12 @@
use crate::{shim, util};
use required_consts::RequiredConstsVisitor;
use rustc_ast::ast;
use rustc_hir as hir;
use rustc_hir::def_id::{CrateNum, DefId, DefIdSet, LocalDefId, LOCAL_CRATE};
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_index::vec::IndexVec;
use rustc_middle::mir::{Body, ConstQualifs, MirPhase, Promoted};
use rustc_middle::mir::visit::Visitor as _;
use rustc_middle::mir::{traversal, Body, ConstQualifs, MirPhase, Promoted};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::steal::Steal;
use rustc_middle::ty::{InstanceDef, TyCtxt, TypeFoldable};
@ -29,6 +31,7 @@ pub mod no_landing_pads;
pub mod promote_consts;
pub mod qualify_min_const_fn;
pub mod remove_noop_landing_pads;
pub mod required_consts;
pub mod rustc_peek;
pub mod simplify;
pub mod simplify_branches;
@ -237,6 +240,14 @@ fn mir_validated(
let _ = tcx.mir_const_qualif(def_id);
let mut body = tcx.mir_const(def_id).steal();
let mut required_consts = Vec::new();
let mut required_consts_visitor = RequiredConstsVisitor::new(&mut required_consts);
for (bb, bb_data) in traversal::reverse_postorder(&body) {
required_consts_visitor.visit_basic_block_data(bb, bb_data);
}
body.required_consts = required_consts;
let promote_pass = promote_consts::PromoteTemps::default();
run_passes(
tcx,

View File

@ -0,0 +1,23 @@
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::{Constant, Location};
use rustc_middle::ty::ConstKind;
pub struct RequiredConstsVisitor<'a, 'tcx> {
required_consts: &'a mut Vec<Constant<'tcx>>,
}
impl<'a, 'tcx> RequiredConstsVisitor<'a, 'tcx> {
pub fn new(required_consts: &'a mut Vec<Constant<'tcx>>) -> Self {
RequiredConstsVisitor { required_consts }
}
}
impl<'a, 'tcx> Visitor<'tcx> for RequiredConstsVisitor<'a, 'tcx> {
fn visit_constant(&mut self, constant: &Constant<'tcx>, _: Location) {
let const_kind = constant.literal.val;
if let ConstKind::Unevaluated(_, _, _) = const_kind {
self.required_consts.push(*constant);
}
}
}

View File

@ -32,7 +32,7 @@ use rustc_index::bit_set::BitSet;
use rustc_index::vec::{Idx, IndexVec};
use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*;
use rustc_middle::ty::{self, TyCtxt};
use rustc_middle::ty::TyCtxt;
use std::borrow::Cow;
pub struct SimplifyCfg {
@ -400,33 +400,18 @@ impl<'a, 'tcx> Visitor<'tcx> for DeclMarker<'a, 'tcx> {
if location.statement_index != block.statements.len() {
let stmt = &block.statements[location.statement_index];
fn can_skip_constant(c: &ty::Const<'tcx>) -> bool {
// Keep assignments from unevaluated constants around, since the
// evaluation may report errors, even if the use of the constant
// is dead code.
!matches!(c.val, ty::ConstKind::Unevaluated(..))
}
fn can_skip_operand(o: &Operand<'_>) -> bool {
match o {
Operand::Copy(_) | Operand::Move(_) => true,
Operand::Constant(c) => can_skip_constant(c.literal),
}
}
if let StatementKind::Assign(box (dest, rvalue)) = &stmt.kind {
if !dest.is_indirect() && dest.local == *local {
let can_skip = match rvalue {
Rvalue::Use(op) => can_skip_operand(op),
Rvalue::Discriminant(_) => true,
Rvalue::BinaryOp(_, l, r) | Rvalue::CheckedBinaryOp(_, l, r) => {
can_skip_operand(l) && can_skip_operand(r)
}
Rvalue::Repeat(op, c) => can_skip_operand(op) && can_skip_constant(c),
Rvalue::AddressOf(_, _) => true,
Rvalue::Len(_) => true,
Rvalue::UnaryOp(_, op) => can_skip_operand(op),
Rvalue::Aggregate(_, operands) => operands.iter().all(can_skip_operand),
Rvalue::Use(_)
| Rvalue::Discriminant(_)
| Rvalue::BinaryOp(_, _, _)
| Rvalue::CheckedBinaryOp(_, _, _)
| Rvalue::Repeat(_, _)
| Rvalue::AddressOf(_, _)
| Rvalue::Len(_)
| Rvalue::UnaryOp(_, _)
| Rvalue::Aggregate(_, _) => true,
_ => false,
};

View File

@ -30,41 +30,41 @@ fn main() -> () {
}
alloc0 (static: FOO, size: 8, align: 4) {
╾alloc25+0╼ 03 00 00 00 │ ╾──╼....
╾alloc21+0╼ 03 00 00 00 │ ╾──╼....
}
alloc25 (size: 48, align: 4) {
0x00 │ 00 00 00 00 __ __ __ __ ╾alloc10+0╼ 00 00 00 00 │ ....░░░░╾──╼....
0x10 │ 00 00 00 00 __ __ __ __ ╾alloc15+0╼ 02 00 00 00 │ ....░░░░╾──╼....
0x20 │ 01 00 00 00 2a 00 00 00 ╾alloc23+0╼ 03 00 00 00 │ ....*...╾──╼....
alloc21 (size: 48, align: 4) {
0x00 │ 00 00 00 00 __ __ __ __ ╾alloc4+0─╼ 00 00 00 00 │ ....░░░░╾──╼....
0x10 │ 00 00 00 00 __ __ __ __ ╾alloc9+0─╼ 02 00 00 00 │ ....░░░░╾──╼....
0x20 │ 01 00 00 00 2a 00 00 00 ╾alloc19+0╼ 03 00 00 00 │ ....*...╾──╼....
}
alloc10 (size: 0, align: 4) {}
alloc4 (size: 0, align: 4) {}
alloc15 (size: 8, align: 4) {
╾alloc13+0╼ ╾alloc14+0╼ │ ╾──╼╾──╼
alloc9 (size: 8, align: 4) {
╾alloc7+0─╼ ╾alloc8+0─╼ │ ╾──╼╾──╼
}
alloc13 (size: 1, align: 1) {
alloc7 (size: 1, align: 1) {
05 │ .
}
alloc14 (size: 1, align: 1) {
alloc8 (size: 1, align: 1) {
06 │ .
}
alloc23 (size: 12, align: 4) {
╾alloc19+3╼ ╾alloc20+0╼ ╾alloc22+2╼ │ ╾──╼╾──╼╾──╼
alloc19 (size: 12, align: 4) {
╾alloc15+3╼ ╾alloc16+0╼ ╾alloc18+2╼ │ ╾──╼╾──╼╾──╼
}
alloc19 (size: 4, align: 1) {
alloc15 (size: 4, align: 1) {
2a 45 15 6f │ *E.o
}
alloc20 (size: 1, align: 1) {
alloc16 (size: 1, align: 1) {
2a │ *
}
alloc22 (size: 4, align: 1) {
alloc18 (size: 4, align: 1) {
2a 45 15 6f │ *E.o
}

View File

@ -30,44 +30,44 @@ fn main() -> () {
}
alloc0 (static: FOO, size: 16, align: 8) {
╾──────alloc25+0──────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
╾──────alloc21+0──────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
}
alloc25 (size: 72, align: 8) {
0x00 │ 00 00 00 00 __ __ __ __ ╾──────alloc10+0──────╼ │ ....░░░░╾──────╼
alloc21 (size: 72, align: 8) {
0x00 │ 00 00 00 00 __ __ __ __ ╾──────alloc4+0───────╼ │ ....░░░░╾──────╼
0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ │ ............░░░░
0x20 │ ╾──────alloc15+0──────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........
0x30 │ 01 00 00 00 2a 00 00 00 ╾──────alloc23+0──────╼ │ ....*...╾──────╼
0x20 │ ╾──────alloc9+0───────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........
0x30 │ 01 00 00 00 2a 00 00 00 ╾──────alloc19+0──────╼ │ ....*...╾──────╼
0x40 │ 03 00 00 00 00 00 00 00 │ ........
}
alloc10 (size: 0, align: 8) {}
alloc4 (size: 0, align: 8) {}
alloc15 (size: 16, align: 8) {
╾──────alloc13+0──────╼ ╾──────alloc14+0──────╼ │ ╾──────╼╾──────╼
alloc9 (size: 16, align: 8) {
╾──────alloc7+0───────╼ ╾──────alloc8+0───────╼ │ ╾──────╼╾──────╼
}
alloc13 (size: 1, align: 1) {
alloc7 (size: 1, align: 1) {
05 │ .
}
alloc14 (size: 1, align: 1) {
alloc8 (size: 1, align: 1) {
06 │ .
}
alloc23 (size: 24, align: 8) {
0x00 │ ╾──────alloc19+3──────╼ ╾──────alloc20+0──────╼ │ ╾──────╼╾──────╼
0x10 │ ╾──────alloc22+2──────╼ │ ╾──────╼
alloc19 (size: 24, align: 8) {
0x00 │ ╾──────alloc15+3──────╼ ╾──────alloc16+0──────╼ │ ╾──────╼╾──────╼
0x10 │ ╾──────alloc18+2──────╼ │ ╾──────╼
}
alloc19 (size: 4, align: 1) {
alloc15 (size: 4, align: 1) {
2a 45 15 6f │ *E.o
}
alloc20 (size: 1, align: 1) {
alloc16 (size: 1, align: 1) {
2a │ *
}
alloc22 (size: 4, align: 1) {
alloc18 (size: 4, align: 1) {
2a 45 15 6f │ *E.o
}

View File

@ -1,5 +1,6 @@
// Regression test for #66975 - ensure that we don't keep unevaluated
// `!`-typed constants until codegen.
// This was originally a regression test for #66975 - ensure that we do not generate never typed
// consts in codegen. We also have tests for this that catches the error, see
// src/test/ui/consts/const-eval/index-out-of-bounds-never-type.rs.
// Force generation of optimized mir for functions that do not reach codegen.
// compile-flags: --emit mir,link

View File

@ -0,0 +1,11 @@
// MIR for `no_codegen` after PreCodegen
fn no_codegen() -> () {
let mut _0: (); // return place in scope 0 at $DIR/remove-never-const.rs:19:20: 19:20
scope 1 {
}
bb0: {
unreachable; // bb0[0]: scope 0 at $DIR/remove-never-const.rs:20:13: 20:33
}
}

View File

@ -1,21 +0,0 @@
// MIR for `no_codegen` after PreCodegen
fn no_codegen() -> () {
let mut _0: (); // return place in scope 0 at $DIR/retain-never-const.rs:18:20: 18:20
let mut _1: !; // in scope 0 at $DIR/retain-never-const.rs:19:13: 19:33
scope 1 {
}
bb0: {
StorageLive(_1); // bb0[0]: scope 0 at $DIR/retain-never-const.rs:19:13: 19:33
_1 = const PrintName::<T>::VOID; // bb0[1]: scope 0 at $DIR/retain-never-const.rs:19:13: 19:33
// ty::Const
// + ty: !
// + val: Unevaluated(DefId(0:9 ~ retain_never_const[317d]::{{impl}}[0]::VOID[0]), [T], None)
// mir::Constant
// + span: $DIR/retain-never-const.rs:19:13: 19:33
// + user_ty: UserType(0)
// + literal: Const { ty: !, val: Unevaluated(DefId(0:9 ~ retain_never_const[317d]::{{impl}}[0]::VOID[0]), [T], None) }
unreachable; // bb0[2]: scope 0 at $DIR/retain-never-const.rs:19:13: 19:33
}
}