use rustc_data_structures::fx::FxHashSet;
-use rustc_index::vec::IndexVec;
-use rustc_data_structures::sync::Lrc;
use rustc::ty::query::Providers;
use rustc::ty::{self, TyCtxt};
use rustc::hir;
use rustc::hir::Node;
use rustc::hir::def_id::DefId;
-use rustc::lint::builtin::{SAFE_EXTERN_STATICS, SAFE_PACKED_BORROWS, UNUSED_UNSAFE};
+use rustc::lint::builtin::{SAFE_PACKED_BORROWS, UNUSED_UNSAFE};
use rustc::mir::*;
use rustc::mir::visit::{PlaceContext, Visitor, MutatingUseContext};
use crate::util;
+use rustc_error_codes::*;
+
pub struct UnsafetyChecker<'a, 'tcx> {
body: &'a Body<'tcx>,
const_context: bool,
min_const_fn: bool,
- source_scope_local_data: &'a IndexVec<SourceScope, SourceScopeLocalData>,
violations: Vec<UnsafetyViolation>,
source_info: SourceInfo,
tcx: TyCtxt<'tcx>,
const_context: bool,
min_const_fn: bool,
body: &'a Body<'tcx>,
- source_scope_local_data: &'a IndexVec<SourceScope, SourceScopeLocalData>,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> Self {
body,
const_context,
min_const_fn,
- source_scope_local_data,
violations: vec![],
source_info: SourceInfo {
span: body.span,
// Locals are safe.
}
PlaceBase::Static(box Static { kind: StaticKind::Promoted(_, _), .. }) => {
- bug!("unsafety checking should happen before promotion")
+ bug!("unsafety checking should happen before promotion");
}
- PlaceBase::Static(box Static { kind: StaticKind::Static, def_id, .. }) => {
- if self.tcx.is_mutable_static(def_id) {
- self.require_unsafe("use of mutable static",
- "mutable statics can be mutated by multiple threads: aliasing \
- violations or data races will cause undefined behavior",
- UnsafetyViolationKind::General);
- } else if self.tcx.is_foreign_item(def_id) {
- let source_info = self.source_info;
- let lint_root =
- self.source_scope_local_data[source_info.scope].lint_root;
- self.register_violations(&[UnsafetyViolation {
- source_info,
- description: Symbol::intern("use of extern static"),
- details: Symbol::intern(
- "extern statics are not controlled by the Rust type system: \
- invalid data, aliasing violations or data races will cause \
- undefined behavior"),
- kind: UnsafetyViolationKind::ExternStatic(lint_root)
- }], &[]);
- }
+ PlaceBase::Static(box Static { kind: StaticKind::Static, .. }) => {
+ bug!("StaticKind::Static should not exist");
}
}
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.source_scope_local_data[source_info.scope].lint_root;
+ let lint_root = self.body.source_scopes[source_info.scope]
+ .local_data
+ .as_ref()
+ .assert_crate_local()
+ .lint_root;
self.register_violations(&[UnsafetyViolation {
source_info,
description: Symbol::intern("borrow of packed field"),
}
let old_source_info = self.source_info;
if let (PlaceBase::Local(local), []) = (&place.base, proj_base) {
- if self.body.local_decls[*local].internal {
- // Internal locals are used in the `move_val_init` desugaring.
- // We want to check unsafety against the source info of the
- // desugaring, rather than the source info of the RHS.
- self.source_info = self.body.local_decls[*local].source_info;
+ let decl = &self.body.local_decls[*local];
+ if decl.internal {
+ if let LocalInfo::StaticRef { def_id, .. } = decl.local_info {
+ if self.tcx.is_mutable_static(def_id) {
+ self.require_unsafe(
+ "use of mutable static",
+ "mutable statics can be mutated by multiple threads: aliasing \
+ violations or data races will cause undefined behavior",
+ UnsafetyViolationKind::General,
+ );
+ return;
+ } else if self.tcx.is_foreign_item(def_id) {
+ self.require_unsafe(
+ "use of extern static",
+ "extern statics are not controlled by the Rust type system: \
+ invalid data, aliasing violations or data races will cause \
+ undefined behavior",
+ UnsafetyViolationKind::General,
+ );
+ return;
+ }
+ } else {
+ // Internal locals are used in the `move_val_init` desugaring.
+ // We want to check unsafety against the source info of the
+ // desugaring, rather than the source info of the RHS.
+ self.source_info = self.body.local_decls[*local].source_info;
+ }
}
}
let base_ty = Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty;
fn register_violations(&mut self,
violations: &[UnsafetyViolation],
unsafe_blocks: &[(hir::HirId, bool)]) {
- let safety = self.source_scope_local_data[self.source_info.scope].safety;
+ let safety = self.body.source_scopes[self.source_info.scope]
+ .local_data
+ .as_ref()
+ .assert_crate_local()
+ .safety;
let within_unsafe = match safety {
// `unsafe` blocks are required in safe code
Safety::Safe => {
match violation.kind {
UnsafetyViolationKind::GeneralAndConstFn |
UnsafetyViolationKind::General => {},
- UnsafetyViolationKind::BorrowPacked(_) |
- UnsafetyViolationKind::ExternStatic(_) => if self.min_const_fn {
+ 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
UnsafetyViolationKind::GeneralAndConstFn => {},
// these things are forbidden in const fns
UnsafetyViolationKind::General |
- UnsafetyViolationKind::BorrowPacked(_) |
- UnsafetyViolationKind::ExternStatic(_) => {
+ UnsafetyViolationKind::BorrowPacked(_) => {
let mut violation = violation.clone();
// const fns don't need to be backwards compatible and can
// emit these violations as a hard error instead of a backwards
// `mir_built` force this.
let body = &tcx.mir_built(def_id).borrow();
- let source_scope_local_data = match body.source_scope_local_data {
- ClearCrossCrate::Set(ref data) => data,
- ClearCrossCrate::Clear => {
- debug!("unsafety_violations: {:?} - remote, skipping", def_id);
- return UnsafetyCheckResult {
- violations: Lrc::new([]),
- unsafe_blocks: Lrc::new([])
- }
- }
- };
-
let param_env = tcx.param_env(def_id);
let id = tcx.hir().as_local_hir_id(def_id).unwrap();
hir::BodyOwnerKind::Const |
hir::BodyOwnerKind::Static(_) => (true, false),
};
- let mut checker = UnsafetyChecker::new(
- const_context, min_const_fn,
- body, source_scope_local_data, tcx, param_env);
+ let mut checker = UnsafetyChecker::new(const_context, min_const_fn, body, tcx, param_env);
+ // mir_built ensures that body has a computed cache, so we don't (and can't) attempt to
+ // recompute it here.
+ let body = body.unwrap_read_only();
checker.visit_body(body);
check_unused_unsafe(tcx, def_id, &checker.used_unsafe, &mut checker.inherited_blocks);
if used_unsafe.contains(&parent_id) {
Some(("block".to_string(), parent_id))
} else if let Some(Node::Item(&hir::Item {
- kind: hir::ItemKind::Fn(_, header, _, _),
+ kind: hir::ItemKind::Fn(ref sig, _, _),
..
})) = tcx.hir().find(parent_id) {
- match header.unsafety {
+ match sig.header.unsafety {
hir::Unsafety::Unsafe => Some(("fn".to_string(), parent_id)),
hir::Unsafety::Normal => None,
}
struct_span_err!(
tcx.sess, source_info.span, E0133,
"{} is unsafe and requires unsafe function or block", description)
- .span_label(source_info.span, &description.as_str()[..])
- .note(&details.as_str()[..])
+ .span_label(source_info.span, &*description.as_str())
+ .note(&details.as_str())
.emit();
}
- UnsafetyViolationKind::ExternStatic(lint_hir_id) => {
- tcx.lint_node_note(SAFE_EXTERN_STATICS,
- lint_hir_id,
- source_info.span,
- &format!("{} is unsafe and requires unsafe function or block \
- (error E0133)", &description.as_str()[..]),
- &details.as_str()[..]);
- }
UnsafetyViolationKind::BorrowPacked(lint_hir_id) => {
if let Some(impl_def_id) = builtin_derive_def_id(tcx, def_id) {
tcx.unsafe_derive_on_repr_packed(impl_def_id);
lint_hir_id,
source_info.span,
&format!("{} is unsafe and requires unsafe function or block \
- (error E0133)", &description.as_str()[..]),
- &details.as_str()[..]);
+ (error E0133)", description),
+ &details.as_str());
}
}
}
let mut unsafe_blocks: Vec<_> = unsafe_blocks.into_iter().collect();
unsafe_blocks.sort_by_cached_key(|(hir_id, _)| tcx.hir().hir_to_node_id(*hir_id));
let used_unsafe: FxHashSet<_> = unsafe_blocks.iter()
- .flat_map(|&&(id, used)| if used { Some(id) } else { None })
+ .flat_map(|&&(id, used)| used.then_some(id))
.collect();
for &(block_id, is_used) in unsafe_blocks {
if !is_used {