Skip to content

Commit 8c48d03

Browse files
committed
Emit a lint for small functions without #[inline]
1 parent d4c86cf commit 8c48d03

File tree

3 files changed

+47
-5
lines changed

3 files changed

+47
-5
lines changed

compiler/rustc_mir_transform/messages.ftl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ mir_transform_requires_unsafe = {$details} is unsafe and requires unsafe {$op_in
4242
}
4343
.not_inherited = items do not inherit unsafety from separate enclosing items
4444
45+
mir_transform_small_fn_without_inline = this function looks small ({$statements}) but doesn't have #[inline], consider adding it
46+
.suggestion = add the inline attribute
47+
4548
mir_transform_target_feature_call_label = call to function with `#[target_feature]`
4649
mir_transform_target_feature_call_note = can only be called if the required target features are available
4750

compiler/rustc_mir_transform/src/cross_crate_inline.rs

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,36 @@ fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
6262
};
6363

6464
let mir = tcx.optimized_mir(def_id);
65-
let mut checker =
66-
CostChecker { tcx, callee_body: mir, calls: 0, statements: 0, landing_pads: 0, resumes: 0 };
65+
let mut checker = CostChecker {
66+
tcx,
67+
callee_body: mir,
68+
calls: 0,
69+
statements: 0,
70+
landing_pads: 0,
71+
resumes: 0,
72+
branches: 0,
73+
asserts: 0,
74+
};
6775
checker.visit_body(mir);
68-
checker.calls == 0
76+
let is_leaf = checker.calls == 0
6977
&& checker.resumes == 0
7078
&& checker.landing_pads == 0
71-
&& checker.statements <= threshold
79+
&& checker.statements <= threshold;
80+
81+
let is_trivial_wrapper = checker.calls == 1
82+
&& checker.resumes == 0
83+
&& checker.landing_pads == 0
84+
&& mir.basic_blocks.len() == 2;
85+
86+
if is_trivial_wrapper {
87+
let span = tcx.def_span(def_id);
88+
tcx.sess.emit_warning(crate::errors::SuggestAddingInline {
89+
place: span,
90+
suggest_inline: span.with_hi(span.lo()),
91+
statements: checker.statements,
92+
});
93+
}
94+
is_leaf
7295
}
7396

7497
struct CostChecker<'b, 'tcx> {
@@ -78,6 +101,8 @@ struct CostChecker<'b, 'tcx> {
78101
statements: usize,
79102
landing_pads: usize,
80103
resumes: usize,
104+
branches: usize,
105+
asserts: usize,
81106
}
82107

83108
impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
@@ -111,7 +136,7 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
111136
}
112137
}
113138
TerminatorKind::Assert { unwind, .. } => {
114-
self.calls += 1;
139+
self.asserts += 1;
115140
if let UnwindAction::Cleanup(_) = unwind {
116141
self.landing_pads += 1;
117142
}
@@ -123,6 +148,10 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
123148
self.landing_pads += 1;
124149
}
125150
}
151+
TerminatorKind::SwitchInt { .. } => {
152+
self.statements += 1;
153+
self.branches += 1;
154+
}
126155
TerminatorKind::Return => {}
127156
_ => self.statements += 1,
128157
}

compiler/rustc_mir_transform/src/errors.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,3 +278,13 @@ pub(crate) struct MustNotSuspendReason {
278278
pub span: Span,
279279
pub reason: String,
280280
}
281+
282+
#[derive(Diagnostic)]
283+
#[diag(mir_transform_small_fn_without_inline)]
284+
pub struct SuggestAddingInline {
285+
#[primary_span]
286+
pub place: Span,
287+
#[suggestion(code = "#[inline]\n", applicability = "machine-applicable")]
288+
pub suggest_inline: Span,
289+
pub statements: usize,
290+
}

0 commit comments

Comments
 (0)