diff options
Diffstat (limited to 'compiler/rustc_const_eval/src/transform')
4 files changed, 101 insertions, 149 deletions
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 0adb88a180f..cbfdb47dd1a 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -135,7 +135,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { // qualifs for the return type. let return_block = ccx .body - .basic_blocks() + .basic_blocks .iter_enumerated() .find(|(_, block)| matches!(block.terminator().kind, TerminatorKind::Return)) .map(|(bb, _)| bb); diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index 33802261644..5fb4bf638b3 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -1,6 +1,7 @@ //! Concrete error types for all operations which may be invalid in a certain const context. use hir::def_id::LocalDefId; +use hir::ConstContext; use rustc_errors::{ error_code, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, }; @@ -23,8 +24,11 @@ use rustc_trait_selection::traits::SelectionContext; use super::ConstCx; use crate::errors::{ - MutDerefErr, NonConstOpErr, PanicNonStrErr, RawPtrToIntErr, StaticAccessErr, - TransientMutBorrowErr, TransientMutBorrowErrRaw, + InteriorMutabilityBorrow, InteriorMutableDataRefer, MutDerefErr, NonConstFmtMacroCall, + NonConstFnCall, NonConstOpErr, PanicNonStrErr, RawPtrToIntErr, StaticAccessErr, + TransientMutBorrowErr, TransientMutBorrowErrRaw, UnallowedFnPointerCall, + UnallowedHeapAllocations, UnallowedInlineAsm, UnallowedMutableRefs, UnallowedMutableRefsRaw, + UnallowedOpInConstContext, UnstableConstFn, }; use crate::util::{call_kind, CallDesugaringKind, CallKind}; @@ -96,10 +100,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallIndirect { ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - ccx.tcx.sess.struct_span_err( - span, - &format!("function pointer calls are not allowed in {}s", ccx.const_kind()), - ) + ccx.tcx.sess.create_err(UnallowedFnPointerCall { span, kind: ccx.const_kind() }) } } @@ -307,22 +308,13 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { err } _ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::ArgumentV1Methods) => { - struct_span_err!( - ccx.tcx.sess, - span, - E0015, - "cannot call non-const formatting macro in {}s", - ccx.const_kind(), - ) + ccx.tcx.sess.create_err(NonConstFmtMacroCall { span, kind: ccx.const_kind() }) } - _ => struct_span_err!( - ccx.tcx.sess, + _ => ccx.tcx.sess.create_err(NonConstFnCall { span, - E0015, - "cannot call non-const fn `{}` in {}s", - ccx.tcx.def_path_str_with_substs(callee, substs), - ccx.const_kind(), - ), + def_path_str: ccx.tcx.def_path_str_with_substs(callee, substs), + kind: ccx.const_kind(), + }), }; err.note(&format!( @@ -331,6 +323,10 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { ccx.const_kind(), )); + if let ConstContext::Static(_) = ccx.const_kind() { + err.note("consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell"); + } + err } } @@ -349,10 +345,10 @@ impl<'tcx> NonConstOp<'tcx> for FnCallUnstable { ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { let FnCallUnstable(def_id, feature) = *self; - let mut err = ccx.tcx.sess.struct_span_err( - span, - &format!("`{}` is not yet stable as a const fn", ccx.tcx.def_path_str(def_id)), - ); + let mut err = ccx + .tcx + .sess + .create_err(UnstableConstFn { span, def_path: ccx.tcx.def_path_str(def_id) }); if ccx.is_const_stable_const_fn() { err.help("const-stable functions can only call other const-stable functions"); @@ -387,9 +383,12 @@ impl<'tcx> NonConstOp<'tcx> for Generator { ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { let msg = format!("{}s are not allowed in {}s", self.0, ccx.const_kind()); if let hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) = self.0 { - feature_err(&ccx.tcx.sess.parse_sess, sym::const_async_blocks, span, &msg) + ccx.tcx.sess.create_feature_err( + UnallowedOpInConstContext { span, msg }, + sym::const_async_blocks, + ) } else { - ccx.tcx.sess.struct_span_err(span, &msg) + ccx.tcx.sess.create_err(UnallowedOpInConstContext { span, msg }) } } } @@ -402,23 +401,11 @@ impl<'tcx> NonConstOp<'tcx> for HeapAllocation { ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - let mut err = struct_span_err!( - ccx.tcx.sess, + ccx.tcx.sess.create_err(UnallowedHeapAllocations { span, - E0010, - "allocations are not allowed in {}s", - ccx.const_kind() - ); - err.span_label(span, format!("allocation not allowed in {}s", ccx.const_kind())); - if ccx.tcx.sess.teach(&err.get_code().unwrap()) { - err.note( - "The value of statics and constants must be known at compile time, \ - and they live for the entire lifetime of a program. Creating a boxed \ - value allocates memory on the heap at runtime, and therefore cannot \ - be done at compile time.", - ); - } - err + kind: ccx.const_kind(), + teach: ccx.tcx.sess.teach(&error_code!(E0010)).then_some(()), + }) } } @@ -430,13 +417,7 @@ impl<'tcx> NonConstOp<'tcx> for InlineAsm { ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - struct_span_err!( - ccx.tcx.sess, - span, - E0015, - "inline assembly is not allowed in {}s", - ccx.const_kind() - ) + ccx.tcx.sess.create_err(UnallowedInlineAsm { span, kind: ccx.const_kind() }) } } @@ -482,12 +463,7 @@ impl<'tcx> NonConstOp<'tcx> for TransientCellBorrow { ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - feature_err( - &ccx.tcx.sess.parse_sess, - sym::const_refs_to_cell, - span, - "cannot borrow here, since the borrowed element may contain interior mutability", - ) + ccx.tcx.sess.create_feature_err(InteriorMutabilityBorrow { span }, sym::const_refs_to_cell) } } @@ -502,32 +478,22 @@ impl<'tcx> NonConstOp<'tcx> for CellBorrow { ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - let mut err = struct_span_err!( - ccx.tcx.sess, - span, - E0492, - "{}s cannot refer to interior mutable data", - ccx.const_kind(), - ); - err.span_label( - span, - "this borrow of an interior mutable value may end up in the final value", - ); + // FIXME: Maybe a more elegant solution to this if else case if let hir::ConstContext::Static(_) = ccx.const_kind() { - err.help( - "to fix this, the value can be extracted to a separate \ - `static` item and then referenced", - ); - } - if ccx.tcx.sess.teach(&err.get_code().unwrap()) { - err.note( - "A constant containing interior mutable data behind a reference can allow you - to modify that data. This would make multiple uses of a constant to be able to - see different values and allow circumventing the `Send` and `Sync` requirements - for shared mutable data, which is unsound.", - ); + ccx.tcx.sess.create_err(InteriorMutableDataRefer { + span, + opt_help: Some(()), + kind: ccx.const_kind(), + teach: ccx.tcx.sess.teach(&error_code!(E0492)).then_some(()), + }) + } else { + ccx.tcx.sess.create_err(InteriorMutableDataRefer { + span, + opt_help: None, + kind: ccx.const_kind(), + teach: ccx.tcx.sess.teach(&error_code!(E0492)).then_some(()), + }) } - err } } @@ -553,33 +519,18 @@ impl<'tcx> NonConstOp<'tcx> for MutBorrow { ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - let raw = match self.0 { - hir::BorrowKind::Raw => "raw ", - hir::BorrowKind::Ref => "", - }; - - let mut err = struct_span_err!( - ccx.tcx.sess, - span, - E0764, - "{}mutable references are not allowed in the final value of {}s", - raw, - ccx.const_kind(), - ); - - if ccx.tcx.sess.teach(&err.get_code().unwrap()) { - err.note( - "References in statics and constants may only refer \ - to immutable values.\n\n\ - Statics are shared everywhere, and if they refer to \ - mutable data one might violate memory safety since \ - holding multiple mutable references to shared data \ - is not allowed.\n\n\ - If you really want global mutable state, try using \ - static mut or a global UnsafeCell.", - ); + match self.0 { + hir::BorrowKind::Raw => ccx.tcx.sess.create_err(UnallowedMutableRefsRaw { + span, + kind: ccx.const_kind(), + teach: ccx.tcx.sess.teach(&error_code!(E0764)).then_some(()), + }), + hir::BorrowKind::Ref => ccx.tcx.sess.create_err(UnallowedMutableRefs { + span, + kind: ccx.const_kind(), + teach: ccx.tcx.sess.teach(&error_code!(E0764)).then_some(()), + }), } - err } } diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index 161c89e3242..f5ba408bee0 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -41,7 +41,7 @@ pub struct PromoteTemps<'tcx> { impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> { fn phase_change(&self) -> Option<MirPhase> { - Some(MirPhase::ConstsPromoted) + Some(MirPhase::Analysis(AnalysisPhase::Initial)) } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { @@ -710,7 +710,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { } fn assign(&mut self, dest: Local, rvalue: Rvalue<'tcx>, span: Span) { - let last = self.promoted.basic_blocks().last().unwrap(); + let last = self.promoted.basic_blocks.last().unwrap(); let data = &mut self.promoted[last]; data.statements.push(Statement { source_info: SourceInfo::outermost(span), @@ -803,7 +803,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { self.visit_operand(arg, loc); } - let last = self.promoted.basic_blocks().last().unwrap(); + let last = self.promoted.basic_blocks.last().unwrap(); let new_target = self.new_block(); *self.promoted[last].terminator_mut() = Terminator { @@ -964,7 +964,7 @@ pub fn promote_candidates<'tcx>( let mut scope = body.source_scopes[body.source_info(candidate.location).scope].clone(); scope.parent_scope = None; - let promoted = Body::new( + let mut promoted = Body::new( body.source, // `promoted` gets filled in below IndexVec::new(), IndexVec::from_elem_n(scope, 1), @@ -976,6 +976,7 @@ pub fn promote_candidates<'tcx>( body.generator_kind(), body.tainted_by_errors, ); + promoted.phase = MirPhase::Analysis(AnalysisPhase::Initial); let promoter = Promoter { promoted, @@ -1041,7 +1042,7 @@ pub fn is_const_fn_in_array_repeat_expression<'tcx>( _ => {} } - for block in body.basic_blocks() { + for block in body.basic_blocks.iter() { if let Some(Terminator { kind: TerminatorKind::Call { func, destination, .. }, .. }) = &block.terminator { diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 15e820f2d19..b662513e70f 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -8,8 +8,8 @@ use rustc_middle::mir::visit::NonUseContext::VarDebugInfo; use rustc_middle::mir::visit::{PlaceContext, Visitor}; use rustc_middle::mir::{ traversal, AggregateKind, BasicBlock, BinOp, Body, BorrowKind, CastKind, Local, Location, - MirPass, MirPhase, Operand, Place, PlaceElem, PlaceRef, ProjectionElem, Rvalue, SourceScope, - Statement, StatementKind, Terminator, TerminatorKind, UnOp, START_BLOCK, + MirPass, MirPhase, Operand, Place, PlaceElem, PlaceRef, ProjectionElem, RuntimePhase, Rvalue, + SourceScope, Statement, StatementKind, Terminator, TerminatorKind, UnOp, START_BLOCK, }; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::subst::Subst; @@ -89,22 +89,20 @@ pub fn equal_up_to_regions<'tcx>( // Normalize lifetimes away on both sides, then compare. let normalize = |ty: Ty<'tcx>| { - tcx.normalize_erasing_regions( - param_env, - ty.fold_with(&mut BottomUpFolder { - tcx, - // FIXME: We erase all late-bound lifetimes, but this is not fully correct. - // If you have a type like `<for<'a> fn(&'a u32) as SomeTrait>::Assoc`, - // this is not necessarily equivalent to `<fn(&'static u32) as SomeTrait>::Assoc`, - // since one may have an `impl SomeTrait for fn(&32)` and - // `impl SomeTrait for fn(&'static u32)` at the same time which - // specify distinct values for Assoc. (See also #56105) - lt_op: |_| tcx.lifetimes.re_erased, - // Leave consts and types unchanged. - ct_op: |ct| ct, - ty_op: |ty| ty, - }), - ) + let ty = ty.fold_with(&mut BottomUpFolder { + tcx, + // FIXME: We erase all late-bound lifetimes, but this is not fully correct. + // If you have a type like `<for<'a> fn(&'a u32) as SomeTrait>::Assoc`, + // this is not necessarily equivalent to `<fn(&'static u32) as SomeTrait>::Assoc`, + // since one may have an `impl SomeTrait for fn(&32)` and + // `impl SomeTrait for fn(&'static u32)` at the same time which + // specify distinct values for Assoc. (See also #56105) + lt_op: |_| tcx.lifetimes.re_erased, + // Leave consts and types unchanged. + ct_op: |ct| ct, + ty_op: |ty| ty, + }); + tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty) }; tcx.infer_ctxt().enter(|infcx| infcx.can_eq(param_env, normalize(src), normalize(dest)).is_ok()) } @@ -142,8 +140,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { if bb == START_BLOCK { self.fail(location, "start block must not have predecessors") } - if let Some(bb) = self.body.basic_blocks().get(bb) { - let src = self.body.basic_blocks().get(location.block).unwrap(); + if let Some(bb) = self.body.basic_blocks.get(bb) { + let src = self.body.basic_blocks.get(location.block).unwrap(); match (src.is_cleanup, bb.is_cleanup, edge_kind) { // Non-cleanup blocks can jump to non-cleanup blocks along non-unwind edges (false, false, EdgeKind::Normal) @@ -223,7 +221,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) { // This check is somewhat expensive, so only run it when -Zvalidate-mir is passed. - if self.tcx.sess.opts.unstable_opts.validate_mir && self.mir_phase < MirPhase::DropsLowered + if self.tcx.sess.opts.unstable_opts.validate_mir + && self.mir_phase < MirPhase::Runtime(RuntimePhase::Initial) { // `Operand::Copy` is only supposed to be used with `Copy` types. if let Operand::Copy(place) = operand { @@ -254,7 +253,9 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { self.fail(location, format!("bad index ({:?} != usize)", index_ty)) } } - ProjectionElem::Deref if self.mir_phase >= MirPhase::GeneratorsLowered => { + ProjectionElem::Deref + if self.mir_phase >= MirPhase::Runtime(RuntimePhase::PostCleanup) => + { let base_ty = Place::ty_from(local, proj_base, &self.body.local_decls, self.tcx).ty; if base_ty.is_box() { @@ -362,7 +363,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { // Set off any `bug!`s in the type computation code let _ = place.ty(&self.body.local_decls, self.tcx); - if self.mir_phase >= MirPhase::Derefered + if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) && place.projection.len() > 1 && cntxt != PlaceContext::NonUse(VarDebugInfo) && place.projection[1..].contains(&ProjectionElem::Deref) @@ -386,8 +387,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { Rvalue::Aggregate(agg_kind, _) => { let disallowed = match **agg_kind { AggregateKind::Array(..) => false, - AggregateKind::Generator(..) => self.mir_phase >= MirPhase::GeneratorsLowered, - _ => self.mir_phase >= MirPhase::Deaggregated, + _ => self.mir_phase >= MirPhase::Runtime(RuntimePhase::PostCleanup), }; if disallowed { self.fail( @@ -397,10 +397,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } Rvalue::Ref(_, BorrowKind::Shallow, _) => { - if self.mir_phase >= MirPhase::DropsLowered { + if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { self.fail( location, - "`Assign` statement with a `Shallow` borrow should have been removed after drop lowering phase", + "`Assign` statement with a `Shallow` borrow should have been removed in runtime MIR", ); } } @@ -614,7 +614,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } StatementKind::AscribeUserType(..) => { - if self.mir_phase >= MirPhase::DropsLowered { + if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { self.fail( location, "`AscribeUserType` should have been removed after drop lowering phase", @@ -622,7 +622,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } StatementKind::FakeRead(..) => { - if self.mir_phase >= MirPhase::DropsLowered { + if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { self.fail( location, "`FakeRead` should have been removed after drop lowering phase", @@ -666,7 +666,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } StatementKind::SetDiscriminant { place, .. } => { - if self.mir_phase < MirPhase::Deaggregated { + if self.mir_phase < MirPhase::Runtime(RuntimePhase::Initial) { self.fail(location, "`SetDiscriminant`is not allowed until deaggregation"); } let pty = place.ty(&self.body.local_decls, self.tcx).ty.kind(); @@ -681,7 +681,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } StatementKind::Deinit(..) => { - if self.mir_phase < MirPhase::Deaggregated { + if self.mir_phase < MirPhase::Runtime(RuntimePhase::Initial) { self.fail(location, "`Deinit`is not allowed until deaggregation"); } } @@ -761,7 +761,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } TerminatorKind::DropAndReplace { target, unwind, .. } => { - if self.mir_phase >= MirPhase::DropsLowered { + if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { self.fail( location, "`DropAndReplace` should have been removed during drop elaboration", @@ -832,7 +832,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { if self.body.generator.is_none() { self.fail(location, "`Yield` cannot appear outside generator bodies"); } - if self.mir_phase >= MirPhase::GeneratorsLowered { + if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { self.fail(location, "`Yield` should have been replaced by generator lowering"); } self.check_edge(location, *resume, EdgeKind::Normal); @@ -841,7 +841,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } TerminatorKind::FalseEdge { real_target, imaginary_target } => { - if self.mir_phase >= MirPhase::DropsLowered { + if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { self.fail( location, "`FalseEdge` should have been removed after drop elaboration", @@ -851,7 +851,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { self.check_edge(location, *imaginary_target, EdgeKind::Normal); } TerminatorKind::FalseUnwind { real_target, unwind } => { - if self.mir_phase >= MirPhase::DropsLowered { + if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { self.fail( location, "`FalseUnwind` should have been removed after drop elaboration", @@ -874,7 +874,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { if self.body.generator.is_none() { self.fail(location, "`GeneratorDrop` cannot appear outside generator bodies"); } - if self.mir_phase >= MirPhase::GeneratorsLowered { + if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { self.fail( location, "`GeneratorDrop` should have been replaced by generator lowering", @@ -883,13 +883,13 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } TerminatorKind::Resume | TerminatorKind::Abort => { let bb = location.block; - if !self.body.basic_blocks()[bb].is_cleanup { + if !self.body.basic_blocks[bb].is_cleanup { self.fail(location, "Cannot `Resume` or `Abort` from non-cleanup basic block") } } TerminatorKind::Return => { let bb = location.block; - if self.body.basic_blocks()[bb].is_cleanup { + if self.body.basic_blocks[bb].is_cleanup { self.fail(location, "Cannot `Return` from cleanup basic block") } } |
