Skip to content

Commit 6859414

Browse files
Rollup merge of rust-lang#111004 - clubby789:migrate-mir-transform, r=oli-obk
Migrate `mir_transform` to translatable diagnostics cc rust-lang#100717
2 parents 29ac429 + d5bc581 commit 6859414

16 files changed

+470
-200
lines changed

Cargo.lock

+3
Original file line numberDiff line numberDiff line change
@@ -3353,6 +3353,7 @@ dependencies = [
33533353
"rustc_middle",
33543354
"rustc_mir_build",
33553355
"rustc_mir_dataflow",
3356+
"rustc_mir_transform",
33563357
"rustc_monomorphize",
33573358
"rustc_parse",
33583359
"rustc_passes",
@@ -3861,8 +3862,10 @@ dependencies = [
38613862
"rustc_const_eval",
38623863
"rustc_data_structures",
38633864
"rustc_errors",
3865+
"rustc_fluent_macro",
38643866
"rustc_hir",
38653867
"rustc_index",
3868+
"rustc_macros",
38663869
"rustc_middle",
38673870
"rustc_mir_dataflow",
38683871
"rustc_serialize",

compiler/rustc_driver_impl/Cargo.toml

+6-2
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ rustc_interface = { path = "../rustc_interface" }
5151
rustc_ast = { path = "../rustc_ast" }
5252
rustc_span = { path = "../rustc_span" }
5353
rustc_hir_analysis = { path = "../rustc_hir_analysis" }
54+
rustc_mir_transform = { path = "../rustc_mir_transform" }
5455

5556
[target.'cfg(unix)'.dependencies]
5657
libc = "0.2"
@@ -64,5 +65,8 @@ features = [
6465
[features]
6566
llvm = ['rustc_interface/llvm']
6667
max_level_info = ['rustc_log/max_level_info']
67-
rustc_use_parallel_compiler = ['rustc_data_structures/rustc_use_parallel_compiler', 'rustc_interface/rustc_use_parallel_compiler',
68-
'rustc_middle/rustc_use_parallel_compiler']
68+
rustc_use_parallel_compiler = [
69+
'rustc_data_structures/rustc_use_parallel_compiler',
70+
'rustc_interface/rustc_use_parallel_compiler',
71+
'rustc_middle/rustc_use_parallel_compiler'
72+
]

compiler/rustc_driver_impl/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ pub static DEFAULT_LOCALE_RESOURCES: &[&str] = &[
9999
rustc_middle::DEFAULT_LOCALE_RESOURCE,
100100
rustc_mir_build::DEFAULT_LOCALE_RESOURCE,
101101
rustc_mir_dataflow::DEFAULT_LOCALE_RESOURCE,
102+
rustc_mir_transform::DEFAULT_LOCALE_RESOURCE,
102103
rustc_monomorphize::DEFAULT_LOCALE_RESOURCE,
103104
rustc_parse::DEFAULT_LOCALE_RESOURCE,
104105
rustc_passes::DEFAULT_LOCALE_RESOURCE,

compiler/rustc_errors/src/diagnostic_builder.rs

+8
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,14 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
571571
Some((diagnostic, handler))
572572
}
573573

574+
/// Retrieves the [`Handler`] if available
575+
pub fn handler(&self) -> Option<&Handler> {
576+
match self.inner.state {
577+
DiagnosticBuilderState::Emittable(handler) => Some(handler),
578+
DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => None,
579+
}
580+
}
581+
574582
/// Buffers the diagnostic for later emission,
575583
/// unless handler has disabled such buffering.
576584
pub fn buffer(self, buffered_diagnostics: &mut Vec<Diagnostic>) {

compiler/rustc_mir_transform/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ rustc_session = { path = "../rustc_session" }
2424
rustc_target = { path = "../rustc_target" }
2525
rustc_trait_selection = { path = "../rustc_trait_selection" }
2626
rustc_span = { path = "../rustc_span" }
27+
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
28+
rustc_macros = { path = "../rustc_macros" }
2729

2830
[dev-dependencies]
2931
coverage_test_macros = { path = "src/coverage/test_macros" }
+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
mir_transform_const_modify = attempting to modify a `const` item
2+
.note = each usage of a `const` item creates a new temporary; the original `const` item will not be modified
3+
4+
mir_transform_const_mut_borrow = taking a mutable reference to a `const` item
5+
.note = each usage of a `const` item creates a new temporary
6+
.note2 = the mutable reference will refer to this temporary, not the original `const` item
7+
.note3 = mutable reference created due to call to this method
8+
9+
mir_transform_const_defined_here = `const` item defined here
10+
11+
mir_transform_unaligned_packed_ref = reference to packed field is unaligned
12+
.note = packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
13+
.note_ub = creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
14+
.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)
15+
16+
mir_transform_unused_unsafe = unnecessary `unsafe` block
17+
.label = because it's nested under this `unsafe` block
18+
19+
mir_transform_requires_unsafe = {$details} is unsafe and requires unsafe {$op_in_unsafe_fn_allowed ->
20+
[true] function or block
21+
*[false] block
22+
}
23+
.not_inherited = items do not inherit unsafety from separate enclosing items
24+
25+
mir_transform_call_to_unsafe_label = call to unsafe function
26+
mir_transform_call_to_unsafe_note = consult the function's documentation for information on how to avoid undefined behavior
27+
mir_transform_use_of_asm_label = use of inline assembly
28+
mir_transform_use_of_asm_note = inline assembly is entirely unchecked and can cause undefined behavior
29+
mir_transform_initializing_valid_range_label = initializing type with `rustc_layout_scalar_valid_range` attr
30+
mir_transform_initializing_valid_range_note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
31+
mir_transform_const_ptr2int_label = cast of pointer to int
32+
mir_transform_const_ptr2int_note = casting pointers to integers in constants
33+
mir_transform_use_of_static_mut_label = use of mutable static
34+
mir_transform_use_of_static_mut_note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
35+
mir_transform_use_of_extern_static_label = use of extern static
36+
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
37+
mir_transform_deref_ptr_label = dereference of raw pointer
38+
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
39+
mir_transform_union_access_label = access to union field
40+
mir_transform_union_access_note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
41+
mir_transform_mutation_layout_constrained_label = mutation of layout constrained field
42+
mir_transform_mutation_layout_constrained_note = mutating layout constrained fields cannot statically be checked for valid values
43+
mir_transform_mutation_layout_constrained_borrow_label = borrow of layout constrained field with interior mutability
44+
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
45+
mir_transform_target_feature_call_label = call to function with `#[target_feature]`
46+
mir_transform_target_feature_call_note = can only be called if the required target features are available
47+
48+
mir_transform_unsafe_op_in_unsafe_fn = {$details} is unsafe and requires unsafe block (error E0133)
49+
50+
mir_transform_arithmetic_overflow = this arithmetic operation will overflow
51+
mir_transform_operation_will_panic = this operation will panic at runtime
52+
53+
mir_transform_ffi_unwind_call = call to {$foreign ->
54+
[true] foreign function
55+
*[false] function pointer
56+
} with FFI-unwind ABI
57+
58+
mir_transform_fn_item_ref = taking a reference to a function item does not give a function pointer
59+
.suggestion = cast `{$ident}` to obtain a function pointer
60+
61+
mir_transform_must_not_suspend = {$pre}`{$def_path}`{$post} held across a suspend point, but should not be
62+
.label = the value is held across this suspend point
63+
.note = {$reason}
64+
.help = consider using a block (`{"{ ... }"}`) to shrink the value's scope, ending before the suspend point
65+
66+
mir_transform_simd_shuffle_last_const = last argument of `simd_shuffle` is required to be a `const` item

compiler/rustc_mir_transform/src/check_const_item_mutation.rs

+33-32
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
use rustc_errors::{DiagnosticBuilder, DiagnosticMessage};
1+
use rustc_hir::HirId;
22
use rustc_middle::mir::visit::Visitor;
33
use rustc_middle::mir::*;
44
use rustc_middle::ty::TyCtxt;
55
use rustc_session::lint::builtin::CONST_ITEM_MUTATION;
66
use rustc_span::def_id::DefId;
7+
use rustc_span::Span;
78

8-
use crate::MirLint;
9+
use crate::{errors, MirLint};
910

1011
pub struct CheckConstItemMutation;
1112

@@ -58,16 +59,14 @@ impl<'tcx> ConstMutationChecker<'_, 'tcx> {
5859
}
5960
}
6061

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

86-
self.tcx.struct_span_lint_hir(
87-
CONST_ITEM_MUTATION,
88-
lint_root,
89-
source_info.span,
90-
msg,
91-
|lint| {
92-
decorate(lint)
93-
.span_note(self.tcx.def_span(const_item), "`const` item defined here")
94-
},
95-
);
85+
Some((lint_root, source_info.span, self.tcx.def_span(const_item)))
86+
} else {
87+
None
9688
}
9789
}
9890
}
@@ -104,10 +96,14 @@ impl<'tcx> Visitor<'tcx> for ConstMutationChecker<'_, 'tcx> {
10496
// Assigning directly to a constant (e.g. `FOO = true;`) is a hard error,
10597
// so emitting a lint would be redundant.
10698
if !lhs.projection.is_empty() {
107-
if let Some(def_id) = self.is_const_item_without_destructor(lhs.local) {
108-
self.lint_const_item_usage(&lhs, def_id, loc, "attempting to modify a `const` item",|lint| {
109-
lint.note("each usage of a `const` item creates a new temporary; the original `const` item will not be modified")
110-
})
99+
if let Some(def_id) = self.is_const_item_without_destructor(lhs.local)
100+
&& let Some((lint_root, span, item)) = self.should_lint_const_item_usage(&lhs, def_id, loc) {
101+
self.tcx.emit_spanned_lint(
102+
CONST_ITEM_MUTATION,
103+
lint_root,
104+
span,
105+
errors::ConstMutate::Modify { konst: item }
106+
);
111107
}
112108
}
113109
// We are looking for MIR of the form:
@@ -143,17 +139,22 @@ impl<'tcx> Visitor<'tcx> for ConstMutationChecker<'_, 'tcx> {
143139
});
144140
let lint_loc =
145141
if method_did.is_some() { self.body.terminator_loc(loc.block) } else { loc };
146-
self.lint_const_item_usage(place, def_id, lint_loc, "taking a mutable reference to a `const` item", |lint| {
147-
lint
148-
.note("each usage of a `const` item creates a new temporary")
149-
.note("the mutable reference will refer to this temporary, not the original `const` item");
150-
151-
if let Some((method_did, _substs)) = method_did {
152-
lint.span_note(self.tcx.def_span(method_did), "mutable reference created due to call to this method");
153-
}
154142

155-
lint
156-
});
143+
let method_call = if let Some((method_did, _)) = method_did {
144+
Some(self.tcx.def_span(method_did))
145+
} else {
146+
None
147+
};
148+
if let Some((lint_root, span, item)) =
149+
self.should_lint_const_item_usage(place, def_id, lint_loc)
150+
{
151+
self.tcx.emit_spanned_lint(
152+
CONST_ITEM_MUTATION,
153+
lint_root,
154+
span,
155+
errors::ConstMutate::MutBorrow { method_call, konst: item },
156+
);
157+
}
157158
}
158159
}
159160
self.super_rvalue(rvalue, loc);

