提交 0b958790 编写于 作者: B bors

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

Replace fragile erroneous const sys

Closes #67191

r? @oli-obk
use crate::base; use crate::base;
use crate::traits::*; use crate::traits::*;
use rustc_errors::ErrorReported;
use rustc_middle::mir; use rustc_middle::mir;
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt, TyAndLayout}; use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt, TyAndLayout};
use rustc_middle::ty::{self, Instance, Ty, TypeFoldable}; use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
use rustc_target::abi::call::{FnAbi, PassMode}; use rustc_target::abi::call::{FnAbi, PassMode};
...@@ -189,6 +191,18 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( ...@@ -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(); 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); let memory_locals = analyze::non_ssa_locals(&fx);
// Allocate variable and temp allocas // Allocate variable and temp allocas
......
...@@ -156,6 +156,10 @@ pub struct Body<'tcx> { ...@@ -156,6 +156,10 @@ pub struct Body<'tcx> {
/// A span representing this MIR, for error reporting. /// A span representing this MIR, for error reporting.
pub span: Span, 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 /// 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 /// 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 /// user without some serious unsafe code. Now this means that our promoted is actually
...@@ -203,6 +207,7 @@ pub fn new( ...@@ -203,6 +207,7 @@ pub fn new(
spread_arg: None, spread_arg: None,
var_debug_info, var_debug_info,
span, span,
required_consts: Vec::new(),
ignore_interior_mut_in_const_validation: false, ignore_interior_mut_in_const_validation: false,
control_flow_destroyed, control_flow_destroyed,
predecessor_cache: PredecessorCache::new(), predecessor_cache: PredecessorCache::new(),
...@@ -227,6 +232,7 @@ pub fn new_cfg_only(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>) -> ...@@ -227,6 +232,7 @@ pub fn new_cfg_only(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>) ->
arg_count: 0, arg_count: 0,
spread_arg: None, spread_arg: None,
span: DUMMY_SP, span: DUMMY_SP,
required_consts: Vec::new(),
control_flow_destroyed: Vec::new(), control_flow_destroyed: Vec::new(),
generator_kind: None, generator_kind: None,
var_debug_info: Vec::new(), var_debug_info: Vec::new(),
...@@ -2395,7 +2401,7 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { ...@@ -2395,7 +2401,7 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
/// this does not necessarily mean that they are "==" in Rust -- in /// this does not necessarily mean that they are "==" in Rust -- in
/// particular one must be wary of `NaN`! /// 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 struct Constant<'tcx> {
pub span: Span, pub span: Span,
......
...@@ -288,6 +288,11 @@ fn super_body( ...@@ -288,6 +288,11 @@ fn super_body(
} }
self.visit_span(&$($mutability)? body.span); 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, fn super_basic_block_data(&mut self,
......
...@@ -830,6 +830,12 @@ fn tcx(&self) -> TyCtxt<'tcx> { ...@@ -830,6 +830,12 @@ fn tcx(&self) -> TyCtxt<'tcx> {
self.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) { fn visit_constant(&mut self, constant: &mut Constant<'tcx>, location: Location) {
trace!("visit_constant: {:?}", constant); trace!("visit_constant: {:?}", constant);
self.super_constant(constant, location); self.super_constant(constant, location);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
use rustc_middle::mir::visit::*; use rustc_middle::mir::visit::*;
use rustc_middle::mir::*; use rustc_middle::mir::*;
use rustc_middle::ty::subst::{Subst, SubstsRef}; 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_session::config::Sanitizer;
use rustc_target::spec::abi::Abi; use rustc_target::spec::abi::Abi;
...@@ -123,6 +123,16 @@ fn run_pass(&self, caller_body: &mut Body<'tcx>) { ...@@ -123,6 +123,16 @@ fn run_pass(&self, caller_body: &mut Body<'tcx>) {
continue; 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(); let start = caller_body.basic_blocks().len();
debug!("attempting to inline callsite {:?} - body={:?}", callsite, callee_body); debug!("attempting to inline callsite {:?} - body={:?}", callsite, callee_body);
if !self.inline_call(callsite, caller_body, callee_body) { if !self.inline_call(callsite, caller_body, callee_body) {
......
use crate::{shim, util}; use crate::{shim, util};
use required_consts::RequiredConstsVisitor;
use rustc_ast::ast; use rustc_ast::ast;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def_id::{CrateNum, DefId, DefIdSet, LocalDefId, LOCAL_CRATE}; use rustc_hir::def_id::{CrateNum, DefId, DefIdSet, LocalDefId, LOCAL_CRATE};
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_index::vec::IndexVec; 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::query::Providers;
use rustc_middle::ty::steal::Steal; use rustc_middle::ty::steal::Steal;
use rustc_middle::ty::{InstanceDef, TyCtxt, TypeFoldable}; use rustc_middle::ty::{InstanceDef, TyCtxt, TypeFoldable};
...@@ -29,6 +31,7 @@ ...@@ -29,6 +31,7 @@
pub mod promote_consts; pub mod promote_consts;
pub mod qualify_min_const_fn; pub mod qualify_min_const_fn;
pub mod remove_noop_landing_pads; pub mod remove_noop_landing_pads;
pub mod required_consts;
pub mod rustc_peek; pub mod rustc_peek;
pub mod simplify; pub mod simplify;
pub mod simplify_branches; pub mod simplify_branches;
...@@ -237,6 +240,14 @@ fn mir_validated( ...@@ -237,6 +240,14 @@ fn mir_validated(
let _ = tcx.mir_const_qualif(def_id); let _ = tcx.mir_const_qualif(def_id);
let mut body = tcx.mir_const(def_id).steal(); 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(); let promote_pass = promote_consts::PromoteTemps::default();
run_passes( run_passes(
tcx, tcx,
......
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);
}
}
}
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
use rustc_index::vec::{Idx, IndexVec}; use rustc_index::vec::{Idx, IndexVec};
use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*; use rustc_middle::mir::*;
use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::ty::TyCtxt;
use std::borrow::Cow; use std::borrow::Cow;
pub struct SimplifyCfg { pub struct SimplifyCfg {
...@@ -400,33 +400,18 @@ fn visit_local(&mut self, local: &Local, ctx: PlaceContext, location: Location) ...@@ -400,33 +400,18 @@ fn visit_local(&mut self, local: &Local, ctx: PlaceContext, location: Location)
if location.statement_index != block.statements.len() { if location.statement_index != block.statements.len() {
let stmt = &block.statements[location.statement_index]; 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 let StatementKind::Assign(box (dest, rvalue)) = &stmt.kind {
if !dest.is_indirect() && dest.local == *local { if !dest.is_indirect() && dest.local == *local {
let can_skip = match rvalue { let can_skip = match rvalue {
Rvalue::Use(op) => can_skip_operand(op), Rvalue::Use(_)
Rvalue::Discriminant(_) => true, | Rvalue::Discriminant(_)
Rvalue::BinaryOp(_, l, r) | Rvalue::CheckedBinaryOp(_, l, r) => { | Rvalue::BinaryOp(_, _, _)
can_skip_operand(l) && can_skip_operand(r) | Rvalue::CheckedBinaryOp(_, _, _)
} | Rvalue::Repeat(_, _)
Rvalue::Repeat(op, c) => can_skip_operand(op) && can_skip_constant(c), | Rvalue::AddressOf(_, _)
Rvalue::AddressOf(_, _) => true, | Rvalue::Len(_)
Rvalue::Len(_) => true, | Rvalue::UnaryOp(_, _)
Rvalue::UnaryOp(_, op) => can_skip_operand(op), | Rvalue::Aggregate(_, _) => true,
Rvalue::Aggregate(_, operands) => operands.iter().all(can_skip_operand),
_ => false, _ => false,
}; };
......
...@@ -30,41 +30,41 @@ fn main() -> () { ...@@ -30,41 +30,41 @@ fn main() -> () {
} }
alloc0 (static: FOO, size: 8, align: 4) { alloc0 (static: FOO, size: 8, align: 4) {
╾alloc25+0╼ 03 00 00 00 │ ╾──╼.... ╾alloc21+0╼ 03 00 00 00 │ ╾──╼....
} }
alloc25 (size: 48, align: 4) { alloc21 (size: 48, align: 4) {
0x00 │ 00 00 00 00 __ __ __ __ ╾alloc10+0╼ 00 00 00 00 │ ....░░░░╾──╼.... 0x00 │ 00 00 00 00 __ __ __ __ ╾alloc4+0─╼ 00 00 00 00 │ ....░░░░╾──╼....
0x10 │ 00 00 00 00 __ __ __ __ ╾alloc15+0╼ 02 00 00 00 │ ....░░░░╾──╼.... 0x10 │ 00 00 00 00 __ __ __ __ ╾alloc9+0─╼ 02 00 00 00 │ ....░░░░╾──╼....
0x20 │ 01 00 00 00 2a 00 00 00 ╾alloc23+0╼ 03 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) { alloc9 (size: 8, align: 4) {
╾alloc13+0╼ ╾alloc14+0╼ │ ╾──╼╾──╼ ╾alloc7+0─╼ ╾alloc8+0─╼ │ ╾──╼╾──╼
} }
alloc13 (size: 1, align: 1) { alloc7 (size: 1, align: 1) {
05 │ . 05 │ .
} }
alloc14 (size: 1, align: 1) { alloc8 (size: 1, align: 1) {
06 │ . 06 │ .
} }
alloc23 (size: 12, align: 4) { alloc19 (size: 12, align: 4) {
╾alloc19+3╼ ╾alloc20+0╼ ╾alloc22+2╼ │ ╾──╼╾──╼╾──╼ ╾alloc15+3╼ ╾alloc16+0╼ ╾alloc18+2╼ │ ╾──╼╾──╼╾──╼
} }
alloc19 (size: 4, align: 1) { alloc15 (size: 4, align: 1) {
2a 45 15 6f │ *E.o 2a 45 15 6f │ *E.o
} }
alloc20 (size: 1, align: 1) { alloc16 (size: 1, align: 1) {
2a │ * 2a │ *
} }
alloc22 (size: 4, align: 1) { alloc18 (size: 4, align: 1) {
2a 45 15 6f │ *E.o 2a 45 15 6f │ *E.o
} }
...@@ -30,44 +30,44 @@ fn main() -> () { ...@@ -30,44 +30,44 @@ fn main() -> () {
} }
alloc0 (static: FOO, size: 16, align: 8) { 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) { alloc21 (size: 72, align: 8) {
0x00 │ 00 00 00 00 __ __ __ __ ╾──────alloc10+0──────╼ │ ....░░░░╾──────╼ 0x00 │ 00 00 00 00 __ __ __ __ ╾──────alloc4+0───────╼ │ ....░░░░╾──────╼
0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ │ ............░░░░ 0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ │ ............░░░░
0x20 │ ╾──────alloc15+0──────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........ 0x20 │ ╾──────alloc9+0───────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........
0x30 │ 01 00 00 00 2a 00 00 00 ╾──────alloc23+0──────╼ │ ....*...╾──────╼ 0x30 │ 01 00 00 00 2a 00 00 00 ╾──────alloc19+0──────╼ │ ....*...╾──────╼
0x40 │ 03 00 00 00 00 00 00 00 │ ........ 0x40 │ 03 00 00 00 00 00 00 00 │ ........
} }
alloc10 (size: 0, align: 8) {} alloc4 (size: 0, align: 8) {}
alloc15 (size: 16, align: 8) { alloc9 (size: 16, align: 8) {
╾──────alloc13+0──────╼ ╾──────alloc14+0──────╼ │ ╾──────╼╾──────╼ ╾──────alloc7+0───────╼ ╾──────alloc8+0───────╼ │ ╾──────╼╾──────╼
} }
alloc13 (size: 1, align: 1) { alloc7 (size: 1, align: 1) {
05 │ . 05 │ .
} }
alloc14 (size: 1, align: 1) { alloc8 (size: 1, align: 1) {
06 │ . 06 │ .
} }
alloc23 (size: 24, align: 8) { alloc19 (size: 24, align: 8) {
0x00 │ ╾──────alloc19+3──────╼ ╾──────alloc20+0──────╼ │ ╾──────╼╾──────╼ 0x00 │ ╾──────alloc15+3──────╼ ╾──────alloc16+0──────╼ │ ╾──────╼╾──────╼
0x10 │ ╾──────alloc22+2──────╼ │ ╾──────╼ 0x10 │ ╾──────alloc18+2──────╼ │ ╾──────╼
} }
alloc19 (size: 4, align: 1) { alloc15 (size: 4, align: 1) {
2a 45 15 6f │ *E.o 2a 45 15 6f │ *E.o
} }
alloc20 (size: 1, align: 1) { alloc16 (size: 1, align: 1) {
2a │ * 2a │ *
} }
alloc22 (size: 4, align: 1) { alloc18 (size: 4, align: 1) {
2a 45 15 6f │ *E.o 2a 45 15 6f │ *E.o
} }
// Regression test for #66975 - ensure that we don't keep unevaluated // This was originally a regression test for #66975 - ensure that we do not generate never typed
// `!`-typed constants until codegen. // 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. // Force generation of optimized mir for functions that do not reach codegen.
// compile-flags: --emit mir,link // compile-flags: --emit mir,link
......
// 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
}
}
// 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
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册