Skip to content

Commit 8b8f665

Browse files
committed
add DefId to unsafety violations and display function path in E0133
this enables consumers to access the function definition that was reported to be unsafe
1 parent d8e59ed commit 8b8f665

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+228
-200
lines changed

compiler/rustc_middle/src/mir/query.rs

+28-19
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use rustc_index::vec::IndexVec;
1212
use rustc_span::Span;
1313
use rustc_target::abi::VariantIdx;
1414
use smallvec::SmallVec;
15+
use std::borrow::Cow;
1516
use std::cell::Cell;
1617
use std::fmt::{self, Debug};
1718

@@ -28,7 +29,7 @@ pub enum UnsafetyViolationKind {
2829

2930
#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
3031
pub enum UnsafetyViolationDetails {
31-
CallToUnsafeFunction,
32+
CallToUnsafeFunction(Option<DefId>),
3233
UseOfInlineAssembly,
3334
InitializingTypeWith,
3435
CastOfPointerToInt,
@@ -39,66 +40,74 @@ pub enum UnsafetyViolationDetails {
3940
AccessToUnionField,
4041
MutationOfLayoutConstrainedField,
4142
BorrowOfLayoutConstrainedField,
42-
CallToFunctionWith,
43+
CallToFunctionWith(DefId),
4344
}
4445

4546
impl UnsafetyViolationDetails {
46-
pub fn description_and_note(&self) -> (&'static str, &'static str) {
47+
pub fn description_and_note(&self, tcx: TyCtxt<'_>) -> (Cow<'static, str>, &'static str) {
4748
use UnsafetyViolationDetails::*;
4849
match self {
49-
CallToUnsafeFunction => (
50-
"call to unsafe function",
50+
CallToUnsafeFunction(did) => (
51+
if let Some(did) = did {
52+
Cow::from(format!("call to unsafe function `{}`", tcx.def_path_str(*did)))
53+
} else {
54+
Cow::Borrowed("call to unsafe function")
55+
},
5156
"consult the function's documentation for information on how to avoid undefined \
5257
behavior",
5358
),
5459
UseOfInlineAssembly => (
55-
"use of inline assembly",
60+
Cow::Borrowed("use of inline assembly"),
5661
"inline assembly is entirely unchecked and can cause undefined behavior",
5762
),
5863
InitializingTypeWith => (
59-
"initializing type with `rustc_layout_scalar_valid_range` attr",
64+
Cow::Borrowed("initializing type with `rustc_layout_scalar_valid_range` attr"),
6065
"initializing a layout restricted type's field with a value outside the valid \
6166
range is undefined behavior",
6267
),
63-
CastOfPointerToInt => {
64-
("cast of pointer to int", "casting pointers to integers in constants")
65-
}
68+
CastOfPointerToInt => (
69+
Cow::Borrowed("cast of pointer to int"),
70+
"casting pointers to integers in constants",
71+
),
6672
UseOfMutableStatic => (
67-
"use of mutable static",
73+
Cow::Borrowed("use of mutable static"),
6874
"mutable statics can be mutated by multiple threads: aliasing violations or data \
6975
races will cause undefined behavior",
7076
),
7177
UseOfExternStatic => (
72-
"use of extern static",
78+
Cow::Borrowed("use of extern static"),
7379
"extern statics are not controlled by the Rust type system: invalid data, \
7480
aliasing violations or data races will cause undefined behavior",
7581
),
7682
DerefOfRawPointer => (
77-
"dereference of raw pointer",
83+
Cow::Borrowed("dereference of raw pointer"),
7884
"raw pointers may be null, dangling or unaligned; they can violate aliasing rules \
7985
and cause data races: all of these are undefined behavior",
8086
),
8187
AssignToDroppingUnionField => (
82-
"assignment to union field that might need dropping",
88+
Cow::Borrowed("assignment to union field that might need dropping"),
8389
"the previous content of the field will be dropped, which causes undefined \
8490
behavior if the field was not properly initialized",
8591
),
8692
AccessToUnionField => (
87-
"access to union field",
93+
Cow::Borrowed("access to union field"),
8894
"the field may not be properly initialized: using uninitialized data will cause \
8995
undefined behavior",
9096
),
9197
MutationOfLayoutConstrainedField => (
92-
"mutation of layout constrained field",
98+
Cow::Borrowed("mutation of layout constrained field"),
9399
"mutating layout constrained fields cannot statically be checked for valid values",
94100
),
95101
BorrowOfLayoutConstrainedField => (
96-
"borrow of layout constrained field with interior mutability",
102+
Cow::Borrowed("borrow of layout constrained field with interior mutability"),
97103
"references to fields of layout constrained fields lose the constraints. Coupled \
98104
with interior mutability, the field can be changed to invalid values",
99105
),
100-
CallToFunctionWith => (
101-
"call to function with `#[target_feature]`",
106+
CallToFunctionWith(did) => (
107+
Cow::from(format!(
108+
"call to function `{}` with `#[target_feature]`",
109+
tcx.def_path_str(*did)
110+
)),
102111
"can only be called if the required target features are available",
103112
),
104113
}

compiler/rustc_mir_build/src/check_unsafety.rs

+33-19
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use rustc_span::def_id::{DefId, LocalDefId};
1212
use rustc_span::symbol::Symbol;
1313
use rustc_span::Span;
1414

15+
use std::borrow::Cow;
1516
use std::ops::Bound;
1617

1718
struct UnsafetyVisitor<'a, 'tcx> {
@@ -70,7 +71,6 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
7071
}
7172

7273
fn requires_unsafe(&mut self, span: Span, kind: UnsafeOpKind) {
73-
let (description, note) = kind.description_and_note();
7474
let unsafe_op_in_unsafe_fn_allowed = self.unsafe_op_in_unsafe_fn_allowed();
7575
match self.safety_context {
7676
SafetyContext::BuiltinUnsafeBlock => {}
@@ -82,6 +82,7 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
8282
}
8383
SafetyContext::UnsafeFn if unsafe_op_in_unsafe_fn_allowed => {}
8484
SafetyContext::UnsafeFn => {
85+
let (description, note) = kind.description_and_note(self.tcx);
8586
// unsafe_op_in_unsafe_fn is disallowed
8687
self.tcx.struct_span_lint_hir(
8788
UNSAFE_OP_IN_UNSAFE_FN,
@@ -99,6 +100,7 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
99100
)
100101
}
101102
SafetyContext::Safe => {
103+
let (description, note) = kind.description_and_note(self.tcx);
102104
let fn_sugg = if unsafe_op_in_unsafe_fn_allowed { " function or" } else { "" };
103105
struct_span_err!(
104106
self.tcx.sess,
@@ -350,7 +352,12 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
350352
}
351353
ExprKind::Call { fun, ty: _, args: _, from_hir_call: _, fn_span: _ } => {
352354
if self.thir[fun].ty.fn_sig(self.tcx).unsafety() == hir::Unsafety::Unsafe {
353-
self.requires_unsafe(expr.span, CallToUnsafeFunction);
355+
let func_id = if let ty::FnDef(func_id, _) = self.thir[fun].ty.kind() {
356+
Some(*func_id)
357+
} else {
358+
None
359+
};
360+
self.requires_unsafe(expr.span, CallToUnsafeFunction(func_id));
354361
} else if let &ty::FnDef(func_did, _) = self.thir[fun].ty.kind() {
355362
// If the called function has target features the calling function hasn't,
356363
// the call requires `unsafe`. Don't check this on wasm
@@ -364,7 +371,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
364371
.iter()
365372
.all(|feature| self.body_target_features.contains(feature))
366373
{
367-
self.requires_unsafe(expr.span, CallToFunctionWith);
374+
self.requires_unsafe(expr.span, CallToFunctionWith(func_did));
368375
}
369376
}
370377
}
@@ -523,7 +530,7 @@ impl BodyUnsafety {
523530

524531
#[derive(Clone, Copy, PartialEq)]
525532
enum UnsafeOpKind {
526-
CallToUnsafeFunction,
533+
CallToUnsafeFunction(Option<DefId>),
527534
UseOfInlineAssembly,
528535
InitializingTypeWith,
529536
UseOfMutableStatic,
@@ -533,64 +540,71 @@ enum UnsafeOpKind {
533540
AccessToUnionField,
534541
MutationOfLayoutConstrainedField,
535542
BorrowOfLayoutConstrainedField,
536-
CallToFunctionWith,
543+
CallToFunctionWith(DefId),
537544
}
538545

539546
use UnsafeOpKind::*;
540547

541548
impl UnsafeOpKind {
542-
pub fn description_and_note(&self) -> (&'static str, &'static str) {
549+
pub fn description_and_note(&self, tcx: TyCtxt<'_>) -> (Cow<'static, str>, &'static str) {
543550
match self {
544-
CallToUnsafeFunction => (
545-
"call to unsafe function",
551+
CallToUnsafeFunction(did) => (
552+
if let Some(did) = did {
553+
Cow::from(format!("call to unsafe function `{}`", tcx.def_path_str(*did)))
554+
} else {
555+
Cow::Borrowed("call to unsafe function")
556+
},
546557
"consult the function's documentation for information on how to avoid undefined \
547558
behavior",
548559
),
549560
UseOfInlineAssembly => (
550-
"use of inline assembly",
561+
Cow::Borrowed("use of inline assembly"),
551562
"inline assembly is entirely unchecked and can cause undefined behavior",
552563
),
553564
InitializingTypeWith => (
554-
"initializing type with `rustc_layout_scalar_valid_range` attr",
565+
Cow::Borrowed("initializing type with `rustc_layout_scalar_valid_range` attr"),
555566
"initializing a layout restricted type's field with a value outside the valid \
556567
range is undefined behavior",
557568
),
558569
UseOfMutableStatic => (
559-
"use of mutable static",
570+
Cow::Borrowed("use of mutable static"),
560571
"mutable statics can be mutated by multiple threads: aliasing violations or data \
561572
races will cause undefined behavior",
562573
),
563574
UseOfExternStatic => (
564-
"use of extern static",
575+
Cow::Borrowed("use of extern static"),
565576
"extern statics are not controlled by the Rust type system: invalid data, \
566577
aliasing violations or data races will cause undefined behavior",
567578
),
568579
DerefOfRawPointer => (
569-
"dereference of raw pointer",
580+
Cow::Borrowed("dereference of raw pointer"),
570581
"raw pointers may be null, dangling or unaligned; they can violate aliasing rules \
571582
and cause data races: all of these are undefined behavior",
572583
),
573584
AssignToDroppingUnionField => (
574-
"assignment to union field that might need dropping",
585+
Cow::Borrowed("assignment to union field that might need dropping"),
575586
"the previous content of the field will be dropped, which causes undefined \
576587
behavior if the field was not properly initialized",
577588
),
578589
AccessToUnionField => (
579-
"access to union field",
590+
Cow::Borrowed("access to union field"),
580591
"the field may not be properly initialized: using uninitialized data will cause \
581592
undefined behavior",
582593
),
583594
MutationOfLayoutConstrainedField => (
584-
"mutation of layout constrained field",
595+
Cow::Borrowed("mutation of layout constrained field"),
585596
"mutating layout constrained fields cannot statically be checked for valid values",
586597
),
587598
BorrowOfLayoutConstrainedField => (
588-
"borrow of layout constrained field with interior mutability",
599+
Cow::Borrowed("borrow of layout constrained field with interior mutability"),
589600
"references to fields of layout constrained fields lose the constraints. Coupled \
590601
with interior mutability, the field can be changed to invalid values",
591602
),
592-
CallToFunctionWith => (
593-
"call to function with `#[target_feature]`",
603+
CallToFunctionWith(did) => (
604+
Cow::from(format!(
605+
"call to function `{}` with `#[target_feature]`",
606+
tcx.def_path_str(*did)
607+
)),
594608
"can only be called if the required target features are available",
595609
),
596610
}

compiler/rustc_mir_transform/src/check_unsafety.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -70,15 +70,17 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
7070

7171
TerminatorKind::Call { ref func, .. } => {
7272
let func_ty = func.ty(self.body, self.tcx);
73+
let func_id =
74+
if let ty::FnDef(func_id, _) = func_ty.kind() { Some(func_id) } else { None };
7375
let sig = func_ty.fn_sig(self.tcx);
7476
if let hir::Unsafety::Unsafe = sig.unsafety() {
7577
self.require_unsafe(
7678
UnsafetyViolationKind::General,
77-
UnsafetyViolationDetails::CallToUnsafeFunction,
79+
UnsafetyViolationDetails::CallToUnsafeFunction(func_id.copied()),
7880
)
7981
}
8082

81-
if let ty::FnDef(func_id, _) = func_ty.kind() {
83+
if let Some(func_id) = func_id {
8284
self.check_target_features(*func_id);
8385
}
8486
}
@@ -379,7 +381,7 @@ impl<'tcx> UnsafetyChecker<'_, 'tcx> {
379381
if !callee_features.iter().all(|feature| self_features.contains(feature)) {
380382
self.require_unsafe(
381383
UnsafetyViolationKind::General,
382-
UnsafetyViolationDetails::CallToFunctionWith,
384+
UnsafetyViolationDetails::CallToFunctionWith(func_did),
383385
)
384386
}
385387
}
@@ -578,7 +580,8 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
578580
let UnsafetyCheckResult { violations, unused_unsafes, .. } = tcx.unsafety_check_result(def_id);
579581

580582
for &UnsafetyViolation { source_info, lint_root, kind, details } in violations.iter() {
581-
let (description, note) = details.description_and_note();
583+
let (description, note) =
584+
ty::print::with_no_trimmed_paths!(details.description_and_note(tcx));
582585

583586
// Report an error.
584587
let unsafe_fn_msg =

src/test/ui/async-await/async-unsafe-fn-call-in-safe.mir.stderr

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,32 @@
1-
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
1+
error[E0133]: call to unsafe function `S::f` is unsafe and requires unsafe function or block
22
--> $DIR/async-unsafe-fn-call-in-safe.rs:14:5
33
|
44
LL | S::f();
5-
| ^^^^^^ call to unsafe function
5+
| ^^^^^^ call to unsafe function `S::f`
66
|
77
= note: consult the function's documentation for information on how to avoid undefined behavior
88

9-
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
9+
error[E0133]: call to unsafe function `f` is unsafe and requires unsafe function or block
1010
--> $DIR/async-unsafe-fn-call-in-safe.rs:15:5
1111
|
1212
LL | f();
13-
| ^^^ call to unsafe function
13+
| ^^^ call to unsafe function `f`
1414
|
1515
= note: consult the function's documentation for information on how to avoid undefined behavior
1616

17-
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
17+
error[E0133]: call to unsafe function `S::f` is unsafe and requires unsafe function or block
1818
--> $DIR/async-unsafe-fn-call-in-safe.rs:19:5
1919
|
2020
LL | S::f();
21-
| ^^^^^^ call to unsafe function
21+
| ^^^^^^ call to unsafe function `S::f`
2222
|
2323
= note: consult the function's documentation for information on how to avoid undefined behavior
2424

25-
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
25+
error[E0133]: call to unsafe function `f` is unsafe and requires unsafe function or block
2626
--> $DIR/async-unsafe-fn-call-in-safe.rs:20:5
2727
|
2828
LL | f();
29-
| ^^^ call to unsafe function
29+
| ^^^ call to unsafe function `f`
3030
|
3131
= note: consult the function's documentation for information on how to avoid undefined behavior
3232

src/test/ui/async-await/async-unsafe-fn-call-in-safe.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ impl S {
1111
async unsafe fn f() {}
1212

1313
async fn g() {
14-
S::f(); //~ ERROR call to unsafe function is unsafe
15-
f(); //~ ERROR call to unsafe function is unsafe
14+
S::f(); //~ ERROR call to unsafe function `S::f` is unsafe
15+
f(); //~ ERROR call to unsafe function `f` is unsafe
1616
}
1717

1818
fn main() {
19-
S::f(); //[mir]~ ERROR call to unsafe function is unsafe
20-
f(); //[mir]~ ERROR call to unsafe function is unsafe
19+
S::f(); //[mir]~ ERROR call to unsafe function `S::f` is unsafe
20+
f(); //[mir]~ ERROR call to unsafe function `f` is unsafe
2121
}

src/test/ui/async-await/async-unsafe-fn-call-in-safe.thir.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
1+
error[E0133]: call to unsafe function `S::f` is unsafe and requires unsafe function or block
22
--> $DIR/async-unsafe-fn-call-in-safe.rs:14:5
33
|
44
LL | S::f();
5-
| ^^^^^^ call to unsafe function
5+
| ^^^^^^ call to unsafe function `S::f`
66
|
77
= note: consult the function's documentation for information on how to avoid undefined behavior
88

9-
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
9+
error[E0133]: call to unsafe function `f` is unsafe and requires unsafe function or block
1010
--> $DIR/async-unsafe-fn-call-in-safe.rs:15:5
1111
|
1212
LL | f();
13-
| ^^^ call to unsafe function
13+
| ^^^ call to unsafe function `f`
1414
|
1515
= note: consult the function's documentation for information on how to avoid undefined behavior
1616

src/test/ui/closures/coerce-unsafe-closure-to-unsafe-fn-ptr.mir.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
1+
error[E0133]: call to unsafe function `std::pin::Pin::<P>::new_unchecked` is unsafe and requires unsafe function or block
22
--> $DIR/coerce-unsafe-closure-to-unsafe-fn-ptr.rs:5:31
33
|
44
LL | let _: unsafe fn() = || { ::std::pin::Pin::new_unchecked(&0_u8); };
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function `std::pin::Pin::<P>::new_unchecked`
66
|
77
= note: consult the function's documentation for information on how to avoid undefined behavior
88

src/test/ui/closures/coerce-unsafe-closure-to-unsafe-fn-ptr.thir.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
1+
error[E0133]: call to unsafe function `Pin::<P>::new_unchecked` is unsafe and requires unsafe function or block
22
--> $DIR/coerce-unsafe-closure-to-unsafe-fn-ptr.rs:5:31
33
|
44
LL | let _: unsafe fn() = || { ::std::pin::Pin::new_unchecked(&0_u8); };
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function `Pin::<P>::new_unchecked`
66
|
77
= note: consult the function's documentation for information on how to avoid undefined behavior
88

0 commit comments

Comments
 (0)