compiler/rustc_mir_transform/src/check_packed_ref.rs

+2-21
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
use rustc_errors::struct_span_err;
21
use rustc_middle::mir::visit::{PlaceContext, Visitor};
32
use rustc_middle::mir::*;
43
use rustc_middle::ty::{self, TyCtxt};
54

6-
use crate::util;
75
use crate::MirLint;
6+
use crate::{errors, util};
87

98
pub struct CheckPackedRef;
109

@@ -49,25 +48,7 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> {
4948
// shouldn't do.
5049
span_bug!(self.source_info.span, "builtin derive created an unaligned reference");
5150
} else {
52-
struct_span_err!(
53-
self.tcx.sess,
54-
self.source_info.span,
55-
E0793,
56-
"reference to packed field is unaligned"
57-
)
58-
.note(
59-
"packed structs are only aligned by one byte, and many modern architectures \
60-
penalize unaligned field accesses"
61-
)
62-
.note(
63-
"creating a misaligned reference is undefined behavior (even if that \
64-
reference is never dereferenced)",
65-
).help(
66-
"copy the field contents to a local variable, or replace the \
67-
reference with a raw pointer and use `read_unaligned`/`write_unaligned` \
68-
(loads and stores via `*p` must be properly aligned even when using raw pointers)"
69-
)
70-
.emit();
51+
self.tcx.sess.emit_err(errors::UnalignedPackedRef { span: self.source_info.span });
7152
}
7253
}
7354
}

