Skip to content

Commit 45e2c28

Browse files
committed
Auto merge of #93678 - steffahn:better_unsafe_diagnostics, r=nagisa
Improve `unused_unsafe` lint I’m going to add some motivation and explanation below, particularly pointing the changes in behavior from this PR. _Edit:_ Looking for existing issues, looks like this PR fixes #88260. _Edit2:_ Now also contains code that closes #90776.
2 parents 523a1b1 + 8f8689f commit 45e2c28

File tree

11 files changed

+3209
-244
lines changed

11 files changed

+3209
-244
lines changed

compiler/rustc_codegen_llvm/src/abi.rs

+5-7
Original file line numberDiff line numberDiff line change
@@ -599,13 +599,11 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
599599
if self.conv == Conv::CCmseNonSecureCall {
600600
// This will probably get ignored on all targets but those supporting the TrustZone-M
601601
// extension (thumbv8m targets).
602-
unsafe {
603-
llvm::AddCallSiteAttrString(
604-
callsite,
605-
llvm::AttributePlace::Function,
606-
cstr::cstr!("cmse_nonsecure_call"),
607-
);
608-
}
602+
llvm::AddCallSiteAttrString(
603+
callsite,
604+
llvm::AttributePlace::Function,
605+
cstr::cstr!("cmse_nonsecure_call"),
606+
);
609607
}
610608
}
611609
}

compiler/rustc_middle/src/hir/nested_filter.rs

+4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ use rustc_hir::intravisit::nested_filter::NestedFilter;
33
/// Do not visit nested item-like things, but visit nested things
44
/// that are inside of an item-like.
55
///
6+
/// Notably, possible occurrences of bodies in non-item-like things
7+
/// include: closures/generators, inline `const {}` blocks, and
8+
/// constant arguments of types, e.g. in `let _: [(); /* HERE */];`.
9+
///
610
/// **This is the most common choice.** A very common pattern is
711
/// to use `visit_all_item_likes()` as an outer loop,
812
/// and to have the visitor that visits the contents of each item

compiler/rustc_middle/src/lint.rs

+73-62
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,77 @@ impl<'a> LintDiagnosticBuilder<'a> {
202202
}
203203
}
204204

205+
pub fn explain_lint_level_source<'s>(
206+
sess: &'s Session,
207+
lint: &'static Lint,
208+
level: Level,
209+
src: LintLevelSource,
210+
err: &mut DiagnosticBuilder<'s>,
211+
) {
212+
let name = lint.name_lower();
213+
match src {
214+
LintLevelSource::Default => {
215+
sess.diag_note_once(
216+
err,
217+
DiagnosticMessageId::from(lint),
218+
&format!("`#[{}({})]` on by default", level.as_str(), name),
219+
);
220+
}
221+
LintLevelSource::CommandLine(lint_flag_val, orig_level) => {
222+
let flag = match orig_level {
223+
Level::Warn => "-W",
224+
Level::Deny => "-D",
225+
Level::Forbid => "-F",
226+
Level::Allow => "-A",
227+
Level::ForceWarn => "--force-warn",
228+
};
229+
let hyphen_case_lint_name = name.replace('_', "-");
230+
if lint_flag_val.as_str() == name {
231+
sess.diag_note_once(
232+
err,
233+
DiagnosticMessageId::from(lint),
234+
&format!(
235+
"requested on the command line with `{} {}`",
236+
flag, hyphen_case_lint_name
237+
),
238+
);
239+
} else {
240+
let hyphen_case_flag_val = lint_flag_val.as_str().replace('_', "-");
241+
sess.diag_note_once(
242+
err,
243+
DiagnosticMessageId::from(lint),
244+
&format!(
245+
"`{} {}` implied by `{} {}`",
246+
flag, hyphen_case_lint_name, flag, hyphen_case_flag_val
247+
),
248+
);
249+
}
250+
}
251+
LintLevelSource::Node(lint_attr_name, src, reason) => {
252+
if let Some(rationale) = reason {
253+
err.note(rationale.as_str());
254+
}
255+
sess.diag_span_note_once(
256+
err,
257+
DiagnosticMessageId::from(lint),
258+
src,
259+
"the lint level is defined here",
260+
);
261+
if lint_attr_name.as_str() != name {
262+
let level_str = level.as_str();
263+
sess.diag_note_once(
264+
err,
265+
DiagnosticMessageId::from(lint),
266+
&format!(
267+
"`#[{}({})]` implied by `#[{}({})]`",
268+
level_str, name, level_str, lint_attr_name
269+
),
270+
);
271+
}
272+
}
273+
}
274+
}
275+
205276
pub fn struct_lint_level<'s, 'd>(
206277
sess: &'s Session,
207278
lint: &'static Lint,
@@ -277,69 +348,9 @@ pub fn struct_lint_level<'s, 'd>(
277348
}
278349
}
279350

