Auto merge of #75573 - Aaron1011:feature/const-mutation-lint, r=oli-obk

Add CONST_ITEM_MUTATION lint

Fixes #74053
Fixes #55721

This PR adds a new lint `CONST_ITEM_MUTATION`.
Given an item `const FOO: SomeType = ..`, this lint fires on:

* Attempting to write directly to a field (`FOO.field = some_val`) or
  array entry (`FOO.array_field[0] = val`)
* Taking a mutable reference to the `const` item (`&mut FOO`), including
  through an autoderef `FOO.some_mut_self_method()`

The lint message explains that since each use of a constant creates a
new temporary, the original `const` item will not be modified.
This commit is contained in:
bors
2020-09-10 05:54:26 +00:00
22 changed files with 427 additions and 116 deletions

View File

@@ -0,0 +1,35 @@
use rustc_middle::mir::*;
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
/// in the provided `BasicBlock`. If it is, then the `DefId` of the called method is
/// returned.
pub fn find_self_call(
tcx: TyCtxt<'_>,
body: &Body<'_>,
local: Local,
block: BasicBlock,
) -> Option<DefId> {
debug!("find_self_call(local={:?}): terminator={:?}", local, &body[block].terminator);
if let Some(Terminator { kind: TerminatorKind::Call { func, args, .. }, .. }) =
&body[block].terminator
{
debug!("find_self_call: func={:?}", func);
if let Operand::Constant(box Constant { literal: ty::Const { ty, .. }, .. }) = func {
if let ty::FnDef(def_id, _) = *ty.kind() {
if let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) =
tcx.opt_associated_item(def_id)
{
debug!("find_self_call: args={:?}", args);
if let [Operand::Move(self_place) | Operand::Copy(self_place), ..] = **args {
if self_place.as_local() == Some(local) {
return Some(def_id);
}
}
}
}
}
}
None
}

View File

@@ -7,12 +7,14 @@ pub mod storage;
mod alignment;
pub mod collect_writes;
mod find_self_call;
mod graphviz;
pub(crate) mod pretty;
pub(crate) mod spanview;
pub use self::aggregate::expand_aggregate;
pub use self::alignment::is_disaligned;
pub use self::find_self_call::find_self_call;
pub use self::graphviz::write_node_label as write_graphviz_node_label;
pub use self::graphviz::{graphviz_safe_def_name, write_mir_graphviz};
pub use self::pretty::{dump_enabled, dump_mir, write_mir_pretty, PassWhere};