Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Only fetch HIR for naked functions that have the attribute. #98489

Merged
merged 2 commits into from
Aug 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 41 additions & 53 deletions compiler/rustc_passes/src/naked_functions.rs
Original file line number Diff line number Diff line change
@@ -1,83 +1,71 @@
//! Checks validity of naked functions.

use rustc_ast::{Attribute, InlineAsmOptions};
use rustc_ast::InlineAsmOptions;
use rustc_errors::{struct_span_err, Applicability};
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{FnKind, Visitor};
use rustc_hir::{ExprKind, HirId, InlineAsmOperand, StmtKind};
use rustc_hir::intravisit::Visitor;
use rustc_hir::{ExprKind, InlineAsmOperand, StmtKind};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::lint::builtin::UNDEFINED_NAKED_FUNCTION_ABI;
use rustc_span::symbol::sym;
use rustc_span::Span;
use rustc_target::spec::abi::Abi;

fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckNakedFunctions { tcx });
}

pub(crate) fn provide(providers: &mut Providers) {
*providers = Providers { check_mod_naked_functions, ..*providers };
}

struct CheckNakedFunctions<'tcx> {
tcx: TyCtxt<'tcx>,
}

impl<'tcx> Visitor<'tcx> for CheckNakedFunctions<'tcx> {
fn visit_fn(
&mut self,
fk: FnKind<'_>,
_fd: &'tcx hir::FnDecl<'tcx>,
body_id: hir::BodyId,
span: Span,
hir_id: HirId,
) {
let ident_span;
let fn_header;

match fk {
FnKind::Closure => {
// Closures with a naked attribute are rejected during attribute
// check. Don't validate them any further.
return;
}
FnKind::ItemFn(ident, _, ref header, ..) => {
ident_span = ident.span;
fn_header = header;
}

FnKind::Method(ident, ref sig, ..) => {
ident_span = ident.span;
fn_header = &sig.header;
}
fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
let items = tcx.hir_module_items(module_def_id);
for def_id in items.definitions() {
if !matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) {
continue;
}

let attrs = self.tcx.hir().attrs(hir_id);
let naked = attrs.iter().any(|attr| attr.has_name(sym::naked));
if naked {
let body = self.tcx.hir().body(body_id);
check_abi(self.tcx, hir_id, fn_header.abi, ident_span);
check_no_patterns(self.tcx, body.params);
check_no_parameters_use(self.tcx, body);
check_asm(self.tcx, body, span);
check_inline(self.tcx, attrs);
let naked = tcx.has_attr(def_id.to_def_id(), sym::naked);
if !naked {
continue;
}

let (fn_header, body_id) = match tcx.hir().get_by_def_id(def_id) {
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. })
| hir::Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)),
..
})
| hir::Node::ImplItem(hir::ImplItem {
kind: hir::ImplItemKind::Fn(sig, body_id),
..
}) => (sig.header, *body_id),
_ => continue,
};

let body = tcx.hir().body(body_id);
check_abi(tcx, def_id, fn_header.abi);
check_no_patterns(tcx, body.params);
check_no_parameters_use(tcx, body);
check_asm(tcx, def_id, body);
check_inline(tcx, def_id);
}
}