280-
let name = lint.name_lower();
281-
match src {
282-
LintLevelSource::Default => {
283-
sess.diag_note_once(
284-
&mut err,
285-
DiagnosticMessageId::from(lint),
286-
&format!("`#[{}({})]` on by default", level.as_str(), name),
287-
);
288-
}
289-
LintLevelSource::CommandLine(lint_flag_val, orig_level) => {
290-
let flag = match orig_level {
291-
Level::Warn => "-W",
292-
Level::Deny => "-D",
293-
Level::Forbid => "-F",
294-
Level::Allow => "-A",
295-
Level::ForceWarn => "--force-warn",
296-
};
297-
let hyphen_case_lint_name = name.replace('_', "-");
298-
if lint_flag_val.as_str() == name {
299-
sess.diag_note_once(
300-
&mut err,
301-
DiagnosticMessageId::from(lint),
302-
&format!(
303-
"requested on the command line with `{} {}`",
304-
flag, hyphen_case_lint_name
305-
),
306-
);
307-
} else {
308-
let hyphen_case_flag_val = lint_flag_val.as_str().replace('_', "-");
309-
sess.diag_note_once(
310-
&mut err,
311-
DiagnosticMessageId::from(lint),
312-
&format!(
313-
"`{} {}` implied by `{} {}`",
314-
flag, hyphen_case_lint_name, flag, hyphen_case_flag_val
315-
),
316-
);
317-
}
318-
}
319-
LintLevelSource::Node(lint_attr_name, src, reason) => {
320-
if let Some(rationale) = reason {
321-
err.note(rationale.as_str());
322-
}
323-
sess.diag_span_note_once(
324-
&mut err,
325-
DiagnosticMessageId::from(lint),
326-
src,
327-
"the lint level is defined here",
328-
);
329-
if lint_attr_name.as_str() != name {
330-
let level_str = level.as_str();
331-
sess.diag_note_once(
332-
&mut err,
333-
DiagnosticMessageId::from(lint),
334-
&format!(
335-
"`#[{}({})]` implied by `#[{}({})]`",
336-
level_str, name, level_str, lint_attr_name
337-
),
338-
);
339-
}
340-
}
341-
}
351+
explain_lint_level_source(sess, lint, level, src, &mut err);
342352

353+
let name = lint.name_lower();
343354
let is_force_warn = matches!(level, Level::ForceWarn);
344355
err.code(DiagnosticId::Lint { name, has_future_breakage, is_force_warn });
345356

compiler/rustc_middle/src/mir/query.rs

+37-6
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use crate::mir::{Body, Promoted};
44
use crate::ty::{self, Ty, TyCtxt};
5-
use rustc_data_structures::sync::Lrc;
5+
use rustc_data_structures::stable_map::FxHashMap;
66
use rustc_data_structures::vec_map::VecMap;
77
use rustc_errors::ErrorReported;
88
use rustc_hir as hir;
@@ -114,13 +114,44 @@ pub struct UnsafetyViolation {
114114
pub details: UnsafetyViolationDetails,
115115
}
116116

