Skip to content

Commit 19a90c7

Browse files
authored
Rollup merge of #95553 - jam1garner:naked-function-compile-error, r=tmiasko
Don't emit non-asm contents error for naked function composed of errors ## Motivation For naked functions an error is emitted when they are composed of anything other than a single asm!() block. However, this error triggers in a couple situations in which it adds no additional information or is actively misleading. One example is if you do have an asm!() block but simply one with a syntax error: ```rust #[naked] unsafe extern "C" fn compiler_errors() { asm!(invalid_syntax) } ``` This results in two errors, one for the syntax error itself and another telling you that you need an asm block in your function: ```rust error[E0787]: naked functions must contain a single asm block --> src/main.rs:6:1 | 6 | / unsafe extern "C" fn naked_compile_error() { 7 | | asm!(blah) 8 | | } | |_^ ``` This issue also comes up when [utilizing `compile_error!()` for improving your diagnostics](https://twitter.com/steveklabnik/status/1509538243020218372), such as raising a compiler error when compiling for an unsupported target. ## Implementation The rules this PR implements are as follows: 1. If any non-erroneous non-asm statement is included, an error will still occur 2. If multiple asm statements are included, an error will still occur 3. If 0 or 1 asm statements are present, as well as any non-zero number of erroneous statements, then this error will *not* be raised as it is likely either redundant or incorrect The rule of thumb is effectively "if an error is present and its correction could change things, don't raise an error".
2 parents 796bc7e + bf26d87 commit 19a90c7

File tree

3 files changed

+60
-4
lines changed

3 files changed

+60
-4
lines changed

compiler/rustc_passes/src/naked_functions.rs

+22-3
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> {
147147
fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, body: &'tcx hir::Body<'tcx>, fn_span: Span) {
148148
let mut this = CheckInlineAssembly { tcx, items: Vec::new() };
149149
this.visit_body(body);
150-
if let [(ItemKind::Asm, _)] = this.items[..] {
150+
if let [(ItemKind::Asm | ItemKind::Err, _)] = this.items[..] {
151151
// Ok.
152152
} else {
153153
let mut diag = struct_span_err!(
@@ -156,19 +156,33 @@ fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, body: &'tcx hir::Body<'tcx>, fn_span: Span
156156
E0787,
157157
"naked functions must contain a single asm block"
158158
);
159+
160+
let mut must_show_error = false;
159161
let mut has_asm = false;
162+
let mut has_err = false;
160163
for &(kind, span) in &this.items {
161164
match kind {
162165
ItemKind::Asm if has_asm => {
166+
must_show_error = true;
163167
diag.span_label(span, "multiple asm blocks are unsupported in naked functions");
164168
}
165169
ItemKind::Asm => has_asm = true,
166170
ItemKind::NonAsm => {
171+
must_show_error = true;
167172
diag.span_label(span, "non-asm is unsupported in naked functions");
168173
}
174+
ItemKind::Err => has_err = true,
169175
}
170176
}
171-
diag.emit();
177+
178+
// If the naked function only contains a single asm block and a non-zero number of
179+
// errors, then don't show an additional error. This allows for appending/prepending
180+
// `compile_error!("...")` statements and reduces error noise.
181+
if must_show_error || !has_err {
182+
diag.emit();
183+
} else {
184+
diag.cancel();
185+
}
172186
}
173187
}
174188

@@ -181,6 +195,7 @@ struct CheckInlineAssembly<'tcx> {
181195
enum ItemKind {
182196
Asm,
183197
NonAsm,
198+
Err,
184199
}
185200

186201
impl<'tcx> CheckInlineAssembly<'tcx> {
@@ -222,9 +237,13 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
222237
self.check_inline_asm(asm, span);
223238
}
224239

225-
ExprKind::DropTemps(..) | ExprKind::Block(..) | ExprKind::Err => {
240+
ExprKind::DropTemps(..) | ExprKind::Block(..) => {
226241
hir::intravisit::walk_expr(self, expr);
227242
}
243+
244+
ExprKind::Err => {
245+
self.items.push((ItemKind::Err, span));
246+
}
228247
}
229248
}
230249

src/test/ui/asm/naked-functions.rs

+19
Original file line numberDiff line numberDiff line change
@@ -196,3 +196,22 @@ pub unsafe extern "C" fn inline_never() {
196196
pub unsafe extern "C" fn inline_all() {
197197
asm!("", options(noreturn));
198198
}
199+
200+
#[naked]
201+
pub unsafe extern "C" fn allow_compile_error(a: u32) -> u32 {
202+
compile_error!("this is a user specified error")
203+
//~^ ERROR this is a user specified error
204+
}
205+
206+
#[naked]
207+
pub unsafe extern "C" fn allow_compile_error_and_asm(a: u32) -> u32 {
208+
compile_error!("this is a user specified error");
209+
//~^ ERROR this is a user specified error
210+
asm!("", options(noreturn))
211+
}
212+
213+
#[naked]
214+
pub unsafe extern "C" fn invalid_asm_syntax(a: u32) -> u32 {
215+
asm!(invalid_syntax)
216+
//~^ ERROR asm template must be a string literal
217+
}

src/test/ui/asm/naked-functions.stderr

+19-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,24 @@ error: asm with the `pure` option must have at least one output
44
LL | asm!("", options(readonly, nostack), options(pure));
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^
66

7+
error: this is a user specified error
8+
--> $DIR/naked-functions.rs:202:5
9+
|
10+
LL | compile_error!("this is a user specified error")
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
13+
error: this is a user specified error
14+
--> $DIR/naked-functions.rs:208:5
15+
|
16+
LL | compile_error!("this is a user specified error");
17+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
18+
19+
error: asm template must be a string literal
20+
--> $DIR/naked-functions.rs:215:10
21+
|
22+
LL | asm!(invalid_syntax)
23+
| ^^^^^^^^^^^^^^
24+
725
error: patterns not allowed in naked function parameters
826
--> $DIR/naked-functions.rs:20:5
927
|
@@ -280,6 +298,6 @@ error: naked functions cannot be inlined
280298
LL | #[inline(never)]
281299
| ^^^^^^^^^^^^^^^^
282300

283-
error: aborting due to 30 previous errors; 2 warnings emitted
301+
error: aborting due to 33 previous errors; 2 warnings emitted
284302

285303
For more information about this error, try `rustc --explain E0787`.

0 commit comments

Comments
 (0)