/// Check that the function isn't inlined.
fn check_inline(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
for attr in attrs.iter().filter(|attr| attr.has_name(sym::inline)) {
fn check_inline(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let attrs = tcx.get_attrs(def_id.to_def_id(), sym::inline);
for attr in attrs {
tcx.sess.struct_span_err(attr.span, "naked functions cannot be inlined").emit();
}
}

/// Checks that function uses non-Rust ABI.
fn check_abi(tcx: TyCtxt<'_>, hir_id: HirId, abi: Abi, fn_ident_span: Span) {
fn check_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, abi: Abi) {
if abi == Abi::Rust {
tcx.struct_span_lint_hir(UNDEFINED_NAKED_FUNCTION_ABI, hir_id, fn_ident_span, |lint| {
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let span = tcx.def_span(def_id);
tcx.struct_span_lint_hir(UNDEFINED_NAKED_FUNCTION_ABI, hir_id, span, |lint| {
lint.build("Rust ABI is unsupported in naked functions").emit();
});
}
Expand Down Expand Up @@ -141,15 +129,15 @@ impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> {
}

/// Checks that function body contains a single inline assembly block.
fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, body: &'tcx hir::Body<'tcx>, fn_span: Span) {
fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body<'tcx>) {
let mut this = CheckInlineAssembly { tcx, items: Vec::new() };
this.visit_body(body);
if let [(ItemKind::Asm | ItemKind::Err, _)] = this.items[..] {
// Ok.
} else {
let mut diag = struct_span_err!(
tcx.sess,
fn_span,
tcx.def_span(def_id),
E0787,
"naked functions must contain a single asm block"
);
Expand Down
103 changes: 45 additions & 58 deletions src/test/ui/asm/naked-functions.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,11 @@ LL | a + 1
error[E0787]: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:33:1
|
LL | / pub unsafe extern "C" fn inc(a: u32) -> u32 {
LL | |
LL | | a + 1
| | ----- non-asm is unsupported in naked functions
LL | |
LL | | }
| |_^
LL | pub unsafe extern "C" fn inc(a: u32) -> u32 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL |
LL | a + 1
| ----- non-asm is unsupported in naked functions

error: referencing function parameters is not allowed in naked functions
--> $DIR/naked-functions.rs:42:31
Expand All @@ -82,12 +80,11 @@ LL | asm!("/* {0} */", in(reg) a, options(noreturn));
error[E0787]: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:48:1
|
LL | / pub unsafe extern "C" fn inc_closure(a: u32) -> u32 {
LL | |
LL | | (|| a + 1)()
| | ------------ non-asm is unsupported in naked functions
LL | | }
| |_^
LL | pub unsafe extern "C" fn inc_closure(a: u32) -> u32 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL |
LL | (|| a + 1)()
| ------------ non-asm is unsupported in naked functions

error[E0787]: only `const` and `sym` operands are supported in naked functions
--> $DIR/naked-functions.rs:65:10
Expand Down Expand Up @@ -124,30 +121,25 @@ LL | sym G, options(noreturn),
error[E0787]: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:54:1
|
LL | / pub unsafe extern "C" fn unsupported_operands() {
LL | |
LL | | let mut a = 0usize;
| | ------------------- non-asm is unsupported in naked functions
LL | | let mut b = 0usize;
| | ------------------- non-asm is unsupported in naked functions
LL | | let mut c = 0usize;
| | ------------------- non-asm is unsupported in naked functions
LL | | let mut d = 0usize;
| | ------------------- non-asm is unsupported in naked functions
LL | | let mut e = 0usize;
| | ------------------- non-asm is unsupported in naked functions
... |
LL | | );
LL | | }
| |_^
LL | pub unsafe extern "C" fn unsupported_operands() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL |
LL | let mut a = 0usize;
| ------------------- non-asm is unsupported in naked functions
LL | let mut b = 0usize;
| ------------------- non-asm is unsupported in naked functions
LL | let mut c = 0usize;
| ------------------- non-asm is unsupported in naked functions
LL | let mut d = 0usize;
| ------------------- non-asm is unsupported in naked functions
LL | let mut e = 0usize;
| ------------------- non-asm is unsupported in naked functions

error[E0787]: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:77:1
|
LL | / pub extern "C" fn missing_assembly() {
LL | |
LL | | }
| |_^
LL | pub extern "C" fn missing_assembly() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0787]: asm in naked functions must use `noreturn` option
--> $DIR/naked-functions.rs:84:5
Expand Down Expand Up @@ -185,20 +177,17 @@ LL | asm!("", options(noreturn));
error[E0787]: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:82:1
|
LL | / pub extern "C" fn too_many_asm_blocks() {
LL | |
LL | | asm!("");
LL | |
LL | | asm!("");
| | -------- multiple asm blocks are unsupported in naked functions
LL | |
LL | | asm!("");
| | -------- multiple asm blocks are unsupported in naked functions
LL | |
LL | | asm!("", options(noreturn));
| | --------------------------- multiple asm blocks are unsupported in naked functions
LL | | }
| |_^
LL | pub extern "C" fn too_many_asm_blocks() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
LL | asm!("");
| -------- multiple asm blocks are unsupported in naked functions
LL |
LL | asm!("");
| -------- multiple asm blocks are unsupported in naked functions
LL |
LL | asm!("", options(noreturn));
| --------------------------- multiple asm blocks are unsupported in naked functions

error: referencing function parameters is not allowed in naked functions
--> $DIR/naked-functions.rs:97:11
Expand All @@ -211,13 +200,11 @@ LL | *&y
error[E0787]: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:95:5
|
LL | / pub extern "C" fn inner(y: usize) -> usize {
LL | |
LL | | *&y
| | --- non-asm is unsupported in naked functions
LL | |
LL | | }
| |_____^
LL | pub extern "C" fn inner(y: usize) -> usize {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL |
LL | *&y
| --- non-asm is unsupported in naked functions

error[E0787]: asm options unsupported in naked functions: `nomem`, `preserves_flags`
--> $DIR/naked-functions.rs:105:5
Expand Down Expand Up @@ -249,18 +236,18 @@ LL | asm!("", options(noreturn, may_unwind));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

warning: Rust ABI is unsupported in naked functions
--> $DIR/naked-functions.rs:124:15
--> $DIR/naked-functions.rs:124:1
|
LL | pub unsafe fn default_abi() {
| ^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(undefined_naked_function_abi)]` on by default

warning: Rust ABI is unsupported in naked functions
--> $DIR/naked-functions.rs:130:15
--> $DIR/naked-functions.rs:130:1
|
LL | pub unsafe fn rust_abi() {
| ^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^^^^^

error: naked functions cannot be inlined
--> $DIR/naked-functions.rs:170:1
Expand Down