117-
#[derive(Clone, TyEncodable, TyDecodable, HashStable, Debug)]
117+
#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
118+
pub enum UnusedUnsafe {
119+
/// `unsafe` block contains no unsafe operations
120+
/// > ``unnecessary `unsafe` block``
121+
Unused,
122+
/// `unsafe` block nested under another (used) `unsafe` block
123+
/// > ``… because it's nested under this `unsafe` block``
124+
InUnsafeBlock(hir::HirId),
125+
/// `unsafe` block nested under `unsafe fn`
126+
/// > ``… because it's nested under this `unsafe fn` ``
127+
///
128+
/// the second HirId here indicates the first usage of the `unsafe` block,
129+
/// which allows retrival of the LintLevelSource for why that operation would
130+
/// have been permitted without the block
131+
InUnsafeFn(hir::HirId, hir::HirId),
132+
}
133+
134+
#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
135+
pub enum UsedUnsafeBlockData {
136+
SomeDisallowedInUnsafeFn,
137+
// the HirId here indicates the first usage of the `unsafe` block
138+
// (i.e. the one that's first encountered in the MIR traversal of the unsafety check)
139+
AllAllowedInUnsafeFn(hir::HirId),
140+
}
141+
142+
#[derive(TyEncodable, TyDecodable, HashStable, Debug)]
118143
pub struct UnsafetyCheckResult {
119144
/// Violations that are propagated *upwards* from this function.
120-
pub violations: Lrc<[UnsafetyViolation]>,
121-
/// `unsafe` blocks in this function, along with whether they are used. This is
122-
/// used for the "unused_unsafe" lint.
123-
pub unsafe_blocks: Lrc<[(hir::HirId, bool)]>,
145+
pub violations: Vec<UnsafetyViolation>,
146+
147+
/// Used `unsafe` blocks in this function. This is used for the "unused_unsafe" lint.
148+
///
149+
/// The keys are the used `unsafe` blocks, the UnusedUnsafeKind indicates whether
150+
/// or not any of the usages happen at a place that doesn't allow `unsafe_op_in_unsafe_fn`.
151+
pub used_unsafe_blocks: FxHashMap<hir::HirId, UsedUnsafeBlockData>,
152+
153+
/// This is `Some` iff the item is not a closure.
154+
pub unused_unsafes: Option<Vec<(hir::HirId, UnusedUnsafe)>>,
124155
}
125156

126157
rustc_index::newtype_index! {

compiler/rustc_mir_build/src/build/block.rs

+5-17
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ use crate::build::ForGuard::OutsideGuard;
33
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
44
use rustc_middle::mir::*;
55
use rustc_middle::thir::*;
6-
use rustc_session::lint::builtin::UNSAFE_OP_IN_UNSAFE_FN;
7-
use rustc_session::lint::Level;
86
use rustc_span::Span;
97

108
impl<'a, 'tcx> Builder<'a, 'tcx> {
@@ -209,28 +207,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
209207
block.unit()
210208
}
211209

212-
/// If we are changing the safety mode, create a new source scope
210+
/// If we are entering an unsafe block, create a new source scope
213211
fn update_source_scope_for_safety_mode(&mut self, span: Span, safety_mode: BlockSafety) {
214212
debug!("update_source_scope_for({:?}, {:?})", span, safety_mode);
215213
let new_unsafety = match safety_mode {
216-
BlockSafety::Safe => None,
217-
BlockSafety::BuiltinUnsafe => Some(Safety::BuiltinUnsafe),
214+
BlockSafety::Safe => return,
215+
BlockSafety::BuiltinUnsafe => Safety::BuiltinUnsafe,
218216
BlockSafety::ExplicitUnsafe(hir_id) => {
219-
match self.in_scope_unsafe {
220-
Safety::Safe => {}
221-
// no longer treat `unsafe fn`s as `unsafe` contexts (see RFC #2585)
222-
Safety::FnUnsafe
223-
if self.tcx.lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, hir_id).0
224-
!= Level::Allow => {}
225-
_ => return,
226-
}
227217
self.in_scope_unsafe = Safety::ExplicitUnsafe(hir_id);
228-
Some(Safety::ExplicitUnsafe(hir_id))
218+
Safety::ExplicitUnsafe(hir_id)
229219
}
230220
};
231221

232-
if let Some(unsafety) = new_unsafety {
233-
self.source_scope = self.new_source_scope(span, LintLevel::Inherited, Some(unsafety));
234-
}
222+
self.source_scope = self.new_source_scope(span, LintLevel::Inherited, Some(new_unsafety));
235223
}
236224
}

0 commit comments

Comments
 (0)