compiler/rustc_mir_transform/src/check_unsafety.rs

+23-45
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use rustc_data_structures::unord::{UnordItems, UnordSet};
2-
use rustc_errors::struct_span_err;
32
use rustc_hir as hir;
43
use rustc_hir::def::DefKind;
54
use rustc_hir::def_id::{DefId, LocalDefId};
@@ -15,6 +14,8 @@ use rustc_session::lint::Level;
1514

1615
use std::ops::Bound;
1716

17+
use crate::errors;
18+
1819
pub struct UnsafetyChecker<'a, 'tcx> {
1920
body: &'a Body<'tcx>,
2021
body_did: LocalDefId,
@@ -509,21 +510,12 @@ fn unsafety_check_result(tcx: TyCtxt<'_>, def: LocalDefId) -> &UnsafetyCheckResu
509510

510511
fn report_unused_unsafe(tcx: TyCtxt<'_>, kind: UnusedUnsafe, id: HirId) {
511512
let span = tcx.sess.source_map().guess_head_span(tcx.hir().span(id));
512-
let msg = "unnecessary `unsafe` block";
513-
tcx.struct_span_lint_hir(UNUSED_UNSAFE, id, span, msg, |lint| {
514-
lint.span_label(span, msg);
515-
match kind {
516-
UnusedUnsafe::Unused => {}
517-
UnusedUnsafe::InUnsafeBlock(id) => {
518-
lint.span_label(
519-
tcx.sess.source_map().guess_head_span(tcx.hir().span(id)),
520-
"because it's nested under this `unsafe` block",
521-
);
522-
}
523-
}
524-
525-
lint
526-
});
513+
let nested_parent = if let UnusedUnsafe::InUnsafeBlock(id) = kind {
514+
Some(tcx.sess.source_map().guess_head_span(tcx.hir().span(id)))
515+
} else {
516+
None
517+
};
518+
tcx.emit_spanned_lint(UNUSED_UNSAFE, id, span, errors::UnusedUnsafe { span, nested_parent });
527519
}
528520

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

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

542534
match kind {
543535
UnsafetyViolationKind::General => {
544-
// once
545-
let unsafe_fn_msg = if unsafe_op_in_unsafe_fn_allowed(tcx, lint_root) {
546-
" function or"
547-
} else {
548-
""
549-
};
550-
551-
let mut err = struct_span_err!(
552-
tcx.sess,
553-
source_info.span,
554-
E0133,
555-
"{} is unsafe and requires unsafe{} block",
556-
description,
557-
unsafe_fn_msg,
558-
);
559-
err.span_label(source_info.span, description).note(note);
536+
let op_in_unsafe_fn_allowed = unsafe_op_in_unsafe_fn_allowed(tcx, lint_root);
560537
let note_non_inherited = tcx.hir().parent_iter(lint_root).find(|(id, node)| {
561538
if let Node::Expr(block) = node
562539
&& let ExprKind::Block(block, _) = block.kind
@@ -572,22 +549,23 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
572549
false
573550
}
574551
});
575-
if let Some((id, _)) = note_non_inherited {
576-
let span = tcx.hir().span(id);
577-
err.span_label(
578-
tcx.sess.source_map().guess_head_span(span),
579-
"items do not inherit unsafety from separate enclosing items",
580-
);
581-
}
582-
583-
err.emit();
552+
let enclosing = if let Some((id, _)) = note_non_inherited {
553+
Some(tcx.sess.source_map().guess_head_span(tcx.hir().span(id)))
554+
} else {
555+
None
556+
};
557+
tcx.sess.emit_err(errors::RequiresUnsafe {
558+
span: source_info.span,
559+
enclosing,
560+
details,
561+
op_in_unsafe_fn_allowed,
562+
});
584563
}
585-
UnsafetyViolationKind::UnsafeFn => tcx.struct_span_lint_hir(
564+
UnsafetyViolationKind::UnsafeFn => tcx.emit_spanned_lint(
586565
UNSAFE_OP_IN_UNSAFE_FN,
587566
lint_root,
588567
source_info.span,
589-
format!("{} is unsafe and requires unsafe block (error E0133)", description,),
590-
|lint| lint.span_label(source_info.span, description).note(note),
568+
errors::UnsafeOpInUnsafeFn { details },
591569
),
592570
}
593571
}

0 commit comments

Comments
 (0)