Importing rustc-1.53.0
Bug: 194400612
Change-Id: Id2f38eeabc8325fff960e46b89b1cc7216f5227c
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
index eb942b1..9f19a47 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
@@ -197,7 +197,11 @@
);
}
}
- FnSelfUseKind::Normal { self_arg, implicit_into_iter } => {
+ FnSelfUseKind::Normal {
+ self_arg,
+ implicit_into_iter,
+ is_option_or_result,
+ } => {
if implicit_into_iter {
err.span_label(
fn_call_span,
@@ -215,6 +219,14 @@
),
);
}
+ if is_option_or_result {
+ err.span_suggestion_verbose(
+ fn_call_span.shrink_to_lo(),
+ "consider calling `.as_ref()` to borrow the type's contents",
+ "as_ref().".to_string(),
+ Applicability::MachineApplicable,
+ );
+ }
// Avoid pointing to the same function in multiple different
// error messages.
if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span)
@@ -264,7 +276,24 @@
if let Some(DesugaringKind::ForLoop(_)) = move_span.desugaring_kind() {
let sess = self.infcx.tcx.sess;
- if let Ok(snippet) = sess.source_map().span_to_snippet(move_span) {
+ let ty = used_place.ty(self.body, self.infcx.tcx).ty;
+ // If we have a `&mut` ref, we need to reborrow.
+ if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
+ // If we are in a loop this will be suggested later.
+ if !is_loop_move {
+ err.span_suggestion_verbose(
+ move_span.shrink_to_lo(),
+ &format!(
+ "consider creating a fresh reborrow of {} here",
+ self.describe_place(moved_place.as_ref())
+ .map(|n| format!("`{}`", n))
+ .unwrap_or_else(|| "the mutable reference".to_string()),
+ ),
+ format!("&mut *"),
+ Applicability::MachineApplicable,
+ );
+ }
+ } else if let Ok(snippet) = sess.source_map().span_to_snippet(move_span) {
err.span_suggestion(
move_span,
"consider borrowing to avoid moving into the for loop",
@@ -1664,7 +1693,7 @@
if decl.can_be_made_mutable() {
err.span_suggestion(
decl.source_info.span,
- "make this binding mutable",
+ "consider making this binding mutable",
format!("mut {}", name),
Applicability::MachineApplicable,
);
@@ -1728,7 +1757,7 @@
impl<'tcx> Visitor<'tcx> for FakeReadCauseFinder<'tcx> {
fn visit_statement(&mut self, statement: &Statement<'tcx>, _: Location) {
match statement {
- Statement { kind: StatementKind::FakeRead(cause, box place), .. }
+ Statement { kind: StatementKind::FakeRead(box (cause, place)), .. }
if *place == self.place =>
{
self.cause = Some(*cause);
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs
index 06e3f4b..2a388b8 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs
@@ -515,7 +515,7 @@
let block = &self.body.basic_blocks()[location.block];
let kind = if let Some(&Statement {
- kind: StatementKind::FakeRead(FakeReadCause::ForLet, _),
+ kind: StatementKind::FakeRead(box (FakeReadCause::ForLet(_), _)),
..
}) = block.statements.get(location.statement_index)
{
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs
index ec561fa..aa9f18d 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs
@@ -7,8 +7,8 @@
use rustc_hir::lang_items::LangItemGroup;
use rustc_hir::GeneratorKind;
use rustc_middle::mir::{
- AggregateKind, Constant, Field, Local, LocalInfo, LocalKind, Location, Operand, Place,
- PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
+ AggregateKind, Constant, FakeReadCause, Field, Local, LocalInfo, LocalKind, Location, Operand,
+ Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
};
use rustc_middle::ty::print::Print;
use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt};
@@ -18,6 +18,7 @@
Span,
};
use rustc_target::abi::VariantIdx;
+use std::iter;
use super::borrow_set::BorrowData;
use super::MirBorrowckCtxt;
@@ -501,7 +502,7 @@
// lifetimes without names with the value `'0`.
match ty.kind() {
ty::Ref(
- ty::RegionKind::ReLateBound(_, ty::BoundRegion { kind: br })
+ ty::RegionKind::ReLateBound(_, ty::BoundRegion { kind: br, .. })
| ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }),
_,
_,
@@ -522,7 +523,7 @@
let region = match ty.kind() {
ty::Ref(region, _, _) => {
match region {
- ty::RegionKind::ReLateBound(_, ty::BoundRegion { kind: br })
+ ty::RegionKind::ReLateBound(_, ty::BoundRegion { kind: br, .. })
| ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }) => {
printer.region_highlight_mode.highlighting_bound_region(*br, counter)
}
@@ -572,7 +573,13 @@
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub(super) enum FnSelfUseKind<'tcx> {
/// A normal method call of the form `receiver.foo(a, b, c)`
- Normal { self_arg: Ident, implicit_into_iter: bool },
+ Normal {
+ self_arg: Ident,
+ implicit_into_iter: bool,
+ /// Whether the self type of the method call has an `.as_ref()` method.
+ /// Used for better diagnostics.
+ is_option_or_result: bool,
+ },
/// A call to `FnOnce::call_once`, desugared from `my_closure(a, b, c)`
FnOnceCall,
/// A call to an operator trait, desuraged from operator syntax (e.g. `a << b`)
@@ -794,6 +801,24 @@
}
}
+ // StatementKind::FakeRead only contains a def_id if they are introduced as a result
+ // of pattern matching within a closure.
+ if let StatementKind::FakeRead(box (cause, ref place)) = stmt.kind {
+ match cause {
+ FakeReadCause::ForMatchedPlace(Some(closure_def_id))
+ | FakeReadCause::ForLet(Some(closure_def_id)) => {
+ debug!("move_spans: def_id={:?} place={:?}", closure_def_id, place);
+ let places = &[Operand::Move(*place)];
+ if let Some((args_span, generator_kind, var_span)) =
+ self.closure_span(closure_def_id, moved_place, places)
+ {
+ return ClosureUse { generator_kind, args_span, var_span };
+ }
+ }
+ _ => {}
+ }
+ }
+
let normal_ret =
if moved_place.projection.iter().any(|p| matches!(p, ProjectionElem::Downcast(..))) {
PatUse(stmt.source_info.span)
@@ -881,7 +906,17 @@
fn_call_span.desugaring_kind(),
Some(DesugaringKind::ForLoop(ForLoopLoc::IntoIter))
);
- FnSelfUseKind::Normal { self_arg, implicit_into_iter }
+ let parent_self_ty = parent
+ .filter(|did| tcx.def_kind(*did) == rustc_hir::def::DefKind::Impl)
+ .and_then(|did| match tcx.type_of(did).kind() {
+ ty::Adt(def, ..) => Some(def.did),
+ _ => None,
+ });
+ let is_option_or_result = parent_self_ty.map_or(false, |def_id| {
+ tcx.is_diagnostic_item(sym::option_type, def_id)
+ || tcx.is_diagnostic_item(sym::result_type, def_id)
+ });
+ FnSelfUseKind::Normal { self_arg, implicit_into_iter, is_option_or_result }
});
return FnSelfUse {
@@ -970,13 +1005,10 @@
let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind;
debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr);
if let hir::ExprKind::Closure(.., body_id, args_span, _) = expr {
- for (captured_place, place) in self
- .infcx
- .tcx
- .typeck(def_id.expect_local())
- .closure_min_captures_flattened(def_id)
- .zip(places)
- {
+ for (captured_place, place) in iter::zip(
+ self.infcx.tcx.typeck(def_id.expect_local()).closure_min_captures_flattened(def_id),
+ places,
+ ) {
let upvar_hir_id = captured_place.get_root_variable();
//FIXME(project-rfc-2229#8): Use better span from captured_place
let span = self.infcx.tcx.upvars_mentioned(local_did)?[&upvar_hir_id].span;
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/outlives_suggestion.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/outlives_suggestion.rs
index 7505e6e..7dc3434 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/outlives_suggestion.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/outlives_suggestion.rs
@@ -1,4 +1,4 @@
-//! Contains utilities for generating suggestions for borrowck errors related to unsatisified
+//! Contains utilities for generating suggestions for borrowck errors related to unsatisfied
//! outlives constraints.
use std::collections::BTreeMap;
@@ -157,7 +157,7 @@
debug!("Collected {:?}: {:?}", fr, outlived_fr);
// Add to set of constraints for final help note.
- self.constraints_to_add.entry(fr).or_insert(Vec::new()).push(outlived_fr);
+ self.constraints_to_add.entry(fr).or_default().push(outlived_fr);
}
/// Emit an intermediate note on the given `Diagnostic` if the involved regions are
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs
index 03738f1..1f168c6 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs
@@ -1,4 +1,5 @@
use std::fmt::{self, Display};
+use std::iter;
use rustc_errors::DiagnosticBuilder;
use rustc_hir as hir;
@@ -536,7 +537,8 @@
// just worry about trying to match up the rustc type
// with the HIR types:
(ty::Tuple(elem_tys), hir::TyKind::Tup(elem_hir_tys)) => {
- search_stack.extend(elem_tys.iter().map(|k| k.expect_ty()).zip(*elem_hir_tys));
+ search_stack
+ .extend(iter::zip(elem_tys.iter().map(|k| k.expect_ty()), *elem_hir_tys));
}
(ty::Slice(elem_ty), hir::TyKind::Slice(elem_hir_ty))
@@ -611,7 +613,7 @@
args: &'hir hir::GenericArgs<'hir>,
search_stack: &mut Vec<(Ty<'tcx>, &'hir hir::Ty<'hir>)>,
) -> Option<&'hir hir::Lifetime> {
- for (kind, hir_arg) in substs.iter().zip(args.args) {
+ for (kind, hir_arg) in iter::zip(substs, args.args) {
match (kind.unpack(), hir_arg) {
(GenericArgKind::Lifetime(r), hir::GenericArg::Lifetime(lt)) => {
if r.to_region_vid() == needle_fr {
diff --git a/compiler/rustc_mir/src/borrow_check/invalidation.rs b/compiler/rustc_mir/src/borrow_check/invalidation.rs
index 17c4f3c..e621baf 100644
--- a/compiler/rustc_mir/src/borrow_check/invalidation.rs
+++ b/compiler/rustc_mir/src/borrow_check/invalidation.rs
@@ -5,6 +5,7 @@
use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind};
use rustc_middle::mir::{Statement, StatementKind};
use rustc_middle::ty::TyCtxt;
+use std::iter;
use crate::dataflow::indexes::BorrowIndex;
@@ -62,14 +63,14 @@
self.mutate_place(location, *lhs, Shallow(None), JustWrite);
}
- StatementKind::FakeRead(_, _) => {
+ StatementKind::FakeRead(box (_, _)) => {
// Only relevant for initialized/liveness/safety checks.
}
StatementKind::SetDiscriminant { place, variant_index: _ } => {
self.mutate_place(location, **place, Shallow(None), JustWrite);
}
StatementKind::LlvmInlineAsm(asm) => {
- for (o, output) in asm.asm.outputs.iter().zip(asm.outputs.iter()) {
+ for (o, output) in iter::zip(&asm.asm.outputs, &*asm.outputs) {
if o.is_indirect {
// FIXME(eddyb) indirect inline asm outputs should
// be encoded through MIR place derefs instead.
@@ -203,8 +204,7 @@
} => {
for op in operands {
match *op {
- InlineAsmOperand::In { reg: _, ref value }
- | InlineAsmOperand::Const { ref value } => {
+ InlineAsmOperand::In { reg: _, ref value } => {
self.consume_operand(location, value);
}
InlineAsmOperand::Out { reg: _, late: _, place, .. } => {
@@ -218,7 +218,8 @@
self.mutate_place(location, out_place, Shallow(None), JustWrite);
}
}
- InlineAsmOperand::SymFn { value: _ }
+ InlineAsmOperand::Const { value: _ }
+ | InlineAsmOperand::SymFn { value: _ }
| InlineAsmOperand::SymStatic { def_id: _ } => {}
}
}
diff --git a/compiler/rustc_mir/src/borrow_check/mod.rs b/compiler/rustc_mir/src/borrow_check/mod.rs
index 5b8bb72..2d1d83b 100644
--- a/compiler/rustc_mir/src/borrow_check/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/mod.rs
@@ -25,6 +25,7 @@
use smallvec::SmallVec;
use std::cell::RefCell;
use std::collections::BTreeMap;
+use std::iter;
use std::mem;
use std::rc::Rc;
@@ -573,7 +574,7 @@
self.mutate_place(location, (*lhs, span), Shallow(None), JustWrite, flow_state);
}
- StatementKind::FakeRead(_, box ref place) => {
+ StatementKind::FakeRead(box (_, ref place)) => {
// Read for match doesn't access any memory and is used to
// assert that a place is safe and live. So we don't have to
// do any checks here.
@@ -595,7 +596,7 @@
self.mutate_place(location, (**place, span), Shallow(None), JustWrite, flow_state);
}
StatementKind::LlvmInlineAsm(ref asm) => {
- for (o, output) in asm.asm.outputs.iter().zip(asm.outputs.iter()) {
+ for (o, output) in iter::zip(&asm.asm.outputs, &*asm.outputs) {
if o.is_indirect {
// FIXME(eddyb) indirect inline asm outputs should
// be encoded through MIR place derefs instead.
@@ -733,8 +734,7 @@
} => {
for op in operands {
match *op {
- InlineAsmOperand::In { reg: _, ref value }
- | InlineAsmOperand::Const { ref value } => {
+ InlineAsmOperand::In { reg: _, ref value } => {
self.consume_operand(loc, (value, span), flow_state);
}
InlineAsmOperand::Out { reg: _, late: _, place, .. } => {
@@ -760,7 +760,8 @@
);
}
}
- InlineAsmOperand::SymFn { value: _ }
+ InlineAsmOperand::Const { value: _ }
+ | InlineAsmOperand::SymFn { value: _ }
| InlineAsmOperand::SymStatic { def_id: _ } => {}
}
}
diff --git a/compiler/rustc_mir/src/borrow_check/places_conflict.rs b/compiler/rustc_mir/src/borrow_check/places_conflict.rs
index 02c7b7d..3654b51 100644
--- a/compiler/rustc_mir/src/borrow_check/places_conflict.rs
+++ b/compiler/rustc_mir/src/borrow_check/places_conflict.rs
@@ -5,6 +5,7 @@
use rustc_middle::mir::{Body, BorrowKind, Local, Place, PlaceElem, PlaceRef, ProjectionElem};
use rustc_middle::ty::{self, TyCtxt};
use std::cmp::max;
+use std::iter;
/// When checking if a place conflicts with another place, this enum is used to influence decisions
/// where a place might be equal or disjoint with another place, such as if `a[i] == a[j]`.
@@ -139,7 +140,7 @@
// loop invariant: borrow_c is always either equal to access_c or disjoint from it.
for (i, (borrow_c, &access_c)) in
- borrow_place.projection.iter().zip(access_place.projection.iter()).enumerate()
+ iter::zip(borrow_place.projection, access_place.projection).enumerate()
{
debug!("borrow_conflicts_with_place: borrow_c = {:?}", borrow_c);
let borrow_proj_base = &borrow_place.projection[..i];
diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/graphviz.rs b/compiler/rustc_mir/src/borrow_check/region_infer/graphviz.rs
index a272e92..7156612 100644
--- a/compiler/rustc_mir/src/borrow_check/region_infer/graphviz.rs
+++ b/compiler/rustc_mir/src/borrow_check/region_infer/graphviz.rs
@@ -1,5 +1,5 @@
//! This module provides linkage between RegionInferenceContext and
-//! librustc_graphviz traits, specialized to attaching borrowck analysis
+//! `rustc_graphviz` traits, specialized to attaching borrowck analysis
//! data to rendered labels.
use std::borrow::Cow;
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs b/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs
index 77d9136..1bb447d 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs
+++ b/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs
@@ -70,6 +70,12 @@
// Equate expected input tys with those in the MIR.
for (argument_index, &normalized_input_ty) in normalized_input_tys.iter().enumerate() {
+ if argument_index + 1 >= body.local_decls.len() {
+ self.tcx()
+ .sess
+ .delay_span_bug(body.span, "found more normalized_input_ty than local_decls");
+ break;
+ }
// In MIR, argument N is stored in local N+1.
let local = Local::new(argument_index + 1);
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
index cce1549..d27fcb2 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
@@ -97,7 +97,7 @@
/// Type checks the given `mir` in the context of the inference
/// context `infcx`. Returns any region constraints that have yet to
-/// be proven. This result is includes liveness constraints that
+/// be proven. This result includes liveness constraints that
/// ensure that regions appearing in the types of all local variables
/// are live at all points where that local variable may later be
/// used.
@@ -316,14 +316,12 @@
let tcx = self.tcx();
let maybe_uneval = match constant.literal {
ConstantKind::Ty(ct) => match ct.val {
- ty::ConstKind::Unevaluated(def, substs, promoted) => {
- Some((def, substs, promoted))
- }
+ ty::ConstKind::Unevaluated(uv) => Some(uv),
_ => None,
},
_ => None,
};
- if let Some((def, substs, promoted)) = maybe_uneval {
+ if let Some(ty::Unevaluated { def, substs, promoted }) = maybe_uneval {
if let Some(promoted) = promoted {
let check_err = |verifier: &mut TypeVerifier<'a, 'b, 'tcx>,
promoted: &Body<'tcx>,
@@ -1772,7 +1770,7 @@
if args.len() < sig.inputs().len() || (args.len() > sig.inputs().len() && !sig.c_variadic) {
span_mirbug!(self, term, "call to {:?} with wrong # of args", sig);
}
- for (n, (fn_arg, op_arg)) in sig.inputs().iter().zip(args).enumerate() {
+ for (n, (fn_arg, op_arg)) in iter::zip(sig.inputs(), args).enumerate() {
let op_arg_ty = op_arg.ty(body, self.tcx());
let op_arg_ty = self.normalize(op_arg_ty, term_location);
let category = if from_hir_call {
@@ -2030,7 +2028,7 @@
traits::ObligationCauseCode::RepeatVec(is_const_fn),
),
self.param_env,
- ty::Binder::bind(ty::TraitRef::new(
+ ty::Binder::dummy(ty::TraitRef::new(
self.tcx().require_lang_item(
LangItem::Copy,
Some(self.last_span),
diff --git a/compiler/rustc_mir/src/borrow_check/universal_regions.rs b/compiler/rustc_mir/src/borrow_check/universal_regions.rs
index 4b1acc1..c2ac1e2 100644
--- a/compiler/rustc_mir/src/borrow_check/universal_regions.rs
+++ b/compiler/rustc_mir/src/borrow_check/universal_regions.rs
@@ -580,7 +580,7 @@
let global_mapping = iter::once((tcx.lifetimes.re_static, fr_static));
let subst_mapping =
- identity_substs.regions().zip(fr_substs.regions().map(|r| r.to_region_vid()));
+ iter::zip(identity_substs.regions(), fr_substs.regions().map(|r| r.to_region_vid()));
UniversalRegionIndices { indices: global_mapping.chain(subst_mapping).collect() }
}
@@ -589,31 +589,45 @@
&self,
indices: &UniversalRegionIndices<'tcx>,
defining_ty: DefiningTy<'tcx>,
- ) -> ty::Binder<&'tcx ty::List<Ty<'tcx>>> {
+ ) -> ty::Binder<'tcx, &'tcx ty::List<Ty<'tcx>>> {
let tcx = self.infcx.tcx;
match defining_ty {
DefiningTy::Closure(def_id, substs) => {
assert_eq!(self.mir_def.did.to_def_id(), def_id);
let closure_sig = substs.as_closure().sig();
let inputs_and_output = closure_sig.inputs_and_output();
- let closure_ty = tcx.closure_env_ty(def_id, substs).unwrap();
- ty::Binder::fuse(closure_ty, inputs_and_output, |closure_ty, inputs_and_output| {
- // The "inputs" of the closure in the
- // signature appear as a tuple. The MIR side
- // flattens this tuple.
- let (&output, tuplized_inputs) = inputs_and_output.split_last().unwrap();
- assert_eq!(tuplized_inputs.len(), 1, "multiple closure inputs");
- let inputs = match tuplized_inputs[0].kind() {
- ty::Tuple(inputs) => inputs,
- _ => bug!("closure inputs not a tuple: {:?}", tuplized_inputs[0]),
- };
+ let bound_vars = tcx.mk_bound_variable_kinds(
+ inputs_and_output
+ .bound_vars()
+ .iter()
+ .chain(iter::once(ty::BoundVariableKind::Region(ty::BrEnv))),
+ );
+ let br = ty::BoundRegion {
+ var: ty::BoundVar::from_usize(bound_vars.len() - 1),
+ kind: ty::BrEnv,
+ };
+ let env_region = ty::ReLateBound(ty::INNERMOST, br);
+ let closure_ty = tcx.closure_env_ty(def_id, substs, env_region).unwrap();
+ // The "inputs" of the closure in the
+ // signature appear as a tuple. The MIR side
+ // flattens this tuple.
+ let (&output, tuplized_inputs) =
+ inputs_and_output.skip_binder().split_last().unwrap();
+ assert_eq!(tuplized_inputs.len(), 1, "multiple closure inputs");
+ let inputs = match tuplized_inputs[0].kind() {
+ ty::Tuple(inputs) => inputs,
+ _ => bug!("closure inputs not a tuple: {:?}", tuplized_inputs[0]),
+ };
+
+ ty::Binder::bind_with_vars(
tcx.mk_type_list(
iter::once(closure_ty)
.chain(inputs.iter().map(|k| k.expect_ty()))
.chain(iter::once(output)),
- )
- })
+ ),
+ bound_vars,
+ )
}
DefiningTy::Generator(def_id, substs, movability) => {
@@ -657,7 +671,7 @@
&self,
origin: NllRegionVariableOrigin,
all_outlive_scope: LocalDefId,
- value: ty::Binder<T>,
+ value: ty::Binder<'tcx, T>,
indices: &mut UniversalRegionIndices<'tcx>,
) -> T
where
@@ -686,7 +700,7 @@
&self,
origin: NllRegionVariableOrigin,
all_outlive_scope: LocalDefId,
- value: ty::Binder<T>,
+ value: ty::Binder<'tcx, T>,
indices: &mut UniversalRegionIndices<'tcx>,
) -> T
where
diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs
index fa234ff..d51adc8 100644
--- a/compiler/rustc_mir/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs
@@ -5,6 +5,7 @@
Immediate, InternKind, InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, Scalar,
ScalarMaybeUninit, StackPopCleanup,
};
+use crate::util::pretty::display_allocation;
use rustc_errors::ErrorReported;
use rustc_hir::def::DefKind;
@@ -360,6 +361,15 @@
"it is undefined behavior to use this value",
|mut diag| {
diag.note(note_on_undefined_behavior_error());
+ diag.note(&format!(
+ "the raw bytes of the constant ({}",
+ display_allocation(
+ *ecx.tcx,
+ ecx.tcx
+ .global_alloc(mplace.ptr.assert_ptr().alloc_id)
+ .unwrap_memory()
+ )
+ ));
diag.emit();
},
))
diff --git a/compiler/rustc_mir/src/const_eval/fn_queries.rs b/compiler/rustc_mir/src/const_eval/fn_queries.rs
index 8c18dfc..40419a4 100644
--- a/compiler/rustc_mir/src/const_eval/fn_queries.rs
+++ b/compiler/rustc_mir/src/const_eval/fn_queries.rs
@@ -1,4 +1,3 @@
-use rustc_attr as attr;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::hir::map::blocks::FnLikeNode;
@@ -34,54 +33,6 @@
}
}
-/// Returns `true` if this function must conform to `min_const_fn`
-pub fn is_min_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
- // Bail out if the signature doesn't contain `const`
- if !tcx.is_const_fn_raw(def_id) {
- return false;
- }
-
- if tcx.features().staged_api {
- // In order for a libstd function to be considered min_const_fn
- // it needs to be stable and have no `rustc_const_unstable` attribute.
- match tcx.lookup_const_stability(def_id) {
- // `rustc_const_unstable` functions don't need to conform.
- Some(&attr::ConstStability { ref level, .. }) if level.is_unstable() => false,
- None => {
- if let Some(stab) = tcx.lookup_stability(def_id) {
- if stab.level.is_stable() {
- tcx.sess.delay_span_bug(
- tcx.def_span(def_id),
- "stable const functions must have either `rustc_const_stable` or \
- `rustc_const_unstable` attribute",
- );
- // While we errored above, because we don't know if we need to conform, we
- // err on the "safe" side and require min_const_fn.
- true
- } else {
- // Unstable functions need not conform to min_const_fn.
- false
- }
- } else {
- // Internal functions are forced to conform to min_const_fn.
- // Annotate the internal function with a const stability attribute if
- // you need to use unstable features.
- // Note: this is an arbitrary choice that does not affect stability or const
- // safety or anything, it just changes whether we need to annotate some
- // internal functions with `rustc_const_stable` or with `rustc_const_unstable`
- true
- }
- }
- // Everything else needs to conform, because it would be callable from
- // other `min_const_fn` functions.
- _ => true,
- }
- } else {
- // users enabling the `const_fn` feature gate can do what they want
- !tcx.features().const_fn
- }
-}
-
pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool {
let parent_id = tcx.hir().get_parent_did(hir_id);
if !parent_id.is_top_level_module() { is_const_impl_raw(tcx, parent_id) } else { false }
diff --git a/compiler/rustc_mir/src/const_eval/machine.rs b/compiler/rustc_mir/src/const_eval/machine.rs
index 61785a5..8e9148f 100644
--- a/compiler/rustc_mir/src/const_eval/machine.rs
+++ b/compiler/rustc_mir/src/const_eval/machine.rs
@@ -53,7 +53,7 @@
/// Extra machine state for CTFE, and the Machine instance
pub struct CompileTimeInterpreter<'mir, 'tcx> {
/// For now, the number of terminators that can be evaluated before we throw a resource
- /// exhuastion error.
+ /// exhaustion error.
///
/// Setting this to `0` disables the limit and allows the interpreter to run forever.
pub steps_remaining: usize,
diff --git a/compiler/rustc_mir/src/const_eval/mod.rs b/compiler/rustc_mir/src/const_eval/mod.rs
index 77531ae..3f14efc 100644
--- a/compiler/rustc_mir/src/const_eval/mod.rs
+++ b/compiler/rustc_mir/src/const_eval/mod.rs
@@ -110,7 +110,7 @@
let variant = ecx.read_discriminant(&place.into()).unwrap().1;
- branches(def.variants[variant].fields.len(), Some(variant))
+ branches(def.variants[variant].fields.len(), def.is_enum().then_some(variant))
}
ty::Never
diff --git a/compiler/rustc_mir/src/dataflow/framework/cursor.rs b/compiler/rustc_mir/src/dataflow/framework/cursor.rs
index 4942bed..c000e49 100644
--- a/compiler/rustc_mir/src/dataflow/framework/cursor.rs
+++ b/compiler/rustc_mir/src/dataflow/framework/cursor.rs
@@ -64,10 +64,6 @@
}
}
- pub fn body(&self) -> &'mir mir::Body<'tcx> {
- self.body
- }
-
/// Returns the underlying `Results`.
pub fn results(&self) -> &Results<'tcx, A> {
&self.results.borrow()
diff --git a/compiler/rustc_mir/src/dataflow/framework/lattice.rs b/compiler/rustc_mir/src/dataflow/framework/lattice.rs
index e7ef926..f937b31 100644
--- a/compiler/rustc_mir/src/dataflow/framework/lattice.rs
+++ b/compiler/rustc_mir/src/dataflow/framework/lattice.rs
@@ -40,6 +40,7 @@
use rustc_index::bit_set::BitSet;
use rustc_index::vec::{Idx, IndexVec};
+use std::iter;
/// A [partially ordered set][poset] that has a [least upper bound][lub] for any pair of elements
/// in the set.
@@ -110,7 +111,7 @@
assert_eq!(self.len(), other.len());
let mut changed = false;
- for (a, b) in self.iter_mut().zip(other.iter()) {
+ for (a, b) in iter::zip(self, other) {
changed |= a.join(b);
}
changed
@@ -122,7 +123,7 @@
assert_eq!(self.len(), other.len());
let mut changed = false;
- for (a, b) in self.iter_mut().zip(other.iter()) {
+ for (a, b) in iter::zip(self, other) {
changed |= a.meet(b);
}
changed
diff --git a/compiler/rustc_mir/src/dataflow/framework/mod.rs b/compiler/rustc_mir/src/dataflow/framework/mod.rs
index 3f7808c..344d7b9 100644
--- a/compiler/rustc_mir/src/dataflow/framework/mod.rs
+++ b/compiler/rustc_mir/src/dataflow/framework/mod.rs
@@ -510,7 +510,7 @@
}
}
- /// Returns `true` if the effect at `self` should be applied eariler than the effect at `other`
+ /// Returns `true` if the effect at `self` should be applied earlier than the effect at `other`
/// in forward order.
fn precedes_in_forward_order(self, other: Self) -> bool {
let ord = self
diff --git a/compiler/rustc_mir/src/dataflow/impls/borrows.rs b/compiler/rustc_mir/src/dataflow/impls/borrows.rs
index f24d0f0..c92cff1 100644
--- a/compiler/rustc_mir/src/dataflow/impls/borrows.rs
+++ b/compiler/rustc_mir/src/dataflow/impls/borrows.rs
@@ -11,6 +11,7 @@
use crate::dataflow::{self, fmt::DebugWithContext, GenKill};
use std::fmt;
+use std::iter;
rustc_index::newtype_index! {
pub struct BorrowIndex {
@@ -292,7 +293,7 @@
}
mir::StatementKind::LlvmInlineAsm(ref asm) => {
- for (output, kind) in asm.outputs.iter().zip(&asm.asm.outputs) {
+ for (output, kind) in iter::zip(&*asm.outputs, &asm.asm.outputs) {
if !kind.is_indirect && !kind.is_rw {
self.kill_borrows_on_place(trans, *output);
}
diff --git a/compiler/rustc_mir/src/dataflow/move_paths/builder.rs b/compiler/rustc_mir/src/dataflow/move_paths/builder.rs
index 1ddd81e..994b403 100644
--- a/compiler/rustc_mir/src/dataflow/move_paths/builder.rs
+++ b/compiler/rustc_mir/src/dataflow/move_paths/builder.rs
@@ -4,6 +4,7 @@
use rustc_middle::ty::{self, TyCtxt};
use smallvec::{smallvec, SmallVec};
+use std::iter;
use std::mem;
use super::abs_domain::Lift;
@@ -292,11 +293,11 @@
}
self.gather_rvalue(rval);
}
- StatementKind::FakeRead(_, place) => {
- self.create_move_path(**place);
+ StatementKind::FakeRead(box (_, place)) => {
+ self.create_move_path(*place);
}
StatementKind::LlvmInlineAsm(ref asm) => {
- for (output, kind) in asm.outputs.iter().zip(&asm.asm.outputs) {
+ for (output, kind) in iter::zip(&*asm.outputs, &asm.asm.outputs) {
if !kind.is_indirect {
self.gather_init(output.as_ref(), InitKind::Deep);
}
@@ -424,7 +425,7 @@
for op in operands {
match *op {
InlineAsmOperand::In { reg: _, ref value }
- | InlineAsmOperand::Const { ref value } => {
+ => {
self.gather_operand(value);
}
InlineAsmOperand::Out { reg: _, late: _, place, .. } => {
@@ -440,7 +441,8 @@
self.gather_init(out_place.as_ref(), InitKind::Deep);
}
}
- InlineAsmOperand::SymFn { value: _ }
+ InlineAsmOperand::Const { value: _ }
+ | InlineAsmOperand::SymFn { value: _ }
| InlineAsmOperand::SymStatic { def_id: _ } => {}
}
}
diff --git a/compiler/rustc_mir/src/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs
index 149a9f8..2d83d6c 100644
--- a/compiler/rustc_mir/src/interpret/eval_context.rs
+++ b/compiler/rustc_mir/src/interpret/eval_context.rs
@@ -232,6 +232,8 @@
/// this frame (can happen e.g. during frame initialization, and during unwinding on
/// frames without cleanup code).
/// We basically abuse `Result` as `Either`.
+ ///
+ /// Used by priroda.
pub fn current_loc(&self) -> Result<mir::Location, Span> {
self.loc
}
@@ -460,11 +462,6 @@
}
#[inline]
- pub fn type_is_sized(&self, ty: Ty<'tcx>) -> bool {
- ty.is_sized(self.tcx, self.param_env)
- }
-
- #[inline]
pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool {
ty.is_freeze(self.tcx, self.param_env)
}
@@ -527,6 +524,7 @@
}
}
+ #[inline(always)]
pub fn layout_of_local(
&self,
frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>,
diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs
index 25c3c2c..d74ef66 100644
--- a/compiler/rustc_mir/src/interpret/intrinsics.rs
+++ b/compiler/rustc_mir/src/interpret/intrinsics.rs
@@ -171,8 +171,7 @@
};
let val =
self.tcx.const_eval_global_id(self.param_env, gid, Some(self.tcx.span))?;
- let const_ = ty::Const { val: ty::ConstKind::Value(val), ty };
- let val = self.const_to_op(&const_, None)?;
+ let val = self.const_val_to_op(val, ty, Some(dest.layout))?;
self.copy_op(&val, dest)?;
}
diff --git a/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs b/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs
index e1ec4cc..ae5e78e 100644
--- a/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs
+++ b/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs
@@ -74,7 +74,7 @@
fn print_dyn_existential(
mut self,
- predicates: &'tcx ty::List<ty::Binder<ty::ExistentialPredicate<'tcx>>>,
+ predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
) -> Result<Self::DynExistential, Self::Error> {
let mut first = true;
for p in predicates {
diff --git a/compiler/rustc_mir/src/interpret/operand.rs b/compiler/rustc_mir/src/interpret/operand.rs
index 2893349..e5bc932 100644
--- a/compiler/rustc_mir/src/interpret/operand.rs
+++ b/compiler/rustc_mir/src/interpret/operand.rs
@@ -77,14 +77,6 @@
pub fn to_scalar(self) -> InterpResult<'tcx, Scalar<Tag>> {
self.to_scalar_or_uninit().check_init()
}
-
- #[inline]
- pub fn to_scalar_pair(self) -> InterpResult<'tcx, (Scalar<Tag>, Scalar<Tag>)> {
- match self {
- Immediate::Scalar(..) => bug!("Got a thin pointer where a scalar pair was expected"),
- Immediate::ScalarPair(a, b) => Ok((a.check_init()?, b.check_init()?)),
- }
- }
}
// ScalarPair needs a type to interpret, so we often have an immediate and a type together
@@ -233,7 +225,7 @@
}
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
- /// Normalice `place.ptr` to a `Pointer` if this is a place and not a ZST.
+ /// Normalize `place.ptr` to a `Pointer` if this is a place and not a ZST.
/// Can be helpful to avoid lots of `force_ptr` calls later, if this place is used a lot.
#[inline]
pub fn force_op_ptr(
@@ -560,7 +552,7 @@
match val.val {
ty::ConstKind::Param(_) | ty::ConstKind::Bound(..) => throw_inval!(TooGeneric),
ty::ConstKind::Error(_) => throw_inval!(AlreadyReported(ErrorReported)),
- ty::ConstKind::Unevaluated(def, substs, promoted) => {
+ ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => {
let instance = self.resolve(def, substs)?;
Ok(self.eval_to_allocation(GlobalId { instance, promoted })?.into())
}
@@ -578,7 +570,7 @@
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
match val {
mir::ConstantKind::Ty(ct) => self.const_to_op(ct, layout),
- mir::ConstantKind::Val(val, ty) => self.const_val_to_op(*val, ty, None),
+ mir::ConstantKind::Val(val, ty) => self.const_val_to_op(*val, ty, layout),
}
}
diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs
index bf4eeb4..f9adc27 100644
--- a/compiler/rustc_mir/src/lib.rs
+++ b/compiler/rustc_mir/src/lib.rs
@@ -11,12 +11,12 @@
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
-#![feature(const_fn)]
#![feature(const_panic)]
#![feature(crate_visibility_modifier)]
#![feature(decl_macro)]
#![feature(exact_size_is_empty)]
#![feature(exhaustive_patterns)]
+#![feature(iter_zip)]
#![feature(never_type)]
#![feature(map_try_insert)]
#![feature(min_specialization)]
@@ -26,7 +26,7 @@
#![feature(stmt_expr_attributes)]
#![feature(trait_alias)]
#![feature(option_get_or_insert_default)]
-#![feature(or_patterns)]
+#![cfg_attr(bootstrap, feature(or_patterns))]
#![feature(once_cell)]
#![feature(control_flow_enum)]
#![recursion_limit = "256"]
diff --git a/compiler/rustc_mir/src/monomorphize/collector.rs b/compiler/rustc_mir/src/monomorphize/collector.rs
index 911224d..fdefc89 100644
--- a/compiler/rustc_mir/src/monomorphize/collector.rs
+++ b/compiler/rustc_mir/src/monomorphize/collector.rs
@@ -59,11 +59,15 @@
//!
//! ### Discovering roots
//!
-//! The roots of the mono item graph correspond to the non-generic
+//! The roots of the mono item graph correspond to the public non-generic
//! syntactic items in the source code. We find them by walking the HIR of the
-//! crate, and whenever we hit upon a function, method, or static item, we
-//! create a mono item consisting of the items DefId and, since we only
-//! consider non-generic items, an empty type-substitution set.
+//! crate, and whenever we hit upon a public function, method, or static item,
+//! we create a mono item consisting of the items DefId and, since we only
+//! consider non-generic items, an empty type-substitution set. (In eager
+//! collection mode, during incremental compilation, all non-generic functions
+//! are considered as roots, as well as when the `-Clink-dead-code` option is
+//! specified. Functions marked `#[no_mangle]` and functions called by inlinable
+//! functions also always act as roots.)
//!
//! ### Finding neighbor nodes
//! Given a mono item node, we can discover neighbors by inspecting its
@@ -184,7 +188,6 @@
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::lang_items::LangItem;
use rustc_index::bit_set::GrowableBitSet;
-use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir::interpret::{AllocId, ConstValue};
use rustc_middle::mir::interpret::{ErrorHandled, GlobalAlloc, Scalar};
use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
@@ -193,8 +196,11 @@
use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCast};
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
use rustc_middle::ty::{self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::{middle::codegen_fn_attrs::CodegenFnAttrFlags, mir::visit::TyContext};
use rustc_session::config::EntryFnType;
+use rustc_session::lint::builtin::LARGE_ASSIGNMENTS;
use rustc_span::source_map::{dummy_spanned, respan, Span, Spanned, DUMMY_SP};
+use rustc_target::abi::Size;
use smallvec::SmallVec;
use std::iter;
use std::ops::Range;
@@ -638,6 +644,35 @@
self.super_rvalue(rvalue, location);
}
+ /// This does not walk the constant, as it has been handled entirely here and trying
+ /// to walk it would attempt to evaluate the `ty::Const` inside, which doesn't necessarily
+ /// work, as some constants cannot be represented in the type system.
+ fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: Location) {
+ let literal = self.monomorphize(constant.literal);
+ let val = match literal {
+ mir::ConstantKind::Val(val, _) => val,
+ mir::ConstantKind::Ty(ct) => match ct.val {
+ ty::ConstKind::Value(val) => val,
+ ty::ConstKind::Unevaluated(ct) => {
+ let param_env = ty::ParamEnv::reveal_all();
+ match self.tcx.const_eval_resolve(param_env, ct, None) {
+ // The `monomorphize` call should have evaluated that constant already.
+ Ok(val) => val,
+ Err(ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted) => return,
+ Err(ErrorHandled::TooGeneric) => span_bug!(
+ self.body.source_info(location).span,
+ "collection encountered polymorphic constant: {:?}",
+ literal
+ ),
+ }
+ }
+ _ => return,
+ },
+ };
+ collect_const_value(self.tcx, val, self.output);
+ self.visit_ty(literal.ty(), TyContext::Location(location));
+ }
+
fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, location: Location) {
debug!("visiting const {:?} @ {:?}", *constant, location);
@@ -646,9 +681,15 @@
match substituted_constant.val {
ty::ConstKind::Value(val) => collect_const_value(self.tcx, val, self.output),
- ty::ConstKind::Unevaluated(def, substs, promoted) => {
- match self.tcx.const_eval_resolve(param_env, def, substs, promoted, None) {
- Ok(val) => collect_const_value(self.tcx, val, self.output),
+ ty::ConstKind::Unevaluated(unevaluated) => {
+ match self.tcx.const_eval_resolve(param_env, unevaluated, None) {
+ // The `monomorphize` call should have evaluated that constant already.
+ Ok(val) => span_bug!(
+ self.body.source_info(location).span,
+ "collection encountered the unevaluated constant {} which evaluated to {:?}",
+ substituted_constant,
+ val
+ ),
Err(ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted) => {}
Err(ErrorHandled::TooGeneric) => span_bug!(
self.body.source_info(location).span,
@@ -714,6 +755,46 @@
self.super_terminator(terminator, location);
}
+ fn visit_operand(&mut self, operand: &mir::Operand<'tcx>, location: Location) {
+ self.super_operand(operand, location);
+ let limit = self.tcx.sess.move_size_limit();
+ if limit == 0 {
+ return;
+ }
+ let limit = Size::from_bytes(limit);
+ let ty = operand.ty(self.body, self.tcx);
+ let ty = self.monomorphize(ty);
+ let layout = self.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty));
+ if let Ok(layout) = layout {
+ if layout.size > limit {
+ debug!(?layout);
+ let source_info = self.body.source_info(location);
+ debug!(?source_info);
+ let lint_root = source_info.scope.lint_root(&self.body.source_scopes);
+ debug!(?lint_root);
+ let lint_root = match lint_root {
+ Some(lint_root) => lint_root,
+ // This happens when the issue is in a function from a foreign crate that
+ // we monomorphized in the current crate. We can't get a `HirId` for things
+ // in other crates.
+ // FIXME: Find out where to report the lint on. Maybe simply crate-level lint root
+ // but correct span? This would make the lint at least accept crate-level lint attributes.
+ None => return,
+ };
+ self.tcx.struct_span_lint_hir(
+ LARGE_ASSIGNMENTS,
+ lint_root,
+ source_info.span,
+ |lint| {
+ let mut err = lint.build(&format!("moving {} bytes", layout.size.bytes()));
+ err.span_label(source_info.span, "value moved from here");
+ err.emit()
+ },
+ );
+ }
+ }
+ }
+
fn visit_local(
&mut self,
_place_local: &Local,
@@ -985,7 +1066,7 @@
tcx: TyCtxt<'tcx>,
mode: MonoItemCollectionMode,
output: &'a mut Vec<Spanned<MonoItem<'tcx>>>,
- entry_fn: Option<(LocalDefId, EntryFnType)>,
+ entry_fn: Option<(DefId, EntryFnType)>,
}
impl ItemLikeVisitor<'v> for RootCollector<'_, 'v> {
@@ -1073,7 +1154,7 @@
&& match self.mode {
MonoItemCollectionMode::Eager => true,
MonoItemCollectionMode::Lazy => {
- self.entry_fn.map(|(id, _)| id) == Some(def_id)
+ self.entry_fn.and_then(|(id, _)| id.as_local()) == Some(def_id)
|| self.tcx.is_reachable_non_generic(def_id)
|| self
.tcx
@@ -1175,7 +1256,8 @@
let substs =
InternalSubsts::for_item(tcx, method.def_id, |param, _| match param.kind {
GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
- GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => {
+ GenericParamDefKind::Type { .. }
+ | GenericParamDefKind::Const { .. } => {
trait_ref.substs[param.index as usize]
}
});
diff --git a/compiler/rustc_mir/src/monomorphize/mod.rs b/compiler/rustc_mir/src/monomorphize/mod.rs
index d2586f0..9ca4b66 100644
--- a/compiler/rustc_mir/src/monomorphize/mod.rs
+++ b/compiler/rustc_mir/src/monomorphize/mod.rs
@@ -8,14 +8,14 @@
pub mod partitioning;
pub mod polymorphize;
-pub fn custom_coerce_unsize_info<'tcx>(
+fn custom_coerce_unsize_info<'tcx>(
tcx: TyCtxt<'tcx>,
source_ty: Ty<'tcx>,
target_ty: Ty<'tcx>,
) -> CustomCoerceUnsized {
let def_id = tcx.require_lang_item(LangItem::CoerceUnsized, None);
- let trait_ref = ty::Binder::bind(ty::TraitRef {
+ let trait_ref = ty::Binder::dummy(ty::TraitRef {
def_id,
substs: tcx.mk_substs_trait(source_ty, &[target_ty.into()]),
});
diff --git a/compiler/rustc_mir/src/monomorphize/polymorphize.rs b/compiler/rustc_mir/src/monomorphize/polymorphize.rs
index 05b0e3a..30e758c7 100644
--- a/compiler/rustc_mir/src/monomorphize/polymorphize.rs
+++ b/compiler/rustc_mir/src/monomorphize/polymorphize.rs
@@ -299,7 +299,7 @@
self.unused_parameters.clear(param.index);
ControlFlow::CONTINUE
}
- ty::ConstKind::Unevaluated(def, _, Some(p))
+ ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs: _, promoted: Some(p)})
// Avoid considering `T` unused when constants are of the form:
// `<Self as Foo<T>>::foo::promoted[p]`
if self.def_id == def.did && !self.tcx.generics_of(def.did).has_self =>
@@ -310,10 +310,10 @@
self.visit_body(&promoted[p]);
ControlFlow::CONTINUE
}
- ty::ConstKind::Unevaluated(def, unevaluated_substs, None)
+ ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted: None })
if self.tcx.def_kind(def.did) == DefKind::AnonConst =>
{
- self.visit_child_body(def.did, unevaluated_substs);
+ self.visit_child_body(def.did, substs);
ControlFlow::CONTINUE
}
_ => c.super_visit_with(self),
diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs
index a18c1f7..ffeaaf6 100644
--- a/compiler/rustc_mir/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs
@@ -540,12 +540,17 @@
pub struct UnsizingCast;
impl NonConstOp for UnsizingCast {
fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
- mcf_status_in_item(ccx)
+ if ccx.const_kind() != hir::ConstContext::ConstFn {
+ Status::Allowed
+ } else {
+ Status::Unstable(sym::const_fn_unsize)
+ }
}
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
- mcf_build_error(
- ccx,
+ feature_err(
+ &ccx.tcx.sess.parse_sess,
+ sym::const_fn_unsize,
span,
"unsizing casts to types besides slices are not allowed in const fn",
)
@@ -642,12 +647,17 @@
}
fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
- mcf_status_in_item(ccx)
+ if ccx.const_kind() != hir::ConstContext::ConstFn {
+ Status::Allowed
+ } else {
+ Status::Unstable(sym::const_fn_trait_bound)
+ }
}
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
- mcf_build_error(
- ccx,
+ feature_err(
+ &ccx.tcx.sess.parse_sess,
+ sym::const_fn_trait_bound,
span,
"trait bounds other than `Sized` on const fn parameters are unstable",
)
@@ -672,21 +682,3 @@
}
}
}
-
-fn mcf_status_in_item(ccx: &ConstCx<'_, '_>) -> Status {
- if ccx.const_kind() != hir::ConstContext::ConstFn {
- Status::Allowed
- } else {
- Status::Unstable(sym::const_fn)
- }
-}
-
-fn mcf_build_error(ccx: &ConstCx<'_, 'tcx>, span: Span, msg: &str) -> DiagnosticBuilder<'tcx> {
- let mut err = struct_span_err!(ccx.tcx.sess, span, E0723, "{}", msg);
- err.note(
- "see issue #57563 <https://github.com/rust-lang/rust/issues/57563> \
- for more information",
- );
- err.help("add `#![feature(const_fn)]` to the crate attributes to enable");
- err
-}
diff --git a/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs b/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs
index 1a2d932..057092b 100644
--- a/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs
@@ -79,7 +79,9 @@
mir::TerminatorKind::Drop { place: dropped_place, .. } => {
let dropped_ty = dropped_place.ty(self.body, self.tcx).ty;
if !NeedsDrop::in_any_value_of_ty(self.ccx, dropped_ty) {
- return;
+ bug!(
+ "Drop elaboration left behind a Drop for a type that does not need dropping"
+ );
}
if dropped_place.is_indirect() {
@@ -87,6 +89,10 @@
return;
}
+ // Drop elaboration is not precise enough to accept code like
+ // `src/test/ui/consts/control-flow/drop-pass.rs`; e.g., when an `Option<Vec<T>>` is
+ // initialized with `None` and never changed, it still emits drop glue.
+ // Hence we additionally check the qualifs here to allow more code to pass.
if self.qualifs.needs_drop(self.ccx, dropped_place.local, location) {
// Use the span where the dropped local was declared for the error.
let span = self.body.local_decls[dropped_place.local].source_info.span;
diff --git a/compiler/rustc_mir/src/transform/check_consts/qualifs.rs b/compiler/rustc_mir/src/transform/check_consts/qualifs.rs
index 748f65c..ac8c748 100644
--- a/compiler/rustc_mir/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/qualifs.rs
@@ -29,11 +29,11 @@
/// Normally, we would determine what qualifications apply to each type and error when an illegal
/// operation is performed on such a type. However, this was found to be too imprecise, especially
/// in the presence of `enum`s. If only a single variant of an enum has a certain qualification, we
-/// needn't reject code unless it actually constructs and operates on the qualifed variant.
+/// needn't reject code unless it actually constructs and operates on the qualified variant.
///
/// To accomplish this, const-checking and promotion use a value-based analysis (as opposed to a
/// type-based one). Qualifications propagate structurally across variables: If a local (or a
-/// projection of a local) is assigned a qualifed value, that local itself becomes qualifed.
+/// projection of a local) is assigned a qualified value, that local itself becomes qualified.
pub trait Qualif {
/// The name of the file used to debug the dataflow analysis that computes this qualif.
const ANALYSIS_NAME: &'static str;
@@ -247,7 +247,7 @@
// Check the qualifs of the value of `const` items.
if let Some(ct) = constant.literal.const_for_ty() {
- if let ty::ConstKind::Unevaluated(def, _, promoted) = ct.val {
+ if let ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs: _, promoted }) = ct.val {
assert!(promoted.is_none());
// Don't peek inside trait associated constants.
if cx.tcx.trait_of_item(def.did).is_none() {
diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs
index 1ad7b8f..63fc66f 100644
--- a/compiler/rustc_mir/src/transform/check_consts/validation.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs
@@ -1,6 +1,6 @@
//! The `Visitor` responsible for actually checking a `mir::Body` for invalid operations.
-use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorReported};
+use rustc_errors::{Applicability, Diagnostic, ErrorReported};
use rustc_hir::def_id::DefId;
use rustc_hir::{self as hir, HirId, LangItem};
use rustc_index::bit_set::BitSet;
@@ -234,13 +234,11 @@
if self.is_const_stable_const_fn() {
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
if crate::const_eval::is_parent_const_impl_raw(tcx, hir_id) {
- struct_span_err!(
- self.ccx.tcx.sess,
- self.span,
- E0723,
- "trait methods cannot be stable const fn"
- )
- .emit();
+ self.ccx
+ .tcx
+ .sess
+ .struct_span_err(self.span, "trait methods cannot be stable const fn")
+ .emit();
}
}
@@ -428,7 +426,7 @@
ty::PredicateKind::Subtype(_) => {
bug!("subtype predicate on function: {:#?}", predicate)
}
- ty::PredicateKind::Trait(pred, constness) => {
+ ty::PredicateKind::Trait(pred, _constness) => {
if Some(pred.def_id()) == tcx.lang_items().sized_trait() {
continue;
}
@@ -442,16 +440,7 @@
// arguments when determining importance.
let kind = LocalKind::Arg;
- if constness == hir::Constness::Const {
- self.check_op_spanned(ops::ty::TraitBound(kind), span);
- } else if !tcx.features().const_fn
- || self.ccx.is_const_stable_const_fn()
- {
- // HACK: We shouldn't need the conditional above, but trait
- // bounds on containing impl blocks are wrongly being marked as
- // "not-const".
- self.check_op_spanned(ops::ty::TraitBound(kind), span);
- }
+ self.check_op_spanned(ops::ty::TraitBound(kind), span);
}
// other kinds of bounds are either tautologies
// or cause errors in other passes
@@ -850,9 +839,12 @@
let obligation = Obligation::new(
ObligationCause::dummy(),
param_env,
- Binder::bind(TraitPredicate {
- trait_ref: TraitRef::from_method(tcx, trait_id, substs),
- }),
+ Binder::bind(
+ TraitPredicate {
+ trait_ref: TraitRef::from_method(tcx, trait_id, substs),
+ },
+ tcx,
+ ),
);
let implsrc = tcx.infer_ctxt().enter(|infcx| {
diff --git a/compiler/rustc_mir/src/transform/check_packed_ref.rs b/compiler/rustc_mir/src/transform/check_packed_ref.rs
index ee88daa..13b7221 100644
--- a/compiler/rustc_mir/src/transform/check_packed_ref.rs
+++ b/compiler/rustc_mir/src/transform/check_packed_ref.rs
@@ -1,11 +1,18 @@
+use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::mir::visit::{PlaceContext, Visitor};
use rustc_middle::mir::*;
+use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, TyCtxt};
use rustc_session::lint::builtin::UNALIGNED_REFERENCES;
+use rustc_span::symbol::sym;
use crate::transform::MirPass;
use crate::util;
+pub(crate) fn provide(providers: &mut Providers) {
+ *providers = Providers { unsafe_derive_on_repr_packed, ..*providers };
+}
+
pub struct CheckPackedRef;
impl<'tcx> MirPass<'tcx> for CheckPackedRef {
@@ -24,6 +31,41 @@
source_info: SourceInfo,
}
+fn unsafe_derive_on_repr_packed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
+ let lint_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+
+ tcx.struct_span_lint_hir(UNALIGNED_REFERENCES, lint_hir_id, tcx.def_span(def_id), |lint| {
+ // FIXME: when we make this a hard error, this should have its
+ // own error code.
+ let message = if tcx.generics_of(def_id).own_requires_monomorphization() {
+ "`#[derive]` can't be used on a `#[repr(packed)]` struct with \
+ type or const parameters (error E0133)"
+ .to_string()
+ } else {
+ "`#[derive]` can't be used on a `#[repr(packed)]` struct that \
+ does not derive Copy (error E0133)"
+ .to_string()
+ };
+ lint.build(&message).emit()
+ });
+}
+
+fn builtin_derive_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
+ debug!("builtin_derive_def_id({:?})", def_id);
+ if let Some(impl_def_id) = tcx.impl_of_method(def_id) {
+ if tcx.has_attr(impl_def_id, sym::automatically_derived) {
+ debug!("builtin_derive_def_id({:?}) - is {:?}", def_id, impl_def_id);
+ Some(impl_def_id)
+ } else {
+ debug!("builtin_derive_def_id({:?}) - not automatically derived", def_id);
+ None
+ }
+ } else {
+ debug!("builtin_derive_def_id({:?}) - not a method", def_id);
+ None
+ }
+}
+
impl<'a, 'tcx> Visitor<'tcx> for PackedRefChecker<'a, 'tcx> {
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
// Make sure we know where in the MIR we are.
@@ -40,26 +82,33 @@
fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) {
if context.is_borrow() {
if util::is_disaligned(self.tcx, self.body, self.param_env, *place) {
- let source_info = self.source_info;
- let lint_root = self.body.source_scopes[source_info.scope]
- .local_data
- .as_ref()
- .assert_crate_local()
- .lint_root;
- self.tcx.struct_span_lint_hir(
- UNALIGNED_REFERENCES,
- lint_root,
- source_info.span,
- |lint| {
- lint.build("reference to packed field is unaligned")
- .note(
- "fields of packed structs are not properly aligned, and creating \
- a misaligned reference is undefined behavior (even if that \
- reference is never dereferenced)",
- )
- .emit()
- },
- );
+ let def_id = self.body.source.instance.def_id();
+ if let Some(impl_def_id) = builtin_derive_def_id(self.tcx, def_id) {
+ // If a method is defined in the local crate,
+ // the impl containing that method should also be.
+ self.tcx.ensure().unsafe_derive_on_repr_packed(impl_def_id.expect_local());
+ } else {
+ let source_info = self.source_info;
+ let lint_root = self.body.source_scopes[source_info.scope]
+ .local_data
+ .as_ref()
+ .assert_crate_local()
+ .lint_root;
+ self.tcx.struct_span_lint_hir(
+ UNALIGNED_REFERENCES,
+ lint_root,
+ source_info.span,
+ |lint| {
+ lint.build("reference to packed field is unaligned")
+ .note(
+ "fields of packed structs are not properly aligned, and creating \
+ a misaligned reference is undefined behavior (even if that \
+ reference is never dereferenced)",
+ )
+ .emit()
+ },
+ );
+ }
}
}
}
diff --git a/compiler/rustc_mir/src/transform/check_unsafety.rs b/compiler/rustc_mir/src/transform/check_unsafety.rs
index 532d201..955be8c 100644
--- a/compiler/rustc_mir/src/transform/check_unsafety.rs
+++ b/compiler/rustc_mir/src/transform/check_unsafety.rs
@@ -10,20 +10,15 @@
use rustc_middle::ty::cast::CastTy;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, TyCtxt};
-use rustc_session::lint::builtin::{SAFE_PACKED_BORROWS, UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE};
+use rustc_session::lint::builtin::{UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE};
use rustc_session::lint::Level;
-use rustc_span::symbol::sym;
use std::ops::Bound;
-use crate::const_eval::is_min_const_fn;
-use crate::util;
-
pub struct UnsafetyChecker<'a, 'tcx> {
body: &'a Body<'tcx>,
body_did: LocalDefId,
const_context: bool,
- min_const_fn: bool,
violations: Vec<UnsafetyViolation>,
source_info: SourceInfo,
tcx: TyCtxt<'tcx>,
@@ -36,21 +31,15 @@
impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
fn new(
const_context: bool,
- min_const_fn: bool,
body: &'a Body<'tcx>,
body_did: LocalDefId,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> Self {
- // sanity check
- if min_const_fn {
- assert!(const_context);
- }
Self {
body,
body_did,
const_context,
- min_const_fn,
violations: vec![],
source_info: SourceInfo::outermost(body.span),
tcx,
@@ -86,7 +75,7 @@
let sig = func_ty.fn_sig(self.tcx);
if let hir::Unsafety::Unsafe = sig.unsafety() {
self.require_unsafe(
- UnsafetyViolationKind::GeneralAndConstFn,
+ UnsafetyViolationKind::General,
UnsafetyViolationDetails::CallToUnsafeFunction,
)
}
@@ -136,7 +125,7 @@
match self.tcx.layout_scalar_valid_range(def.did) {
(Bound::Unbounded, Bound::Unbounded) => {}
_ => self.require_unsafe(
- UnsafetyViolationKind::GeneralAndConstFn,
+ UnsafetyViolationKind::General,
UnsafetyViolationDetails::InitializingTypeWith,
),
}
@@ -182,18 +171,6 @@
self.check_mut_borrowing_layout_constrained_field(*place, context.is_mutating_use());
}
- // Check for borrows to packed fields.
- // `is_disaligned` already traverses the place to consider all projections after the last
- // `Deref`, so this only needs to be called once at the top level.
- if context.is_borrow() {
- if util::is_disaligned(self.tcx, self.body, self.param_env, *place) {
- self.require_unsafe(
- UnsafetyViolationKind::BorrowPacked,
- UnsafetyViolationDetails::BorrowOfPackedField,
- );
- }
- }
-
// Some checks below need the extra metainfo of the local declaration.
let decl = &self.body.local_decls[place.local];
@@ -227,7 +204,7 @@
let base_ty = base.ty(self.body, self.tcx).ty;
if base_ty.is_unsafe_ptr() {
self.require_unsafe(
- UnsafetyViolationKind::GeneralAndConstFn,
+ UnsafetyViolationKind::General,
UnsafetyViolationDetails::DerefOfRawPointer,
)
}
@@ -272,7 +249,7 @@
);
if !nodrop {
self.require_unsafe(
- UnsafetyViolationKind::GeneralAndConstFn,
+ UnsafetyViolationKind::General,
UnsafetyViolationDetails::AssignToDroppingUnionField,
);
} else {
@@ -280,7 +257,7 @@
}
} else {
self.require_unsafe(
- UnsafetyViolationKind::GeneralAndConstFn,
+ UnsafetyViolationKind::General,
UnsafetyViolationDetails::AccessToUnionField,
)
}
@@ -291,6 +268,9 @@
impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
fn require_unsafe(&mut self, kind: UnsafetyViolationKind, details: UnsafetyViolationDetails) {
+ // Violations can turn out to be `UnsafeFn` during analysis, but they should not start out as such.
+ assert_ne!(kind, UnsafetyViolationKind::UnsafeFn);
+
let source_info = self.source_info;
let lint_root = self.body.source_scopes[self.source_info.scope]
.local_data
@@ -317,25 +297,14 @@
// `unsafe` blocks are required in safe code
Safety::Safe => {
for violation in violations {
- let mut violation = *violation;
match violation.kind {
- UnsafetyViolationKind::GeneralAndConstFn
- | UnsafetyViolationKind::General => {}
- UnsafetyViolationKind::BorrowPacked => {
- if self.min_const_fn {
- // const fns don't need to be backwards compatible and can
- // emit these violations as a hard error instead of a backwards
- // compat lint
- violation.kind = UnsafetyViolationKind::General;
- }
- }
- UnsafetyViolationKind::UnsafeFn
- | UnsafetyViolationKind::UnsafeFnBorrowPacked => {
+ UnsafetyViolationKind::General => {}
+ UnsafetyViolationKind::UnsafeFn => {
bug!("`UnsafetyViolationKind::UnsafeFn` in an `Safe` context")
}
}
- if !self.violations.contains(&violation) {
- self.violations.push(violation)
+ if !self.violations.contains(violation) {
+ self.violations.push(*violation)
}
}
false
@@ -345,11 +314,7 @@
for violation in violations {
let mut violation = *violation;
- if violation.kind == UnsafetyViolationKind::BorrowPacked {
- violation.kind = UnsafetyViolationKind::UnsafeFnBorrowPacked;
- } else {
- violation.kind = UnsafetyViolationKind::UnsafeFn;
- }
+ violation.kind = UnsafetyViolationKind::UnsafeFn;
if !self.violations.contains(&violation) {
self.violations.push(violation)
}
@@ -362,31 +327,6 @@
if !violations.is_empty() {
self.used_unsafe.insert(hir_id);
}
- // only some unsafety is allowed in const fn
- if self.min_const_fn {
- for violation in violations {
- match violation.kind {
- // these unsafe things are stable in const fn
- UnsafetyViolationKind::GeneralAndConstFn => {}
- // these things are forbidden in const fns
- UnsafetyViolationKind::General
- | UnsafetyViolationKind::BorrowPacked => {
- let mut violation = *violation;
- // const fns don't need to be backwards compatible and can
- // emit these violations as a hard error instead of a backwards
- // compat lint
- violation.kind = UnsafetyViolationKind::General;
- if !self.violations.contains(&violation) {
- self.violations.push(violation)
- }
- }
- UnsafetyViolationKind::UnsafeFn
- | UnsafetyViolationKind::UnsafeFnBorrowPacked => bug!(
- "`UnsafetyViolationKind::UnsafeFn` in an `ExplicitUnsafe` context"
- ),
- }
- }
- }
true
}
};
@@ -424,7 +364,7 @@
} else {
continue;
};
- self.require_unsafe(UnsafetyViolationKind::GeneralAndConstFn, details);
+ self.require_unsafe(UnsafetyViolationKind::General, details);
}
}
}
@@ -442,7 +382,7 @@
// Is `callee_features` a subset of `calling_features`?
if !callee_features.iter().all(|feature| self_features.contains(feature)) {
self.require_unsafe(
- UnsafetyViolationKind::GeneralAndConstFn,
+ UnsafetyViolationKind::General,
UnsafetyViolationDetails::CallToFunctionWith,
)
}
@@ -464,7 +404,6 @@
ty::WithOptConstParam { did, const_param_did: Some(param_did) },
)
},
- unsafe_derive_on_repr_packed,
..*providers
};
}
@@ -525,15 +464,12 @@
let param_env = tcx.param_env(def.did);
let id = tcx.hir().local_def_id_to_hir_id(def.did);
- let (const_context, min_const_fn) = match tcx.hir().body_owner_kind(id) {
- hir::BodyOwnerKind::Closure => (false, false),
- hir::BodyOwnerKind::Fn => {
- (tcx.is_const_fn_raw(def.did.to_def_id()), is_min_const_fn(tcx, def.did.to_def_id()))
- }
- hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => (true, false),
+ let const_context = match tcx.hir().body_owner_kind(id) {
+ hir::BodyOwnerKind::Closure => false,
+ hir::BodyOwnerKind::Fn => tcx.is_const_fn_raw(def.did.to_def_id()),
+ hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => true,
};
- let mut checker =
- UnsafetyChecker::new(const_context, min_const_fn, body, def.did, tcx, param_env);
+ let mut checker = UnsafetyChecker::new(const_context, body, def.did, tcx, param_env);
checker.visit_body(&body);
check_unused_unsafe(tcx, def.did, &checker.used_unsafe, &mut checker.inherited_blocks);
@@ -544,25 +480,6 @@
})
}
-fn unsafe_derive_on_repr_packed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
- let lint_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-
- tcx.struct_span_lint_hir(SAFE_PACKED_BORROWS, lint_hir_id, tcx.def_span(def_id), |lint| {
- // FIXME: when we make this a hard error, this should have its
- // own error code.
- let message = if tcx.generics_of(def_id).own_requires_monomorphization() {
- "`#[derive]` can't be used on a `#[repr(packed)]` struct with \
- type or const parameters (error E0133)"
- .to_string()
- } else {
- "`#[derive]` can't be used on a `#[repr(packed)]` struct that \
- does not derive Copy (error E0133)"
- .to_string()
- };
- lint.build(&message).emit()
- });
-}
-
/// Returns the `HirId` for an enclosing scope that is also `unsafe`.
fn is_enclosed(
tcx: TyCtxt<'_>,
@@ -609,22 +526,6 @@
});
}
-fn builtin_derive_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
- debug!("builtin_derive_def_id({:?})", def_id);
- if let Some(impl_def_id) = tcx.impl_of_method(def_id) {
- if tcx.has_attr(impl_def_id, sym::automatically_derived) {
- debug!("builtin_derive_def_id({:?}) - is {:?}", def_id, impl_def_id);
- Some(impl_def_id)
- } else {
- debug!("builtin_derive_def_id({:?}) - not automatically derived", def_id);
- None
- }
- } else {
- debug!("builtin_derive_def_id({:?}) - not a method", def_id);
- None
- }
-}
-
pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
debug!("check_unsafety({:?})", def_id);
@@ -643,7 +544,7 @@
if unsafe_op_in_unsafe_fn_allowed(tcx, lint_root) { " function or" } else { "" };
match kind {
- UnsafetyViolationKind::GeneralAndConstFn | UnsafetyViolationKind::General => {
+ UnsafetyViolationKind::General => {
// once
struct_span_err!(
tcx.sess,
@@ -657,27 +558,6 @@
.note(note)
.emit();
}
- UnsafetyViolationKind::BorrowPacked => {
- if let Some(impl_def_id) = builtin_derive_def_id(tcx, def_id.to_def_id()) {
- // If a method is defined in the local crate,
- // the impl containing that method should also be.
- tcx.ensure().unsafe_derive_on_repr_packed(impl_def_id.expect_local());
- } else {
- tcx.struct_span_lint_hir(
- SAFE_PACKED_BORROWS,
- lint_root,
- source_info.span,
- |lint| {
- lint.build(&format!(
- "{} is unsafe and requires unsafe{} block (error E0133)",
- description, unsafe_fn_msg,
- ))
- .note(note)
- .emit()
- },
- )
- }
- }
UnsafetyViolationKind::UnsafeFn => tcx.struct_span_lint_hir(
UNSAFE_OP_IN_UNSAFE_FN,
lint_root,
@@ -692,35 +572,6 @@
.emit();
},
),
- UnsafetyViolationKind::UnsafeFnBorrowPacked => {
- // When `unsafe_op_in_unsafe_fn` is disallowed, the behavior of safe and unsafe functions
- // should be the same in terms of warnings and errors. Therefore, with `#[warn(safe_packed_borrows)]`,
- // a safe packed borrow should emit a warning *but not an error* in an unsafe function,
- // just like in a safe function, even if `unsafe_op_in_unsafe_fn` is `deny`.
- //
- // Also, `#[warn(unsafe_op_in_unsafe_fn)]` can't cause any new errors. Therefore, with
- // `#[deny(safe_packed_borrows)]` and `#[warn(unsafe_op_in_unsafe_fn)]`, a packed borrow
- // should only issue a warning for the sake of backwards compatibility.
- //
- // The solution those 2 expectations is to always take the minimum of both lints.
- // This prevent any new errors (unless both lints are explicitly set to `deny`).
- let lint = if tcx.lint_level_at_node(SAFE_PACKED_BORROWS, lint_root).0
- <= tcx.lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, lint_root).0
- {
- SAFE_PACKED_BORROWS
- } else {
- UNSAFE_OP_IN_UNSAFE_FN
- };
- tcx.struct_span_lint_hir(&lint, lint_root, source_info.span, |lint| {
- lint.build(&format!(
- "{} is unsafe and requires unsafe block (error E0133)",
- description,
- ))
- .span_label(source_info.span, description)
- .note(note)
- .emit();
- })
- }
}
}
diff --git a/compiler/rustc_mir/src/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs
index cc8669d..5968bbb 100644
--- a/compiler/rustc_mir/src/transform/const_prop.rs
+++ b/compiler/rustc_mir/src/transform/const_prop.rs
@@ -13,9 +13,9 @@
MutVisitor, MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor,
};
use rustc_middle::mir::{
- AssertKind, BasicBlock, BinOp, Body, ClearCrossCrate, Constant, ConstantKind, Local, LocalDecl,
- LocalKind, Location, Operand, Place, Rvalue, SourceInfo, SourceScope, SourceScopeData,
- Statement, StatementKind, Terminator, TerminatorKind, UnOp, RETURN_PLACE,
+ AssertKind, BasicBlock, BinOp, Body, Constant, ConstantKind, Local, LocalDecl, LocalKind,
+ Location, Operand, Place, Rvalue, SourceInfo, SourceScope, SourceScopeData, Statement,
+ StatementKind, Terminator, TerminatorKind, UnOp, RETURN_PLACE,
};
use rustc_middle::ty::layout::{HasTyCtxt, LayoutError, TyAndLayout};
use rustc_middle::ty::subst::{InternalSubsts, Subst};
@@ -440,18 +440,7 @@
}
fn lint_root(&self, source_info: SourceInfo) -> Option<HirId> {
- let mut data = &self.source_scopes[source_info.scope];
- // FIXME(oli-obk): we should be able to just walk the `inlined_parent_scope`, but it
- // does not work as I thought it would. Needs more investigation and documentation.
- while data.inlined.is_some() {
- trace!(?data);
- data = &self.source_scopes[data.parent_scope.unwrap()];
- }
- trace!(?data);
- match &data.local_data {
- ClearCrossCrate::Set(data) => Some(data.lint_root),
- ClearCrossCrate::Clear => None,
- }
+ source_info.scope.lint_root(&self.source_scopes)
}
fn use_ecx<F, T>(&mut self, f: F) -> Option<T>
@@ -491,7 +480,11 @@
let lint_only = match c.literal {
ConstantKind::Ty(ct) => match ct.val {
// Promoteds must lint and not error as the user didn't ask for them
- ConstKind::Unevaluated(_, _, Some(_)) => true,
+ ConstKind::Unevaluated(ty::Unevaluated {
+ def: _,
+ substs: _,
+ promoted: Some(_),
+ }) => true,
// Out of backwards compatibility we cannot report hard errors in unused
// generic functions using associated constants of the generic parameters.
_ => c.literal.needs_subst(),
diff --git a/compiler/rustc_mir/src/transform/coverage/debug.rs b/compiler/rustc_mir/src/transform/coverage/debug.rs
index aabfee5..4836148 100644
--- a/compiler/rustc_mir/src/transform/coverage/debug.rs
+++ b/compiler/rustc_mir/src/transform/coverage/debug.rs
@@ -121,6 +121,7 @@
use rustc_middle::mir::{self, BasicBlock, TerminatorKind};
use rustc_middle::ty::TyCtxt;
+use std::iter;
use std::lazy::SyncOnceCell;
pub const NESTED_INDENT: &str = " ";
@@ -703,9 +704,7 @@
let edge_counters = from_terminator
.successors()
.map(|&successor_bb| graphviz_data.get_edge_counter(from_bcb, successor_bb));
- edge_labels
- .iter()
- .zip(edge_counters)
+ iter::zip(&edge_labels, edge_counters)
.map(|(label, some_counter)| {
if let Some(counter) = some_counter {
format!("{}\n{}", label, debug_counters.format_counter(counter))
@@ -817,7 +816,7 @@
sections
}
-/// Returns a simple string representation of a `TerminatorKind` variant, indenpendent of any
+/// Returns a simple string representation of a `TerminatorKind` variant, independent of any
/// values it might hold.
pub(super) fn term_type(kind: &TerminatorKind<'tcx>) -> &'static str {
match kind {
diff --git a/compiler/rustc_mir/src/transform/coverage/mod.rs b/compiler/rustc_mir/src/transform/coverage/mod.rs
index 93133e9..eaeb442 100644
--- a/compiler/rustc_mir/src/transform/coverage/mod.rs
+++ b/compiler/rustc_mir/src/transform/coverage/mod.rs
@@ -23,6 +23,7 @@
use rustc_middle::hir;
use rustc_middle::hir::map::blocks::FnLikeNode;
use rustc_middle::ich::StableHashingContext;
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir::coverage::*;
use rustc_middle::mir::{
self, BasicBlock, BasicBlockData, Coverage, SourceInfo, Statement, StatementKind, Terminator,
@@ -87,6 +88,11 @@
_ => {}
}
+ let codegen_fn_attrs = tcx.codegen_fn_attrs(mir_source.def_id());
+ if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_COVERAGE) {
+ return;
+ }
+
trace!("InstrumentCoverage starting for {:?}", mir_source.def_id());
Instrumentor::new(&self.name(), tcx, mir_body).inject_counters();
trace!("InstrumentCoverage starting for {:?}", mir_source.def_id());
@@ -111,7 +117,8 @@
let body_span = hir_body.value.span;
let source_file = source_map.lookup_source_file(body_span.lo());
let fn_sig_span = match some_fn_sig.filter(|fn_sig| {
- Lrc::ptr_eq(&source_file, &source_map.lookup_source_file(fn_sig.span.hi()))
+ fn_sig.span.ctxt() == body_span.ctxt()
+ && Lrc::ptr_eq(&source_file, &source_map.lookup_source_file(fn_sig.span.lo()))
}) {
Some(fn_sig) => fn_sig.span.with_hi(body_span.lo()),
None => body_span.shrink_to_lo(),
diff --git a/compiler/rustc_mir/src/transform/coverage/query.rs b/compiler/rustc_mir/src/transform/coverage/query.rs
index de8447f..2ba9d1b 100644
--- a/compiler/rustc_mir/src/transform/coverage/query.rs
+++ b/compiler/rustc_mir/src/transform/coverage/query.rs
@@ -6,10 +6,9 @@
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::def_id::DefId;
-/// The `query` provider for `CoverageInfo`, requested by `codegen_coverage()` (to inject each
-/// counter) and `FunctionCoverage::new()` (to extract the coverage map metadata from the MIR).
+/// A `query` provider for retrieving coverage information injected into MIR.
pub(crate) fn provide(providers: &mut Providers) {
- providers.coverageinfo = |tcx, def_id| coverageinfo_from_mir(tcx, def_id);
+ providers.coverageinfo = |tcx, def_id| coverageinfo(tcx, def_id);
providers.covered_file_name = |tcx, def_id| covered_file_name(tcx, def_id);
providers.covered_code_regions = |tcx, def_id| covered_code_regions(tcx, def_id);
}
@@ -121,7 +120,7 @@
}
}
-fn coverageinfo_from_mir<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> CoverageInfo {
+fn coverageinfo<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> CoverageInfo {
let mir_body = mir_body(tcx, def_id);
let mut coverage_visitor = CoverageVisitor {
@@ -139,29 +138,22 @@
}
fn covered_file_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option<Symbol> {
- let body = mir_body(tcx, def_id);
- for bb_data in body.basic_blocks().iter() {
- for statement in bb_data.statements.iter() {
- if let StatementKind::Coverage(box ref coverage) = statement.kind {
- if let Some(code_region) = coverage.code_region.as_ref() {
- if is_inlined(body, statement) {
- continue;
+ if tcx.is_mir_available(def_id) {
+ let body = mir_body(tcx, def_id);
+ for bb_data in body.basic_blocks().iter() {
+ for statement in bb_data.statements.iter() {
+ if let StatementKind::Coverage(box ref coverage) = statement.kind {
+ if let Some(code_region) = coverage.code_region.as_ref() {
+ if is_inlined(body, statement) {
+ continue;
+ }
+ return Some(code_region.file_name);
}
- return Some(code_region.file_name);
}
}
}
}
- None
-}
-
-/// This function ensures we obtain the correct MIR for the given item irrespective of
-/// whether that means const mir or runtime mir. For `const fn` this opts for runtime
-/// mir.
-fn mir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx mir::Body<'tcx> {
- let id = ty::WithOptConstParam::unknown(def_id);
- let def = ty::InstanceDef::Item(id);
- tcx.instance_mir(def)
+ return None;
}
fn covered_code_regions<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Vec<&'tcx CodeRegion> {
@@ -188,3 +180,12 @@
let scope_data = &body.source_scopes[statement.source_info.scope];
scope_data.inlined.is_some() || scope_data.inlined_parent_scope.is_some()
}
+
+/// This function ensures we obtain the correct MIR for the given item irrespective of
+/// whether that means const mir or runtime mir. For `const fn` this opts for runtime
+/// mir.
+fn mir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx mir::Body<'tcx> {
+ let id = ty::WithOptConstParam::unknown(def_id);
+ let def = ty::InstanceDef::Item(id);
+ tcx.instance_mir(def)
+}
diff --git a/compiler/rustc_mir/src/transform/coverage/spans.rs b/compiler/rustc_mir/src/transform/coverage/spans.rs
index e7097ce..2041109 100644
--- a/compiler/rustc_mir/src/transform/coverage/spans.rs
+++ b/compiler/rustc_mir/src/transform/coverage/spans.rs
@@ -11,7 +11,7 @@
use rustc_middle::ty::TyCtxt;
use rustc_span::source_map::original_sp;
-use rustc_span::{BytePos, Span, SyntaxContext};
+use rustc_span::{BytePos, Span};
use std::cmp::Ordering;
@@ -240,7 +240,7 @@
/// to be).
pub(super) fn generate_coverage_spans(
mir_body: &'a mir::Body<'tcx>,
- fn_sig_span: Span,
+ fn_sig_span: Span, // Ensured to be same SourceFile and SyntaxContext as `body_span`
body_span: Span,
basic_coverage_blocks: &'a CoverageGraph,
) -> Vec<CoverageSpan> {
@@ -683,10 +683,10 @@
// and `_1` is the `Place` for `somenum`.
//
// If and when the Issue is resolved, remove this special case match pattern:
- StatementKind::FakeRead(cause, _) if cause == FakeReadCause::ForGuardBinding => None,
+ StatementKind::FakeRead(box (cause, _)) if cause == FakeReadCause::ForGuardBinding => None,
// Retain spans from all other statements
- StatementKind::FakeRead(_, _) // Not including `ForGuardBinding`
+ StatementKind::FakeRead(box (_, _)) // Not including `ForGuardBinding`
| StatementKind::CopyNonOverlapping(..)
| StatementKind::Assign(_)
| StatementKind::SetDiscriminant { .. }
@@ -717,11 +717,21 @@
| TerminatorKind::FalseEdge { .. }
| TerminatorKind::Goto { .. } => None,
+ // Call `func` operand can have a more specific span when part of a chain of calls
+ | TerminatorKind::Call { ref func, .. } => {
+ let mut span = terminator.source_info.span;
+ if let mir::Operand::Constant(box constant) = func {
+ if constant.span.lo() > span.lo() {
+ span = span.with_lo(constant.span.lo());
+ }
+ }
+ Some(function_source_span(span, body_span))
+ }
+
// Retain spans from all other terminators
TerminatorKind::Resume
| TerminatorKind::Abort
| TerminatorKind::Return
- | TerminatorKind::Call { .. }
| TerminatorKind::Yield { .. }
| TerminatorKind::GeneratorDrop
| TerminatorKind::FalseUnwind { .. }
@@ -733,6 +743,6 @@
#[inline]
fn function_source_span(span: Span, body_span: Span) -> Span {
- let span = original_sp(span, body_span).with_ctxt(SyntaxContext::root());
+ let span = original_sp(span, body_span).with_ctxt(body_span.ctxt());
if body_span.contains(span) { span } else { body_span }
}
diff --git a/compiler/rustc_mir/src/transform/coverage/tests.rs b/compiler/rustc_mir/src/transform/coverage/tests.rs
index 7a9bfaa..dee1124 100644
--- a/compiler/rustc_mir/src/transform/coverage/tests.rs
+++ b/compiler/rustc_mir/src/transform/coverage/tests.rs
@@ -17,7 +17,7 @@
//! Also note, some basic features of `Span` also rely on the `Span`s own "session globals", which
//! are unrelated to the `TyCtxt` global. Without initializing the `Span` session globals, some
//! basic, coverage-specific features would be impossible to test, but thankfully initializing these
-//! globals is comparitively simpler. The easiest way is to wrap the test in a closure argument
+//! globals is comparatively simpler. The easiest way is to wrap the test in a closure argument
//! to: `rustc_span::with_default_session_globals(|| { test_here(); })`.
use super::counters;
diff --git a/compiler/rustc_mir/src/transform/deduplicate_blocks.rs b/compiler/rustc_mir/src/transform/deduplicate_blocks.rs
index e102512..c41e71e 100644
--- a/compiler/rustc_mir/src/transform/deduplicate_blocks.rs
+++ b/compiler/rustc_mir/src/transform/deduplicate_blocks.rs
@@ -1,7 +1,7 @@
//! This pass finds basic blocks that are completely equal,
//! and replaces all uses with just one of them.
-use std::{collections::hash_map::Entry, hash::Hash, hash::Hasher};
+use std::{collections::hash_map::Entry, hash::Hash, hash::Hasher, iter};
use crate::transform::MirPass;
@@ -115,11 +115,7 @@
fn eq(&self, other: &Self) -> bool {
self.basic_block_data.statements.len() == other.basic_block_data.statements.len()
&& &self.basic_block_data.terminator().kind == &other.basic_block_data.terminator().kind
- && self
- .basic_block_data
- .statements
- .iter()
- .zip(&other.basic_block_data.statements)
+ && iter::zip(&self.basic_block_data.statements, &other.basic_block_data.statements)
.all(|(x, y)| statement_eq(&x.kind, &y.kind))
}
}
diff --git a/compiler/rustc_mir/src/transform/dest_prop.rs b/compiler/rustc_mir/src/transform/dest_prop.rs
index 6656dea..29df86c 100644
--- a/compiler/rustc_mir/src/transform/dest_prop.rs
+++ b/compiler/rustc_mir/src/transform/dest_prop.rs
@@ -720,9 +720,6 @@
}
}
}
- InlineAsmOperand::Const { value } => {
- assert!(value.place().is_none());
- }
InlineAsmOperand::InOut {
reg: _,
late: _,
@@ -731,6 +728,7 @@
}
| InlineAsmOperand::In { reg: _, value: _ }
| InlineAsmOperand::Out { reg: _, late: _, place: None }
+ | InlineAsmOperand::Const { value: _ }
| InlineAsmOperand::SymFn { value: _ }
| InlineAsmOperand::SymStatic { def_id: _ } => {}
}
diff --git a/compiler/rustc_mir/src/transform/generator.rs b/compiler/rustc_mir/src/transform/generator.rs
index c85e9b9..003003a 100644
--- a/compiler/rustc_mir/src/transform/generator.rs
+++ b/compiler/rustc_mir/src/transform/generator.rs
@@ -751,9 +751,10 @@
span_bug!(
body.span,
"Broken MIR: generator contains type {} in MIR, \
- but typeck only knows about {}",
- decl.ty,
- witness,
+ but typeck only knows about {} and {:?}",
+ decl_ty,
+ allowed,
+ allowed_upvars
);
}
}
diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs
index 12fdbd6..b6f8076 100644
--- a/compiler/rustc_mir/src/transform/inline.rs
+++ b/compiler/rustc_mir/src/transform/inline.rs
@@ -630,7 +630,7 @@
caller_body.required_consts.extend(
callee_body.required_consts.iter().copied().filter(|&ct| {
match ct.literal.const_for_ty() {
- Some(ct) => matches!(ct.val, ConstKind::Unevaluated(_, _, _)),
+ Some(ct) => matches!(ct.val, ConstKind::Unevaluated(_)),
None => true,
}
}),
diff --git a/compiler/rustc_mir/src/transform/match_branches.rs b/compiler/rustc_mir/src/transform/match_branches.rs
index d04a701..f7a9835 100644
--- a/compiler/rustc_mir/src/transform/match_branches.rs
+++ b/compiler/rustc_mir/src/transform/match_branches.rs
@@ -1,6 +1,7 @@
use crate::transform::MirPass;
use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt;
+use std::iter;
use super::simplify::simplify_cfg;
@@ -83,7 +84,7 @@
if first_stmts.len() != scnd_stmts.len() {
continue;
}
- for (f, s) in first_stmts.iter().zip(scnd_stmts.iter()) {
+ for (f, s) in iter::zip(first_stmts, scnd_stmts) {
match (&f.kind, &s.kind) {
// If two statements are exactly the same, we can optimize.
(f_s, s_s) if f_s == s_s => {}
@@ -113,7 +114,7 @@
// and bb_idx has a different terminator from both of them.
let (from, first, second) = bbs.pick3_mut(bb_idx, first, second);
- let new_stmts = first.statements.iter().zip(second.statements.iter()).map(|(f, s)| {
+ let new_stmts = iter::zip(&first.statements, &second.statements).map(|(f, s)| {
match (&f.kind, &s.kind) {
(f_s, s_s) if f_s == s_s => (*f).clone(),
diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs
index 1354644..5c49ee6 100644
--- a/compiler/rustc_mir/src/transform/mod.rs
+++ b/compiler/rustc_mir/src/transform/mod.rs
@@ -44,6 +44,7 @@
pub mod remove_noop_landing_pads;
pub mod remove_storage_markers;
pub mod remove_unneeded_drops;
+pub mod remove_zsts;
pub mod required_consts;
pub mod rustc_peek;
pub mod simplify;
@@ -58,6 +59,7 @@
pub(crate) fn provide(providers: &mut Providers) {
self::check_unsafety::provide(providers);
+ self::check_packed_ref::provide(providers);
*providers = Providers {
mir_keys,
mir_const,
@@ -313,11 +315,8 @@
&simplify::SimplifyCfg::new("promote-consts"),
];
- let opt_coverage: &[&dyn MirPass<'tcx>] = if tcx.sess.opts.debugging_opts.instrument_coverage {
- &[&coverage::InstrumentCoverage]
- } else {
- &[]
- };
+ let opt_coverage: &[&dyn MirPass<'tcx>] =
+ if tcx.sess.instrument_coverage() { &[&coverage::InstrumentCoverage] } else { &[] };
run_passes(tcx, &mut body, MirPhase::ConstPromotion, &[promote, opt_coverage]);
@@ -494,6 +493,7 @@
// The main optimizations that we do on MIR.
let optimizations: &[&dyn MirPass<'tcx>] = &[
&remove_storage_markers::RemoveStorageMarkers,
+ &remove_zsts::RemoveZsts,
&const_goto::ConstGoto,
&remove_unneeded_drops::RemoveUnneededDrops,
&match_branches::MatchBranchSimplification,
diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs
index 7db790c..1bbaf83 100644
--- a/compiler/rustc_mir/src/transform/promote_consts.rs
+++ b/compiler/rustc_mir/src/transform/promote_consts.rs
@@ -108,9 +108,6 @@
/// the attribute currently provides the semantic requirement that arguments
/// must be constant.
Argument { bb: BasicBlock, index: usize },
-
- /// `const` operand in asm!.
- InlineAsm { bb: BasicBlock, index: usize },
}
impl Candidate {
@@ -118,16 +115,14 @@
fn forces_explicit_promotion(&self) -> bool {
match self {
Candidate::Ref(_) => false,
- Candidate::Argument { .. } | Candidate::InlineAsm { .. } => true,
+ Candidate::Argument { .. } => true,
}
}
fn source_info(&self, body: &Body<'_>) -> SourceInfo {
match self {
Candidate::Ref(location) => *body.source_info(*location),
- Candidate::Argument { bb, .. } | Candidate::InlineAsm { bb, .. } => {
- *body.source_info(body.terminator_loc(*bb))
- }
+ Candidate::Argument { bb, .. } => *body.source_info(body.terminator_loc(*bb)),
}
}
}
@@ -217,36 +212,25 @@
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
self.super_terminator(terminator, location);
- match terminator.kind {
- TerminatorKind::Call { ref func, .. } => {
- if let ty::FnDef(def_id, _) = *func.ty(self.ccx.body, self.ccx.tcx).kind() {
- let fn_sig = self.ccx.tcx.fn_sig(def_id);
- if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = fn_sig.abi() {
- let name = self.ccx.tcx.item_name(def_id);
- // FIXME(eddyb) use `#[rustc_args_required_const(2)]` for shuffles.
- if name.as_str().starts_with("simd_shuffle") {
- self.candidates
- .push(Candidate::Argument { bb: location.block, index: 2 });
+ if let TerminatorKind::Call { ref func, .. } = terminator.kind {
+ if let ty::FnDef(def_id, _) = *func.ty(self.ccx.body, self.ccx.tcx).kind() {
+ let fn_sig = self.ccx.tcx.fn_sig(def_id);
+ if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = fn_sig.abi() {
+ let name = self.ccx.tcx.item_name(def_id);
+ // FIXME(eddyb) use `#[rustc_args_required_const(2)]` for shuffles.
+ if name.as_str().starts_with("simd_shuffle") {
+ self.candidates.push(Candidate::Argument { bb: location.block, index: 2 });
- return; // Don't double count `simd_shuffle` candidates
- }
+ return; // Don't double count `simd_shuffle` candidates
}
+ }
- if let Some(constant_args) = args_required_const(self.ccx.tcx, def_id) {
- for index in constant_args {
- self.candidates.push(Candidate::Argument { bb: location.block, index });
- }
+ if let Some(constant_args) = args_required_const(self.ccx.tcx, def_id) {
+ for index in constant_args {
+ self.candidates.push(Candidate::Argument { bb: location.block, index });
}
}
}
- TerminatorKind::InlineAsm { ref operands, .. } => {
- for (index, op) in operands.iter().enumerate() {
- if let InlineAsmOperand::Const { .. } = op {
- self.candidates.push(Candidate::InlineAsm { bb: location.block, index })
- }
- }
- }
- _ => {}
}
}
}
@@ -335,18 +319,6 @@
_ => bug!(),
}
}
- Candidate::InlineAsm { bb, index } => {
- assert!(self.explicit);
-
- let terminator = self.body[bb].terminator();
- match &terminator.kind {
- TerminatorKind::InlineAsm { operands, .. } => match &operands[index] {
- InlineAsmOperand::Const { value } => self.validate_operand(value),
- _ => bug!(),
- },
- _ => bug!(),
- }
- }
}
}
@@ -818,9 +790,7 @@
}
match candidate {
- Candidate::Argument { bb, index } | Candidate::InlineAsm { bb, index }
- if !is_promotable =>
- {
+ Candidate::Argument { bb, index } if !is_promotable => {
let span = ccx.body[bb].terminator().source_info.span;
let msg = format!("argument {} is required to be a constant", index + 1);
ccx.tcx.sess.span_err(span, &msg);
@@ -1001,17 +971,17 @@
literal: tcx
.mk_const(ty::Const {
ty,
- val: ty::ConstKind::Unevaluated(
+ val: ty::ConstKind::Unevaluated(ty::Unevaluated {
def,
- InternalSubsts::for_item(tcx, def.did, |param, _| {
+ substs: InternalSubsts::for_item(tcx, def.did, |param, _| {
if let ty::GenericParamDefKind::Lifetime = param.kind {
tcx.lifetimes.re_erased.into()
} else {
tcx.mk_param_from_def(param)
}
}),
- Some(promoted_id),
- ),
+ promoted: Some(promoted_id),
+ }),
})
.into(),
}))
@@ -1089,24 +1059,6 @@
_ => bug!(),
}
}
- Candidate::InlineAsm { bb, index } => {
- let terminator = blocks[bb].terminator_mut();
- match terminator.kind {
- TerminatorKind::InlineAsm { ref mut operands, .. } => {
- match &mut operands[index] {
- InlineAsmOperand::Const { ref mut value } => {
- let ty = value.ty(local_decls, self.tcx);
- let span = terminator.source_info.span;
-
- Rvalue::Use(mem::replace(value, promoted_operand(ty, span)))
- }
- _ => bug!(),
- }
- }
-
- _ => bug!(),
- }
- }
}
};
@@ -1161,7 +1113,7 @@
}
}
}
- Candidate::Argument { .. } | Candidate::InlineAsm { .. } => {}
+ Candidate::Argument { .. } => {}
}
// Declare return place local so that `mir::Body::new` doesn't complain.
diff --git a/compiler/rustc_mir/src/transform/remove_zsts.rs b/compiler/rustc_mir/src/transform/remove_zsts.rs
new file mode 100644
index 0000000..70f7538
--- /dev/null
+++ b/compiler/rustc_mir/src/transform/remove_zsts.rs
@@ -0,0 +1,89 @@
+//! Removes assignments to ZST places.
+
+use crate::transform::MirPass;
+use rustc_middle::mir::tcx::PlaceTy;
+use rustc_middle::mir::{Body, LocalDecls, Place, StatementKind};
+use rustc_middle::ty::{self, Ty, TyCtxt};
+
+pub struct RemoveZsts;
+
+impl<'tcx> MirPass<'tcx> for RemoveZsts {
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+ if tcx.sess.mir_opt_level() < 3 {
+ return;
+ }
+ let param_env = tcx.param_env(body.source.def_id());
+ let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
+ for block in basic_blocks.iter_mut() {
+ for statement in block.statements.iter_mut() {
+ match statement.kind {
+ StatementKind::Assign(box (place, _)) => {
+ let place_ty = place.ty(local_decls, tcx).ty;
+ if !maybe_zst(place_ty) {
+ continue;
+ }
+ let layout = match tcx.layout_of(param_env.and(place_ty)) {
+ Ok(layout) => layout,
+ Err(_) => continue,
+ };
+ if !layout.is_zst() {
+ continue;
+ }
+ if involves_a_union(place, local_decls, tcx) {
+ continue;
+ }
+ if tcx.consider_optimizing(|| {
+ format!(
+ "RemoveZsts - Place: {:?} SourceInfo: {:?}",
+ place, statement.source_info
+ )
+ }) {
+ statement.make_nop();
+ }
+ }
+ _ => {}
+ }
+ }
+ }
+ }
+}
+
+/// A cheap, approximate check to avoid unnecessary `layout_of` calls.
+fn maybe_zst(ty: Ty<'_>) -> bool {
+ match ty.kind() {
+ // maybe ZST (could be more precise)
+ ty::Adt(..) | ty::Array(..) | ty::Closure(..) | ty::Tuple(..) | ty::Opaque(..) => true,
+ // definitely ZST
+ ty::FnDef(..) | ty::Never => true,
+ // unreachable or can't be ZST
+ _ => false,
+ }
+}
+
+/// Miri lazily allocates memory for locals on assignment,
+/// so we must preserve writes to unions and union fields,
+/// or it will ICE on reads of those fields.
+fn involves_a_union<'tcx>(
+ place: Place<'tcx>,
+ local_decls: &LocalDecls<'tcx>,
+ tcx: TyCtxt<'tcx>,
+) -> bool {
+ let mut place_ty = PlaceTy::from_ty(local_decls[place.local].ty);
+ if is_union(place_ty.ty) {
+ return true;
+ }
+ for elem in place.projection {
+ place_ty = place_ty.projection_ty(tcx, elem);
+ if is_union(place_ty.ty) {
+ return true;
+ }
+ }
+ return false;
+}
+
+fn is_union(ty: Ty<'_>) -> bool {
+ match ty.kind() {
+ ty::Adt(def, _) if def.is_union() => true,
+ _ => false,
+ }
+}
diff --git a/compiler/rustc_mir/src/transform/required_consts.rs b/compiler/rustc_mir/src/transform/required_consts.rs
index 2b518bd..8b64ad6 100644
--- a/compiler/rustc_mir/src/transform/required_consts.rs
+++ b/compiler/rustc_mir/src/transform/required_consts.rs
@@ -15,7 +15,7 @@
impl<'a, 'tcx> Visitor<'tcx> for RequiredConstsVisitor<'a, 'tcx> {
fn visit_constant(&mut self, constant: &Constant<'tcx>, _: Location) {
if let Some(ct) = constant.literal.const_for_ty() {
- if let ConstKind::Unevaluated(_, _, _) = ct.val {
+ if let ConstKind::Unevaluated(_) = ct.val {
self.required_consts.push(*constant);
}
}
diff --git a/compiler/rustc_mir/src/transform/simplify.rs b/compiler/rustc_mir/src/transform/simplify.rs
index d2314a9..65e2d09 100644
--- a/compiler/rustc_mir/src/transform/simplify.rs
+++ b/compiler/rustc_mir/src/transform/simplify.rs
@@ -31,10 +31,10 @@
use rustc_index::vec::{Idx, IndexVec};
use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*;
-use rustc_middle::ty::ParamEnv;
use rustc_middle::ty::TyCtxt;
use smallvec::SmallVec;
-use std::{borrow::Cow, convert::TryInto};
+use std::borrow::Cow;
+use std::convert::TryInto;
pub struct SimplifyCfg {
label: String,
@@ -326,7 +326,7 @@
pub fn simplify_locals<'tcx>(body: &mut Body<'tcx>, tcx: TyCtxt<'tcx>) {
// First, we're going to get a count of *actual* uses for every `Local`.
- let mut used_locals = UsedLocals::new(body, tcx);
+ let mut used_locals = UsedLocals::new(body);
// Next, we're going to remove any `Local` with zero actual uses. When we remove those
// `Locals`, we're also going to subtract any uses of other `Locals` from the `used_locals`
@@ -336,8 +336,7 @@
remove_unused_definitions(&mut used_locals, body);
// Finally, we'll actually do the work of shrinking `body.local_decls` and remapping the `Local`s.
- let arg_count = body.arg_count.try_into().unwrap();
- let map = make_local_map(&mut body.local_decls, &used_locals, arg_count);
+ let map = make_local_map(&mut body.local_decls, &used_locals);
// Only bother running the `LocalUpdater` if we actually found locals to remove.
if map.iter().any(Option::is_none) {
@@ -350,61 +349,54 @@
}
/// Construct the mapping while swapping out unused stuff out from the `vec`.
-fn make_local_map<'tcx, V>(
+fn make_local_map<V>(
local_decls: &mut IndexVec<Local, V>,
- used_locals: &UsedLocals<'tcx>,
- arg_count: u32,
+ used_locals: &UsedLocals,
) -> IndexVec<Local, Option<Local>> {
- let mut map: IndexVec<Local, Option<Local>> = IndexVec::from_elem(None, local_decls);
+ let mut map: IndexVec<Local, Option<Local>> = IndexVec::from_elem(None, &*local_decls);
let mut used = Local::new(0);
for alive_index in local_decls.indices() {
- // When creating the local map treat the `RETURN_PLACE` and arguments as used.
- if alive_index.as_u32() <= arg_count || used_locals.is_used(alive_index) {
- map[alive_index] = Some(used);
- if alive_index != used {
- local_decls.swap(alive_index, used);
- }
- used.increment_by(1);
+ // `is_used` treats the `RETURN_PLACE` and arguments as used.
+ if !used_locals.is_used(alive_index) {
+ continue;
}
+
+ map[alive_index] = Some(used);
+ if alive_index != used {
+ local_decls.swap(alive_index, used);
+ }
+ used.increment_by(1);
}
local_decls.truncate(used.index());
map
}
/// Keeps track of used & unused locals.
-struct UsedLocals<'tcx> {
+struct UsedLocals {
increment: bool,
+ arg_count: u32,
use_count: IndexVec<Local, u32>,
- is_static: bool,
- local_decls: IndexVec<Local, LocalDecl<'tcx>>,
- param_env: ParamEnv<'tcx>,
- tcx: TyCtxt<'tcx>,
}
-impl UsedLocals<'tcx> {
+impl UsedLocals {
/// Determines which locals are used & unused in the given body.
- fn new(body: &Body<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
- let def_id = body.source.def_id();
- let is_static = tcx.is_static(def_id);
- let param_env = tcx.param_env(def_id);
- let local_decls = body.local_decls.clone();
+ fn new(body: &Body<'_>) -> Self {
let mut this = Self {
increment: true,
+ arg_count: body.arg_count.try_into().unwrap(),
use_count: IndexVec::from_elem(0, &body.local_decls),
- is_static,
- local_decls,
- param_env,
- tcx,
};
this.visit_body(body);
this
}
/// Checks if local is used.
+ ///
+ /// Return place and arguments are always considered used.
fn is_used(&self, local: Local) -> bool {
trace!("is_used({:?}): use_count: {:?}", local, self.use_count[local]);
- self.use_count[local] != 0
+ local.as_u32() <= self.arg_count || self.use_count[local] != 0
}
/// Updates the use counts to reflect the removal of given statement.
@@ -422,7 +414,9 @@
// A use, not a definition.
self.visit_place(place, PlaceContext::MutatingUse(MutatingUseContext::Store), location);
} else {
- // A definition. Although, it still might use other locals for indexing.
+ // A definition. The base local itself is not visited, so this occurrence is not counted
+ // toward its use count. There might be other locals still, used in an indexing
+ // projection.
self.super_projection(
place.as_ref(),
PlaceContext::MutatingUse(MutatingUseContext::Projection),
@@ -432,7 +426,7 @@
}
}
-impl Visitor<'tcx> for UsedLocals<'tcx> {
+impl Visitor<'_> for UsedLocals {
fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
match statement.kind {
StatementKind::LlvmInlineAsm(..)
@@ -459,21 +453,7 @@
}
}
- fn visit_local(&mut self, local: &Local, ctx: PlaceContext, _location: Location) {
- debug!("local: {:?} is_static: {:?}, ctx: {:?}", local, self.is_static, ctx);
- // Do not count _0 as a used in `return;` if it is a ZST.
- let return_place = *local == RETURN_PLACE
- && matches!(ctx, PlaceContext::NonMutatingUse(visit::NonMutatingUseContext::Move));
- if !self.is_static && return_place {
- let ty = self.local_decls[*local].ty;
- let param_env_and = self.param_env.and(ty);
- if let Ok(layout) = self.tcx.layout_of(param_env_and) {
- debug!("layout.is_zst: {:?}", layout.is_zst());
- if layout.is_zst() {
- return;
- }
- }
- }
+ fn visit_local(&mut self, local: &Local, _ctx: PlaceContext, _location: Location) {
if self.increment {
self.use_count[*local] += 1;
} else {
@@ -484,10 +464,7 @@
}
/// Removes unused definitions. Updates the used locals to reflect the changes made.
-fn remove_unused_definitions<'a, 'tcx>(
- used_locals: &'a mut UsedLocals<'tcx>,
- body: &mut Body<'tcx>,
-) {
+fn remove_unused_definitions<'a, 'tcx>(used_locals: &'a mut UsedLocals, body: &mut Body<'tcx>) {
// The use counts are updated as we remove the statements. A local might become unused
// during the retain operation, leading to a temporary inconsistency (storage statements or
// definitions referencing the local might remain). For correctness it is crucial that this
diff --git a/compiler/rustc_mir/src/util/alignment.rs b/compiler/rustc_mir/src/util/alignment.rs
index f567c9c..5d4ca87 100644
--- a/compiler/rustc_mir/src/util/alignment.rs
+++ b/compiler/rustc_mir/src/util/alignment.rs
@@ -1,5 +1,6 @@
use rustc_middle::mir::*;
use rustc_middle::ty::{self, TyCtxt};
+use rustc_target::abi::Align;
/// Returns `true` if this place is allowed to be less aligned
/// than its containing struct (because it is within a packed
@@ -14,17 +15,25 @@
L: HasLocalDecls<'tcx>,
{
debug!("is_disaligned({:?})", place);
- if !is_within_packed(tcx, local_decls, place) {
- debug!("is_disaligned({:?}) - not within packed", place);
- return false;
- }
+ let pack = match is_within_packed(tcx, local_decls, place) {
+ None => {
+ debug!("is_disaligned({:?}) - not within packed", place);
+ return false;
+ }
+ Some(pack) => pack,
+ };
let ty = place.ty(local_decls, tcx).ty;
match tcx.layout_raw(param_env.and(ty)) {
- Ok(layout) if layout.align.abi.bytes() == 1 => {
- // if the alignment is 1, the type can't be further
- // disaligned.
- debug!("is_disaligned({:?}) - align = 1", place);
+ Ok(layout) if layout.align.abi <= pack => {
+ // If the packed alignment is greater or equal to the field alignment, the type won't be
+ // further disaligned.
+ debug!(
+ "is_disaligned({:?}) - align = {}, packed = {}; not disaligned",
+ place,
+ layout.align.abi.bytes(),
+ pack.bytes()
+ );
false
}
_ => {
@@ -34,7 +43,11 @@
}
}
-fn is_within_packed<'tcx, L>(tcx: TyCtxt<'tcx>, local_decls: &L, place: Place<'tcx>) -> bool
+fn is_within_packed<'tcx, L>(
+ tcx: TyCtxt<'tcx>,
+ local_decls: &L,
+ place: Place<'tcx>,
+) -> Option<Align>
where
L: HasLocalDecls<'tcx>,
{
@@ -45,7 +58,7 @@
ProjectionElem::Field(..) => {
let ty = place_base.ty(local_decls, tcx).ty;
match ty.kind() {
- ty::Adt(def, _) if def.repr.packed() => return true,
+ ty::Adt(def, _) => return def.repr.pack,
_ => {}
}
}
@@ -53,5 +66,5 @@
}
}
- false
+ None
}
diff --git a/compiler/rustc_mir/src/util/find_self_call.rs b/compiler/rustc_mir/src/util/find_self_call.rs
index ddda98d..33ad128 100644
--- a/compiler/rustc_mir/src/util/find_self_call.rs
+++ b/compiler/rustc_mir/src/util/find_self_call.rs
@@ -3,7 +3,7 @@
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::def_id::DefId;
-/// Checks if the specified `local` is used as the `self` prameter of a method call
+/// Checks if the specified `local` is used as the `self` parameter of a method call
/// in the provided `BasicBlock`. If it is, then the `DefId` of the called method is
/// returned.
pub fn find_self_call<'tcx>(
diff --git a/compiler/rustc_mir/src/util/generic_graphviz.rs b/compiler/rustc_mir/src/util/generic_graphviz.rs
index fd41e28..21c18b2 100644
--- a/compiler/rustc_mir/src/util/generic_graphviz.rs
+++ b/compiler/rustc_mir/src/util/generic_graphviz.rs
@@ -40,22 +40,6 @@
}
}
- pub fn new_subgraph(
- graph: &'a G,
- graphviz_name: &str,
- node_content_fn: NodeContentFn,
- edge_labels_fn: EdgeLabelsFn,
- ) -> Self {
- Self {
- graph,
- is_subgraph: true,
- graphviz_name: graphviz_name.to_owned(),
- graph_label: None,
- node_content_fn,
- edge_labels_fn,
- }
- }
-
pub fn set_graph_label(&mut self, graph_label: &str) {
self.graph_label = Some(graph_label.to_owned());
}
diff --git a/compiler/rustc_mir/src/util/patch.rs b/compiler/rustc_mir/src/util/patch.rs
index 6566a99..d09195f 100644
--- a/compiler/rustc_mir/src/util/patch.rs
+++ b/compiler/rustc_mir/src/util/patch.rs
@@ -13,7 +13,6 @@
new_locals: Vec<LocalDecl<'tcx>>,
resume_block: BasicBlock,
next_local: usize,
- make_nop: Vec<Location>,
}
impl<'tcx> MirPatch<'tcx> {
@@ -25,7 +24,6 @@
new_locals: vec![],
next_local: body.local_decls.len(),
resume_block: START_BLOCK,
- make_nop: vec![],
};
// make sure the MIR we create has a resume block. It is
@@ -117,15 +115,7 @@
self.add_statement(loc, StatementKind::Assign(box (place, rv)));
}
- pub fn make_nop(&mut self, loc: Location) {
- self.make_nop.push(loc);
- }
-
pub fn apply(self, body: &mut Body<'tcx>) {
- debug!("MirPatch: make nops at: {:?}", self.make_nop);
- for loc in self.make_nop {
- body.make_statement_nop(loc);
- }
debug!(
"MirPatch: {:?} new temps, starting from index {}: {:?}",
self.new_locals.len(),
diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs
index 1bf010f..3b88aec 100644
--- a/compiler/rustc_mir/src/util/pretty.rs
+++ b/compiler/rustc_mir/src/util/pretty.rs
@@ -452,7 +452,11 @@
match literal {
ConstantKind::Ty(literal) => self.push(&format!("+ literal: {:?}", literal)),
ConstantKind::Val(val, ty) => {
- self.push(&format!("+ literal: {:?}, {}", val, ty))
+ // To keep the diffs small, we render this almost like we render ty::Const
+ self.push(&format!(
+ "+ literal: Const {{ ty: {}, val: Value({:?}) }}",
+ ty, val
+ ))
}
}
}
@@ -465,7 +469,21 @@
if use_verbose(ty) {
self.push("ty::Const");
self.push(&format!("+ ty: {:?}", ty));
- self.push(&format!("+ val: {:?}", val));
+ let val = match val {
+ ty::ConstKind::Param(p) => format!("Param({})", p),
+ ty::ConstKind::Infer(infer) => format!("Infer({:?})", infer),
+ ty::ConstKind::Bound(idx, var) => format!("Bound({:?}, {:?})", idx, var),
+ ty::ConstKind::Placeholder(ph) => format!("PlaceHolder({:?})", ph),
+ ty::ConstKind::Unevaluated(uv) => format!(
+ "Unevaluated({}, {:?}, {:?})",
+ self.tcx.def_path_str(uv.def.did),
+ uv.substs,
+ uv.promoted
+ ),
+ ty::ConstKind::Value(val) => format!("Value({:?})", val),
+ ty::ConstKind::Error(_) => format!("Error"),
+ };
+ self.push(&format!("+ val: {}", val));
}
}