Skip to content

Commit

Permalink
Rollup merge of rust-lang#111004 - clubby789:migrate-mir-transform, r…
Browse files Browse the repository at this point in the history
…=oli-obk

Migrate `mir_transform` to translatable diagnostics

cc rust-lang#100717
  • Loading branch information
matthiaskrgr committed May 5, 2023
2 parents 8a1f4f3 + d5bc581 commit 3e01276
Show file tree
Hide file tree
Showing 16 changed files with 470 additions and 200 deletions.
3 changes: 3 additions & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3353,6 +3353,7 @@ dependencies = [
"rustc_middle",
"rustc_mir_build",
"rustc_mir_dataflow",
"rustc_mir_transform",
"rustc_monomorphize",
"rustc_parse",
"rustc_passes",
Expand Down Expand Up @@ -3861,8 +3862,10 @@ dependencies = [
"rustc_const_eval",
"rustc_data_structures",
"rustc_errors",
"rustc_fluent_macro",
"rustc_hir",
"rustc_index",
"rustc_macros",
"rustc_middle",
"rustc_mir_dataflow",
"rustc_serialize",
Expand Down
8 changes: 6 additions & 2 deletions compiler/rustc_driver_impl/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ rustc_interface = { path = "../rustc_interface" }
rustc_ast = { path = "../rustc_ast" }
rustc_span = { path = "../rustc_span" }
rustc_hir_analysis = { path = "../rustc_hir_analysis" }
rustc_mir_transform = { path = "../rustc_mir_transform" }

[target.'cfg(unix)'.dependencies]
libc = "0.2"
Expand All @@ -64,5 +65,8 @@ features = [
[features]
llvm = ['rustc_interface/llvm']
max_level_info = ['rustc_log/max_level_info']
rustc_use_parallel_compiler = ['rustc_data_structures/rustc_use_parallel_compiler', 'rustc_interface/rustc_use_parallel_compiler',
'rustc_middle/rustc_use_parallel_compiler']
rustc_use_parallel_compiler = [
'rustc_data_structures/rustc_use_parallel_compiler',
'rustc_interface/rustc_use_parallel_compiler',
'rustc_middle/rustc_use_parallel_compiler'
]
1 change: 1 addition & 0 deletions compiler/rustc_driver_impl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ pub static DEFAULT_LOCALE_RESOURCES: &[&str] = &[
rustc_middle::DEFAULT_LOCALE_RESOURCE,
rustc_mir_build::DEFAULT_LOCALE_RESOURCE,
rustc_mir_dataflow::DEFAULT_LOCALE_RESOURCE,
rustc_mir_transform::DEFAULT_LOCALE_RESOURCE,
rustc_monomorphize::DEFAULT_LOCALE_RESOURCE,
rustc_parse::DEFAULT_LOCALE_RESOURCE,
rustc_passes::DEFAULT_LOCALE_RESOURCE,
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_errors/src/diagnostic_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,14 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
Some((diagnostic, handler))
}

/// Retrieves the [`Handler`] if available
pub fn handler(&self) -> Option<&Handler> {
match self.inner.state {
DiagnosticBuilderState::Emittable(handler) => Some(handler),
DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => None,
}
}

/// Buffers the diagnostic for later emission,
/// unless handler has disabled such buffering.
pub fn buffer(self, buffered_diagnostics: &mut Vec<Diagnostic>) {
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_mir_transform/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ rustc_session = { path = "../rustc_session" }
rustc_target = { path = "../rustc_target" }
rustc_trait_selection = { path = "../rustc_trait_selection" }
rustc_span = { path = "../rustc_span" }
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_macros = { path = "../rustc_macros" }

[dev-dependencies]
coverage_test_macros = { path = "src/coverage/test_macros" }
66 changes: 66 additions & 0 deletions compiler/rustc_mir_transform/messages.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
mir_transform_const_modify = attempting to modify a `const` item
.note = each usage of a `const` item creates a new temporary; the original `const` item will not be modified
mir_transform_const_mut_borrow = taking a mutable reference to a `const` item
.note = each usage of a `const` item creates a new temporary
.note2 = the mutable reference will refer to this temporary, not the original `const` item
.note3 = mutable reference created due to call to this method
mir_transform_const_defined_here = `const` item defined here
mir_transform_unaligned_packed_ref = reference to packed field is unaligned
.note = packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
.note_ub = creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
.help = copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
mir_transform_unused_unsafe = unnecessary `unsafe` block
.label = because it's nested under this `unsafe` block
mir_transform_requires_unsafe = {$details} is unsafe and requires unsafe {$op_in_unsafe_fn_allowed ->
[true] function or block
*[false] block
}
.not_inherited = items do not inherit unsafety from separate enclosing items
mir_transform_call_to_unsafe_label = call to unsafe function
mir_transform_call_to_unsafe_note = consult the function's documentation for information on how to avoid undefined behavior
mir_transform_use_of_asm_label = use of inline assembly
mir_transform_use_of_asm_note = inline assembly is entirely unchecked and can cause undefined behavior
mir_transform_initializing_valid_range_label = initializing type with `rustc_layout_scalar_valid_range` attr
mir_transform_initializing_valid_range_note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
mir_transform_const_ptr2int_label = cast of pointer to int
mir_transform_const_ptr2int_note = casting pointers to integers in constants
mir_transform_use_of_static_mut_label = use of mutable static
mir_transform_use_of_static_mut_note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
mir_transform_use_of_extern_static_label = use of extern static
mir_transform_use_of_extern_static_note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
mir_transform_deref_ptr_label = dereference of raw pointer
mir_transform_deref_ptr_note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
mir_transform_union_access_label = access to union field
mir_transform_union_access_note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
mir_transform_mutation_layout_constrained_label = mutation of layout constrained field
mir_transform_mutation_layout_constrained_note = mutating layout constrained fields cannot statically be checked for valid values
mir_transform_mutation_layout_constrained_borrow_label = borrow of layout constrained field with interior mutability
mir_transform_mutation_layout_constrained_borrow_note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
mir_transform_target_feature_call_label = call to function with `#[target_feature]`
mir_transform_target_feature_call_note = can only be called if the required target features are available
mir_transform_unsafe_op_in_unsafe_fn = {$details} is unsafe and requires unsafe block (error E0133)
mir_transform_arithmetic_overflow = this arithmetic operation will overflow
mir_transform_operation_will_panic = this operation will panic at runtime
mir_transform_ffi_unwind_call = call to {$foreign ->
[true] foreign function
*[false] function pointer
} with FFI-unwind ABI
mir_transform_fn_item_ref = taking a reference to a function item does not give a function pointer
.suggestion = cast `{$ident}` to obtain a function pointer
mir_transform_must_not_suspend = {$pre}`{$def_path}`{$post} held across a suspend point, but should not be
.label = the value is held across this suspend point
.note = {$reason}
.help = consider using a block (`{"{ ... }"}`) to shrink the value's scope, ending before the suspend point
mir_transform_simd_shuffle_last_const = last argument of `simd_shuffle` is required to be a `const` item
65 changes: 33 additions & 32 deletions compiler/rustc_mir_transform/src/check_const_item_mutation.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use rustc_errors::{DiagnosticBuilder, DiagnosticMessage};
use rustc_hir::HirId;
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt;
use rustc_session::lint::builtin::CONST_ITEM_MUTATION;
use rustc_span::def_id::DefId;
use rustc_span::Span;

use crate::MirLint;
use crate::{errors, MirLint};

pub struct CheckConstItemMutation;

Expand Down Expand Up @@ -58,16 +59,14 @@ impl<'tcx> ConstMutationChecker<'_, 'tcx> {
}
}

fn lint_const_item_usage(
/// If we should lint on this usage, return the [`HirId`], source [`Span`]
/// and [`Span`] of the const item to use in the lint.
fn should_lint_const_item_usage(
&self,
place: &Place<'tcx>,
const_item: DefId,
location: Location,
msg: impl Into<DiagnosticMessage>,
decorate: impl for<'a, 'b> FnOnce(
&'a mut DiagnosticBuilder<'b, ()>,
) -> &'a mut DiagnosticBuilder<'b, ()>,
) {
) -> Option<(HirId, Span, Span)> {
// Don't lint on borrowing/assigning when a dereference is involved.
// If we 'leave' the temporary via a dereference, we must
// be modifying something else
Expand All @@ -83,16 +82,9 @@ impl<'tcx> ConstMutationChecker<'_, 'tcx> {
.assert_crate_local()
.lint_root;

self.tcx.struct_span_lint_hir(
CONST_ITEM_MUTATION,
lint_root,
source_info.span,
msg,
|lint| {
decorate(lint)
.span_note(self.tcx.def_span(const_item), "`const` item defined here")
},
);
Some((lint_root, source_info.span, self.tcx.def_span(const_item)))
} else {
None
}
}
}
Expand All @@ -104,10 +96,14 @@ impl<'tcx> Visitor<'tcx> for ConstMutationChecker<'_, 'tcx> {
// Assigning directly to a constant (e.g. `FOO = true;`) is a hard error,
// so emitting a lint would be redundant.
if !lhs.projection.is_empty() {
if let Some(def_id) = self.is_const_item_without_destructor(lhs.local) {
self.lint_const_item_usage(&lhs, def_id, loc, "attempting to modify a `const` item",|lint| {
lint.note("each usage of a `const` item creates a new temporary; the original `const` item will not be modified")
})
if let Some(def_id) = self.is_const_item_without_destructor(lhs.local)
&& let Some((lint_root, span, item)) = self.should_lint_const_item_usage(&lhs, def_id, loc) {
self.tcx.emit_spanned_lint(
CONST_ITEM_MUTATION,
lint_root,
span,
errors::ConstMutate::Modify { konst: item }
);
}
}
// We are looking for MIR of the form:
Expand Down Expand Up @@ -143,17 +139,22 @@ impl<'tcx> Visitor<'tcx> for ConstMutationChecker<'_, 'tcx> {
});
let lint_loc =
if method_did.is_some() { self.body.terminator_loc(loc.block) } else { loc };
self.lint_const_item_usage(place, def_id, lint_loc, "taking a mutable reference to a `const` item", |lint| {
lint
.note("each usage of a `const` item creates a new temporary")
.note("the mutable reference will refer to this temporary, not the original `const` item");

if let Some((method_did, _substs)) = method_did {
lint.span_note(self.tcx.def_span(method_did), "mutable reference created due to call to this method");
}

lint
});
let method_call = if let Some((method_did, _)) = method_did {
Some(self.tcx.def_span(method_did))
} else {
None
};
if let Some((lint_root, span, item)) =
self.should_lint_const_item_usage(place, def_id, lint_loc)
{
self.tcx.emit_spanned_lint(
CONST_ITEM_MUTATION,
lint_root,
span,
errors::ConstMutate::MutBorrow { method_call, konst: item },
);
}
}
}
self.super_rvalue(rvalue, loc);
Expand Down
23 changes: 2 additions & 21 deletions compiler/rustc_mir_transform/src/check_packed_ref.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use rustc_errors::struct_span_err;
use rustc_middle::mir::visit::{PlaceContext, Visitor};
use rustc_middle::mir::*;
use rustc_middle::ty::{self, TyCtxt};

use crate::util;
use crate::MirLint;
use crate::{errors, util};

pub struct CheckPackedRef;

Expand Down Expand Up @@ -49,25 +48,7 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> {
// shouldn't do.
span_bug!(self.source_info.span, "builtin derive created an unaligned reference");
} else {
struct_span_err!(
self.tcx.sess,
self.source_info.span,
E0793,
"reference to packed field is unaligned"
)
.note(
"packed structs are only aligned by one byte, and many modern architectures \
penalize unaligned field accesses"
)
.note(
"creating a misaligned reference is undefined behavior (even if that \
reference is never dereferenced)",
).help(
"copy the field contents to a local variable, or replace the \
reference with a raw pointer and use `read_unaligned`/`write_unaligned` \
(loads and stores via `*p` must be properly aligned even when using raw pointers)"
)
.emit();
self.tcx.sess.emit_err(errors::UnalignedPackedRef { span: self.source_info.span });
}
}
}
Expand Down
68 changes: 23 additions & 45 deletions compiler/rustc_mir_transform/src/check_unsafety.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use rustc_data_structures::unord::{UnordItems, UnordSet};
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
Expand All @@ -15,6 +14,8 @@ use rustc_session::lint::Level;

use std::ops::Bound;

use crate::errors;

pub struct UnsafetyChecker<'a, 'tcx> {
body: &'a Body<'tcx>,
body_did: LocalDefId,
Expand Down Expand Up @@ -509,21 +510,12 @@ fn unsafety_check_result(tcx: TyCtxt<'_>, def: LocalDefId) -> &UnsafetyCheckResu

fn report_unused_unsafe(tcx: TyCtxt<'_>, kind: UnusedUnsafe, id: HirId) {
let span = tcx.sess.source_map().guess_head_span(tcx.hir().span(id));
let msg = "unnecessary `unsafe` block";
tcx.struct_span_lint_hir(UNUSED_UNSAFE, id, span, msg, |lint| {
lint.span_label(span, msg);
match kind {
UnusedUnsafe::Unused => {}
UnusedUnsafe::InUnsafeBlock(id) => {
lint.span_label(
tcx.sess.source_map().guess_head_span(tcx.hir().span(id)),
"because it's nested under this `unsafe` block",
);
}
}

lint
});
let nested_parent = if let UnusedUnsafe::InUnsafeBlock(id) = kind {
Some(tcx.sess.source_map().guess_head_span(tcx.hir().span(id)))
} else {
None
};
tcx.emit_spanned_lint(UNUSED_UNSAFE, id, span, errors::UnusedUnsafe { span, nested_parent });
}

pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
Expand All @@ -537,26 +529,11 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let UnsafetyCheckResult { violations, unused_unsafes, .. } = tcx.unsafety_check_result(def_id);

for &UnsafetyViolation { source_info, lint_root, kind, details } in violations.iter() {
let (description, note) = details.description_and_note();
let details = errors::RequiresUnsafeDetail { violation: details, span: source_info.span };

match kind {
UnsafetyViolationKind::General => {
// once
let unsafe_fn_msg = if unsafe_op_in_unsafe_fn_allowed(tcx, lint_root) {
" function or"
} else {
""
};

let mut err = struct_span_err!(
tcx.sess,
source_info.span,
E0133,
"{} is unsafe and requires unsafe{} block",
description,
unsafe_fn_msg,
);
err.span_label(source_info.span, description).note(note);
let op_in_unsafe_fn_allowed = unsafe_op_in_unsafe_fn_allowed(tcx, lint_root);
let note_non_inherited = tcx.hir().parent_iter(lint_root).find(|(id, node)| {
if let Node::Expr(block) = node
&& let ExprKind::Block(block, _) = block.kind
Expand All @@ -572,22 +549,23 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
false
}
});
if let Some((id, _)) = note_non_inherited {
let span = tcx.hir().span(id);
err.span_label(
tcx.sess.source_map().guess_head_span(span),
"items do not inherit unsafety from separate enclosing items",
);
}

err.emit();
let enclosing = if let Some((id, _)) = note_non_inherited {
Some(tcx.sess.source_map().guess_head_span(tcx.hir().span(id)))
} else {
None
};
tcx.sess.emit_err(errors::RequiresUnsafe {
span: source_info.span,
enclosing,
details,
op_in_unsafe_fn_allowed,
});
}
UnsafetyViolationKind::UnsafeFn => tcx.struct_span_lint_hir(
UnsafetyViolationKind::UnsafeFn => tcx.emit_spanned_lint(
UNSAFE_OP_IN_UNSAFE_FN,
lint_root,
source_info.span,
format!("{} is unsafe and requires unsafe block (error E0133)", description,),
|lint| lint.span_label(source_info.span, description).note(note),
errors::UnsafeOpInUnsafeFn { details },
),
}
}
Expand Down
Loading

0 comments on commit 3e01276

Please sign in to comment.