Auto merge of #79653 - tmiasko:naked-functions, r=Amanieu

Validate naked functions definitions

Validate that naked functions are defined in terms of a single inline assembly
block that uses only `const` and `sym` operands and has `noreturn` option.

Implemented as future incompatibility lint with intention to migrate it into
hard error. When it becomes a hard error it will ensure that naked functions are
either unsafe or contain an unsafe block around the inline assembly. It will
guarantee that naked functions do not reference functions parameters (obsoleting
part of existing checks from #79411). It will limit the definitions of naked
functions to what can be reliably supported. It will also reject naked functions
implemented using legacy LLVM style assembly since it cannot satisfy those
conditions.

https://github.com/rust-lang/rfcs/pull/2774
https://github.com/rust-lang/rfcs/pull/2972
This commit is contained in:
bors 2020-12-07 22:47:20 +00:00
commit bda05cc471
23 changed files with 775 additions and 141 deletions

View File

@ -1307,7 +1307,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
hir::InlineAsmOperand::Sym { expr: self.lower_expr_mut(expr) }
}
};
Some(op)
Some((op, *op_sp))
})
.collect();
@ -1326,7 +1326,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
} = *p
{
let op_sp = asm.operands[operand_idx].1;
match &operands[operand_idx] {
match &operands[operand_idx].0 {
hir::InlineAsmOperand::In { reg, .. }
| hir::InlineAsmOperand::Out { reg, .. }
| hir::InlineAsmOperand::InOut { reg, .. }
@ -1385,8 +1385,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let mut used_input_regs = FxHashMap::default();
let mut used_output_regs = FxHashMap::default();
let mut required_features: Vec<&str> = vec![];
for (idx, op) in operands.iter().enumerate() {
let op_sp = asm.operands[idx].1;
for (idx, &(ref op, op_sp)) in operands.iter().enumerate() {
if let Some(reg) = op.reg() {
// Make sure we don't accidentally carry features from the
// previous iteration.
@ -1458,8 +1457,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
skip = true;
let idx2 = *o.get();
let op2 = &operands[idx2];
let op_sp2 = asm.operands[idx2].1;
let &(ref op2, op_sp2) = &operands[idx2];
let reg2 = match op2.reg() {
Some(asm::InlineAsmRegOrRegClass::Reg(r)) => r,
_ => unreachable!(),

View File

@ -14,7 +14,7 @@ macro_rules! arena_types {
// HIR types
[few] hir_krate: rustc_hir::Crate<$tcx>,
[] arm: rustc_hir::Arm<$tcx>,
[] asm_operand: rustc_hir::InlineAsmOperand<$tcx>,
[] asm_operand: (rustc_hir::InlineAsmOperand<$tcx>, Span),
[] asm_template: rustc_ast::InlineAsmTemplatePiece,
[] attribute: rustc_ast::Attribute,
[] block: rustc_hir::Block<$tcx>,

View File

@ -2143,7 +2143,7 @@ impl<'hir> InlineAsmOperand<'hir> {
#[derive(Debug, HashStable_Generic)]
pub struct InlineAsm<'hir> {
pub template: &'hir [InlineAsmTemplatePiece],
pub operands: &'hir [InlineAsmOperand<'hir>],
pub operands: &'hir [(InlineAsmOperand<'hir>, Span)],
pub options: InlineAsmOptions,
pub line_spans: &'hir [Span],
}

View File

@ -1191,7 +1191,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
walk_list!(visitor, visit_expr, optional_expression);
}
ExprKind::InlineAsm(ref asm) => {
for op in asm.operands {
for (op, _op_sp) in asm.operands {
match op {
InlineAsmOperand::In { expr, .. }
| InlineAsmOperand::InOut { expr, .. }

View File

@ -1462,7 +1462,7 @@ impl<'a> State<'a> {
let mut args = vec![];
args.push(AsmArg::Template(ast::InlineAsmTemplatePiece::to_string(&a.template)));
args.extend(a.operands.iter().map(|o| AsmArg::Operand(o)));
args.extend(a.operands.iter().map(|(o, _)| AsmArg::Operand(o)));
if !a.options.is_empty() {
args.push(AsmArg::Options(a.options));
}

View File

@ -2742,6 +2742,50 @@ declare_lint! {
"detects deprecation attributes with no effect",
}
declare_lint! {
/// The `unsupported_naked_functions` lint detects naked function
/// definitions that are unsupported but were previously accepted.
///
/// ### Example
///
/// ```rust
/// #![feature(naked_functions)]
///
/// #[naked]
/// pub fn f() -> u32 {
/// 42
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// The naked functions must be defined using a single inline assembly
/// block.
///
/// The execution must never fall through past the end of the assembly
/// code so the block must use `noreturn` option. The asm block can also
/// use `att_syntax` option, but other options are not allowed.
///
/// The asm block must not contain any operands other than `const` and
/// `sym`. Additionally, naked function should specify a non-Rust ABI.
///
/// While other definitions of naked functions were previously accepted,
/// they are unsupported and might not work reliably. This is a
/// [future-incompatible] lint that will transition into hard error in
/// the future.
///
/// [future-incompatible]: ../index.md#future-incompatible-lints
pub UNSUPPORTED_NAKED_FUNCTIONS,
Warn,
"unsupported naked function definitions",
@future_incompatible = FutureIncompatibleInfo {
reference: "issue #32408 <https://github.com/rust-lang/rust/issues/32408>",
edition: None,
};
}
declare_tool_lint! {
pub rustc::INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
Deny,
@ -2832,6 +2876,7 @@ declare_lint_pass! {
UNINHABITED_STATIC,
FUNCTION_ITEM_REFERENCES,
USELESS_DEPRECATED,
UNSUPPORTED_NAKED_FUNCTIONS,
]
}

View File

@ -408,7 +408,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
operands: asm
.operands
.iter()
.map(|op| {
.map(|(op, _op_sp)| {
match *op {
hir::InlineAsmOperand::In { reg, ref expr } => {
InlineAsmOperand::In { reg, expr: expr.to_ref() }

View File

@ -347,7 +347,7 @@ impl ExprVisitor<'tcx> {
}
fn check_asm(&self, asm: &hir::InlineAsm<'tcx>) {
for (idx, op) in asm.operands.iter().enumerate() {
for (idx, (op, _op_sp)) in asm.operands.iter().enumerate() {
match *op {
hir::InlineAsmOperand::In { reg, ref expr } => {
self.check_asm_operand_type(idx, reg, expr, asm.template, None);

View File

@ -1174,7 +1174,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
};
// Do a first pass for writing outputs only
for op in asm.operands.iter().rev() {
for (op, _op_sp) in asm.operands.iter().rev() {
match op {
hir::InlineAsmOperand::In { .. }
| hir::InlineAsmOperand::Const { .. }
@ -1197,7 +1197,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
// Then do a second pass for inputs
let mut succ = succ;
for op in asm.operands.iter().rev() {
for (op, _op_sp) in asm.operands.iter().rev() {
match op {
hir::InlineAsmOperand::In { expr, .. }
| hir::InlineAsmOperand::Const { expr, .. }
@ -1454,7 +1454,7 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) {
}
hir::ExprKind::InlineAsm(ref asm) => {
for op in asm.operands {
for (op, _op_sp) in asm.operands {
match op {
hir::InlineAsmOperand::Out { expr, .. } => {
if let Some(expr) = expr {

View File

@ -1,10 +1,16 @@
//! Checks validity of naked functions.
use rustc_ast::InlineAsmOptions;
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{ErasedMap, FnKind, NestedVisitorMap, Visitor};
use rustc_hir::{ExprKind, HirId, InlineAsmOperand, StmtKind};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::lint::builtin::UNSUPPORTED_NAKED_FUNCTIONS;
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(
@ -33,27 +39,52 @@ impl<'tcx> Visitor<'tcx> for CheckNakedFunctions<'tcx> {
fk: FnKind<'v>,
_fd: &'tcx hir::FnDecl<'tcx>,
body_id: hir::BodyId,
_span: Span,
_hir_id: hir::HirId,
span: Span,
hir_id: HirId,
) {
let ident_span;
let fn_header;
match fk {
// Rejected during attribute check. Do not validate further.
FnKind::Closure(..) => return,
FnKind::ItemFn(..) | FnKind::Method(..) => {}
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;
}
}
let naked = fk.attrs().iter().any(|attr| attr.has_name(sym::naked));
if naked {
let body = self.tcx.hir().body(body_id);
check_params(self.tcx, body);
check_body(self.tcx, body);
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, hir_id, body, span);
}
}
}
/// Checks that function uses non-Rust ABI.
fn check_abi(tcx: TyCtxt<'_>, hir_id: HirId, abi: Abi, fn_ident_span: Span) {
if abi == Abi::Rust {
tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, fn_ident_span, |lint| {
lint.build("Rust ABI is unsupported in naked functions").emit();
});
}
}
/// Checks that parameters don't use patterns. Mirrors the checks for function declarations.
fn check_params(tcx: TyCtxt<'_>, body: &hir::Body<'_>) {
for param in body.params {
fn check_no_patterns(tcx: TyCtxt<'_>, params: &[hir::Param<'_>]) {
for param in params {
match param.pat.kind {
hir::PatKind::Wild
| hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, _, None) => {}
@ -69,23 +100,23 @@ fn check_params(tcx: TyCtxt<'_>, body: &hir::Body<'_>) {
}
}
/// Checks that function parameters aren't referenced in the function body.
fn check_body<'tcx>(tcx: TyCtxt<'tcx>, body: &'tcx hir::Body<'tcx>) {
/// Checks that function parameters aren't used in the function body.
fn check_no_parameters_use<'tcx>(tcx: TyCtxt<'tcx>, body: &'tcx hir::Body<'tcx>) {
let mut params = hir::HirIdSet::default();
for param in body.params {
param.pat.each_binding(|_binding_mode, hir_id, _span, _ident| {
params.insert(hir_id);
});
}
CheckBody { tcx, params }.visit_body(body);
CheckParameters { tcx, params }.visit_body(body);
}
struct CheckBody<'tcx> {
struct CheckParameters<'tcx> {
tcx: TyCtxt<'tcx>,
params: hir::HirIdSet,
}
impl<'tcx> Visitor<'tcx> for CheckBody<'tcx> {
impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> {
type Map = ErasedMap<'tcx>;
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
@ -103,11 +134,189 @@ impl<'tcx> Visitor<'tcx> for CheckBody<'tcx> {
.sess
.struct_span_err(
expr.span,
"use of parameters not allowed inside naked functions",
"referencing function parameters is not allowed in naked functions",
)
.help("follow the calling convention in asm block to use parameters")
.emit();
return;
}
}
hir::intravisit::walk_expr(self, expr);
}
}
/// Checks that function body contains a single inline assembly block.
fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, hir_id: HirId, body: &'tcx hir::Body<'tcx>, fn_span: Span) {
let mut this = CheckInlineAssembly { tcx, items: Vec::new() };
this.visit_body(body);
if let &[(ItemKind::Asm, _)] = &this.items[..] {
// Ok.
} else {
tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, fn_span, |lint| {
let mut diag = lint.build("naked functions must contain a single asm block");
let mut has_asm = false;
for &(kind, span) in &this.items {
match kind {
ItemKind::Asm if has_asm => {
diag.span_label(
span,
"multiple asm blocks are unsupported in naked functions",
);
}
ItemKind::Asm => has_asm = true,
ItemKind::NonAsm => {
diag.span_label(span, "non-asm is unsupported in naked functions");
}
}
}
diag.emit();
});
}
}
struct CheckInlineAssembly<'tcx> {
tcx: TyCtxt<'tcx>,
items: Vec<(ItemKind, Span)>,
}
#[derive(Copy, Clone)]
enum ItemKind {
Asm,
NonAsm,
}
impl<'tcx> CheckInlineAssembly<'tcx> {
fn check_expr(&mut self, expr: &'tcx hir::Expr<'tcx>, span: Span) {
match expr.kind {
ExprKind::Box(..)
| ExprKind::ConstBlock(..)
| ExprKind::Array(..)
| ExprKind::Call(..)
| ExprKind::MethodCall(..)
| ExprKind::Tup(..)
| ExprKind::Binary(..)
| ExprKind::Unary(..)
| ExprKind::Lit(..)
| ExprKind::Cast(..)
| ExprKind::Type(..)
| ExprKind::Loop(..)
| ExprKind::Match(..)
| ExprKind::Closure(..)
| ExprKind::Assign(..)
| ExprKind::AssignOp(..)
| ExprKind::Field(..)
| ExprKind::Index(..)
| ExprKind::Path(..)
| ExprKind::AddrOf(..)
| ExprKind::Break(..)
| ExprKind::Continue(..)
| ExprKind::Ret(..)
| ExprKind::Struct(..)
| ExprKind::Repeat(..)
| ExprKind::Yield(..) => {
self.items.push((ItemKind::NonAsm, span));
}
ExprKind::InlineAsm(ref asm) => {
self.items.push((ItemKind::Asm, span));
self.check_inline_asm(expr.hir_id, asm, span);
}
ExprKind::LlvmInlineAsm(..) => {
self.items.push((ItemKind::Asm, span));
self.tcx.struct_span_lint_hir(
UNSUPPORTED_NAKED_FUNCTIONS,
expr.hir_id,
span,
|lint| {
lint.build(
"the LLVM-style inline assembly is unsupported in naked functions",
)
.help("use the new asm! syntax specified in RFC 2873")
.emit();
},
);
}
ExprKind::DropTemps(..) | ExprKind::Block(..) | ExprKind::Err => {
hir::intravisit::walk_expr(self, expr);
}
}
}
fn check_inline_asm(&self, hir_id: HirId, asm: &'tcx hir::InlineAsm<'tcx>, span: Span) {
let unsupported_operands: Vec<Span> = asm
.operands
.iter()
.filter_map(|&(ref op, op_sp)| match op {
InlineAsmOperand::Const { .. } | InlineAsmOperand::Sym { .. } => None,
InlineAsmOperand::In { .. }
| InlineAsmOperand::Out { .. }
| InlineAsmOperand::InOut { .. }
| InlineAsmOperand::SplitInOut { .. } => Some(op_sp),
})
.collect();
if !unsupported_operands.is_empty() {
self.tcx.struct_span_lint_hir(
UNSUPPORTED_NAKED_FUNCTIONS,
hir_id,
unsupported_operands,
|lint| {
lint.build("only `const` and `sym` operands are supported in naked functions")
.emit();
},
);
}
let unsupported_options: Vec<&'static str> = [
(InlineAsmOptions::NOMEM, "`nomem`"),
(InlineAsmOptions::NOSTACK, "`nostack`"),
(InlineAsmOptions::PRESERVES_FLAGS, "`preserves_flags`"),
(InlineAsmOptions::PURE, "`pure`"),
(InlineAsmOptions::READONLY, "`readonly`"),
]
.iter()
.filter_map(|&(option, name)| if asm.options.contains(option) { Some(name) } else { None })
.collect();
if !unsupported_options.is_empty() {
self.tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, span, |lint| {
lint.build(&format!(
"asm options unsupported in naked functions: {}",
unsupported_options.join(", ")
))
.emit();
});
}
if !asm.options.contains(InlineAsmOptions::NORETURN) {
self.tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, span, |lint| {
lint.build("asm in naked functions must use `noreturn` option").emit();
});
}
}
}
impl<'tcx> Visitor<'tcx> for CheckInlineAssembly<'tcx> {
type Map = ErasedMap<'tcx>;
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
NestedVisitorMap::None
}
fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) {
match stmt.kind {
StmtKind::Item(..) => {}
StmtKind::Local(..) => {
self.items.push((ItemKind::NonAsm, stmt.span));
}
StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => {
self.check_expr(expr, stmt.span);
}
}
}
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
self.check_expr(&expr, expr.span);
}
}

View File

@ -1929,7 +1929,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
fn check_expr_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>) -> Ty<'tcx> {
for op in asm.operands {
for (op, _op_sp) in asm.operands {
match op {
hir::InlineAsmOperand::In { expr, .. } | hir::InlineAsmOperand::Const { expr } => {
self.check_expr_asm_operand(expr, true);

View File

@ -243,7 +243,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
}
hir::ExprKind::InlineAsm(ref asm) => {
for op in asm.operands {
for (op, _op_sp) in asm.operands {
match op {
hir::InlineAsmOperand::In { expr, .. }
| hir::InlineAsmOperand::Const { expr, .. }

View File

@ -0,0 +1,169 @@
// only-x86_64
#![feature(asm)]
#![feature(llvm_asm)]
#![feature(naked_functions)]
#![feature(or_patterns)]
#![crate_type = "lib"]
#[repr(C)]
pub struct P { x: u8, y: u16 }
#[naked]
pub unsafe extern "C" fn patterns(
mut a: u32,
//~^ ERROR patterns not allowed in naked function parameters
&b: &i32,
//~^ ERROR patterns not allowed in naked function parameters
(None | Some(_)): Option<std::ptr::NonNull<u8>>,
//~^ ERROR patterns not allowed in naked function parameters
P { x, y }: P,
//~^ ERROR patterns not allowed in naked function parameters
) {
asm!("", options(noreturn))
}
#[naked]
pub unsafe extern "C" fn inc(a: u32) -> u32 {
//~^ WARN naked functions must contain a single asm block
//~| WARN this was previously accepted
a + 1
//~^ ERROR referencing function parameters is not allowed in naked functions
}
#[naked]
pub unsafe extern "C" fn inc_asm(a: u32) -> u32 {
asm!("/* {0} */", in(reg) a, options(noreturn));
//~^ ERROR referencing function parameters is not allowed in naked functions
//~| WARN only `const` and `sym` operands are supported in naked functions
//~| WARN this was previously accepted
}
#[naked]
pub unsafe extern "C" fn inc_closure(a: u32) -> u32 {
//~^ WARN naked functions must contain a single asm block
//~| WARN this was previously accepted
(|| a + 1)()
}
#[naked]
pub unsafe extern "C" fn unsupported_operands() {
//~^ WARN naked functions must contain a single asm block
//~| WARN this was previously accepted
let mut a = 0usize;
let mut b = 0usize;
let mut c = 0usize;
let mut d = 0usize;
let mut e = 0usize;
const F: usize = 0usize;
static G: usize = 0usize;
asm!("/* {0} {1} {2} {3} {4} {5} {6} */",
//~^ WARN asm in naked functions must use `noreturn` option
//~| WARN this was previously accepted
in(reg) a,
//~^ WARN only `const` and `sym` operands are supported in naked functions
//~| WARN this was previously accepted
inlateout(reg) b,
inout(reg) c,
lateout(reg) d,
out(reg) e,
const F,
sym G,
);
}
#[naked]
pub extern "C" fn missing_assembly() {
//~^ WARN naked functions must contain a single asm block
//~| WARN this was previously accepted
}
#[naked]
pub extern "C" fn too_many_asm_blocks() {
//~^ WARN naked functions must contain a single asm block
//~| WARN this was previously accepted
asm!("");
//~^ WARN asm in naked functions must use `noreturn` option
//~| WARN this was previously accepted
asm!("");
//~^ WARN asm in naked functions must use `noreturn` option
//~| WARN this was previously accepted
asm!("");
//~^ WARN asm in naked functions must use `noreturn` option
//~| WARN this was previously accepted
asm!("", options(noreturn));
}
pub fn outer(x: u32) -> extern "C" fn(usize) -> usize {
#[naked]
pub extern "C" fn inner(y: usize) -> usize {
//~^ WARN naked functions must contain a single asm block
//~| WARN this was previously accepted
*&y
//~^ ERROR referencing function parameters is not allowed in naked functions
}
inner
}
#[naked]
unsafe extern "C" fn llvm() -> ! {
//~^ WARN naked functions must contain a single asm block
//~| WARN this was previously accepted
llvm_asm!("");
//~^ WARN LLVM-style inline assembly is unsupported in naked functions
//~| WARN this was previously accepted
core::hint::unreachable_unchecked();
}
#[naked]
unsafe extern "C" fn invalid_options() {
asm!("", options(nomem, preserves_flags, noreturn));
//~^ WARN asm options unsupported in naked functions: `nomem`, `preserves_flags`
//~| WARN this was previously accepted
}
#[naked]
unsafe extern "C" fn invalid_options_continued() {
asm!("", options(readonly, nostack), options(pure));
//~^ ERROR asm with `pure` option must have at least one output
//~| WARN asm options unsupported in naked functions: `nostack`, `pure`, `readonly`
//~| WARN this was previously accepted
//~| WARN asm in naked functions must use `noreturn` option
//~| WARN this was previously accepted
}
#[naked]
pub unsafe fn default_abi() {
//~^ WARN Rust ABI is unsupported in naked functions
//~| WARN this was previously accepted
asm!("", options(noreturn));
}
#[naked]
pub unsafe extern "Rust" fn rust_abi() {
//~^ WARN Rust ABI is unsupported in naked functions
//~| WARN this was previously accepted
asm!("", options(noreturn));
}
#[naked]
pub extern "C" fn valid_a<T>() -> T {
unsafe { asm!("", options(noreturn)); }
}
#[naked]
pub extern "C" fn valid_b() {
unsafe { { {
asm!("", options(noreturn)); ; ; ;
} ; } ; }
}
#[naked]
pub unsafe extern "C" fn valid_c() {
asm!("", options(noreturn));
}
#[cfg(target_arch = "x86_64")]
#[naked]
pub unsafe extern "C" fn valid_att_syntax() {
asm!("", options(noreturn, att_syntax));
}

View File

@ -0,0 +1,300 @@
error: asm with `pure` option must have at least one output
--> $DIR/naked-functions.rs:126:14
|
LL | asm!("", options(readonly, nostack), options(pure));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^
error: patterns not allowed in naked function parameters
--> $DIR/naked-functions.rs:13:5
|
LL | mut a: u32,
| ^^^^^
error: patterns not allowed in naked function parameters
--> $DIR/naked-functions.rs:15:5
|
LL | &b: &i32,
| ^^
error: patterns not allowed in naked function parameters
--> $DIR/naked-functions.rs:17:6
|
LL | (None | Some(_)): Option<std::ptr::NonNull<u8>>,
| ^^^^^^^^^^^^^^
error: patterns not allowed in naked function parameters
--> $DIR/naked-functions.rs:19:5
|
LL | P { x, y }: P,
| ^^^^^^^^^^
error: referencing function parameters is not allowed in naked functions
--> $DIR/naked-functions.rs:29:5
|
LL | a + 1
| ^
|
= help: follow the calling convention in asm block to use parameters
warning: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:26:1
|
LL | / pub unsafe extern "C" fn inc(a: u32) -> u32 {
LL | |
LL | |
LL | | a + 1
| | ----- non-asm is unsupported in naked functions
LL | |
LL | | }
| |_^
|
= note: `#[warn(unsupported_naked_functions)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
error: referencing function parameters is not allowed in naked functions
--> $DIR/naked-functions.rs:35:31
|
LL | asm!("/* {0} */", in(reg) a, options(noreturn));
| ^
|
= help: follow the calling convention in asm block to use parameters
warning: only `const` and `sym` operands are supported in naked functions
--> $DIR/naked-functions.rs:35:23
|
LL | asm!("/* {0} */", in(reg) a, options(noreturn));
| ^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:42:1
|
LL | / pub unsafe extern "C" fn inc_closure(a: u32) -> u32 {
LL | |
LL | |
LL | | (|| a + 1)()
| | ------------ non-asm is unsupported in naked functions
LL | | }
| |_^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: only `const` and `sym` operands are supported in naked functions
--> $DIR/naked-functions.rs:62:10
|
LL | in(reg) a,
| ^^^^^^^^^
...
LL | inlateout(reg) b,
| ^^^^^^^^^^^^^^^^
LL | inout(reg) c,
| ^^^^^^^^^^^^
LL | lateout(reg) d,
| ^^^^^^^^^^^^^^
LL | out(reg) e,
| ^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm in naked functions must use `noreturn` option
--> $DIR/naked-functions.rs:59:5
|
LL | / asm!("/* {0} {1} {2} {3} {4} {5} {6} */",
LL | |
LL | |
LL | | in(reg) a,
... |
LL | | sym G,
LL | | );
| |______^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:49:1
|
LL | / pub unsafe extern "C" fn unsupported_operands() {
LL | |
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 | | }
| |_^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:75:1
|
LL | / pub extern "C" fn missing_assembly() {
LL | |
LL | |
LL | | }
| |_^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm in naked functions must use `noreturn` option
--> $DIR/naked-functions.rs:84:5
|
LL | asm!("");
| ^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm in naked functions must use `noreturn` option
--> $DIR/naked-functions.rs:87:5
|
LL | asm!("");
| ^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm in naked functions must use `noreturn` option
--> $DIR/naked-functions.rs:90:5
|
LL | asm!("");
| ^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:81:1
|
LL | / pub extern "C" fn too_many_asm_blocks() {
LL | |
LL | |
LL | | asm!("");
... |
LL | | asm!("");
| | --------- multiple asm blocks are unsupported in naked functions
... |
LL | | asm!("");
| | --------- multiple asm blocks are unsupported in naked functions
... |
LL | | asm!("", options(noreturn));
| | ---------------------------- multiple asm blocks are unsupported in naked functions
LL | | }
| |_^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
error: referencing function parameters is not allowed in naked functions
--> $DIR/naked-functions.rs:101:11
|
LL | *&y
| ^
|
= help: follow the calling convention in asm block to use parameters
warning: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:98:5
|
LL | / pub extern "C" fn inner(y: usize) -> usize {
LL | |
LL | |
LL | | *&y
| | --- non-asm is unsupported in naked functions
LL | |
LL | | }
| |_____^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: the LLVM-style inline assembly is unsupported in naked functions
--> $DIR/naked-functions.rs:111:5
|
LL | llvm_asm!("");
| ^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
= help: use the new asm! syntax specified in RFC 2873
= note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
warning: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:108:1
|
LL | / unsafe extern "C" fn llvm() -> ! {
LL | |
LL | |
LL | | llvm_asm!("");
... |
LL | | core::hint::unreachable_unchecked();
| | ------------------------------------ non-asm is unsupported in naked functions
LL | | }
| |_^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm options unsupported in naked functions: `nomem`, `preserves_flags`
--> $DIR/naked-functions.rs:119:5
|
LL | asm!("", options(nomem, preserves_flags, noreturn));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm options unsupported in naked functions: `nostack`, `pure`, `readonly`
--> $DIR/naked-functions.rs:126:5
|
LL | asm!("", options(readonly, nostack), options(pure));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm in naked functions must use `noreturn` option
--> $DIR/naked-functions.rs:126:5
|
LL | asm!("", options(readonly, nostack), options(pure));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: Rust ABI is unsupported in naked functions
--> $DIR/naked-functions.rs:135:15
|
LL | pub unsafe fn default_abi() {
| ^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: Rust ABI is unsupported in naked functions
--> $DIR/naked-functions.rs:142:29
|
LL | pub unsafe extern "Rust" fn rust_abi() {
| ^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
error: aborting due to 8 previous errors; 19 warnings emitted

View File

@ -1,51 +0,0 @@
// Check that use of function parameters is validate in naked functions.
//
// ignore-wasm32 asm unsupported
#![feature(asm)]
#![feature(naked_functions)]
#![feature(or_patterns)]
#![crate_type = "lib"]
#[repr(C)]
pub struct P { x: u8, y: u16 }
#[naked]
pub unsafe extern "C" fn f(
mut a: u32,
//~^ ERROR patterns not allowed in naked function parameters
&b: &i32,
//~^ ERROR patterns not allowed in naked function parameters
(None | Some(_)): Option<std::ptr::NonNull<u8>>,
//~^ ERROR patterns not allowed in naked function parameters
P { x, y }: P,
//~^ ERROR patterns not allowed in naked function parameters
) {
asm!("", options(noreturn))
}
#[naked]
pub unsafe extern "C" fn inc(a: u32) -> u32 {
a + 1
//~^ ERROR use of parameters not allowed inside naked functions
}
#[naked]
pub unsafe extern "C" fn inc_asm(a: u32) -> u32 {
asm!("/* {0} */", in(reg) a, options(noreturn));
//~^ ERROR use of parameters not allowed inside naked functions
}
#[naked]
pub unsafe extern "C" fn sum(x: u32, y: u32) -> u32 {
// FIXME: Should be detected by asm-only check.
(|| { x + y})()
}
pub fn outer(x: u32) -> extern "C" fn(usize) -> usize {
#[naked]
pub extern "C" fn inner(y: usize) -> usize {
*&y
//~^ ERROR use of parameters not allowed inside naked functions
}
inner
}

View File

@ -1,44 +0,0 @@
error: patterns not allowed in naked function parameters
--> $DIR/naked-params.rs:14:5
|
LL | mut a: u32,
| ^^^^^
error: patterns not allowed in naked function parameters
--> $DIR/naked-params.rs:16:5
|
LL | &b: &i32,
| ^^
error: patterns not allowed in naked function parameters
--> $DIR/naked-params.rs:18:6
|
LL | (None | Some(_)): Option<std::ptr::NonNull<u8>>,
| ^^^^^^^^^^^^^^
error: patterns not allowed in naked function parameters
--> $DIR/naked-params.rs:20:5
|
LL | P { x, y }: P,
| ^^^^^^^^^^
error: use of parameters not allowed inside naked functions
--> $DIR/naked-params.rs:28:5
|
LL | a + 1
| ^
error: use of parameters not allowed inside naked functions
--> $DIR/naked-params.rs:34:31
|
LL | asm!("/* {0} */", in(reg) a, options(noreturn));
| ^
error: use of parameters not allowed inside naked functions
--> $DIR/naked-params.rs:47:11
|
LL | *&y
| ^
error: aborting due to 7 previous errors

View File

@ -1,11 +1,15 @@
#[naked]
//~^ the `#[naked]` attribute is an experimental feature
fn naked() {}
#![feature(asm)]
#[naked]
//~^ the `#[naked]` attribute is an experimental feature
fn naked_2() -> isize {
0
extern "C" fn naked() {
asm!("", options(noreturn))
}
#[naked]
//~^ the `#[naked]` attribute is an experimental feature
extern "C" fn naked_2() -> isize {
asm!("", options(noreturn))
}
fn main() {}

View File

@ -1,5 +1,5 @@
error[E0658]: the `#[naked]` attribute is an experimental feature
--> $DIR/feature-gate-naked_functions.rs:1:1
--> $DIR/feature-gate-naked_functions.rs:3:1
|
LL | #[naked]
| ^^^^^^^^
@ -8,7 +8,7 @@ LL | #[naked]
= help: add `#![feature(naked_functions)]` to the crate attributes to enable
error[E0658]: the `#[naked]` attribute is an experimental feature
--> $DIR/feature-gate-naked_functions.rs:5:1
--> $DIR/feature-gate-naked_functions.rs:9:1
|
LL | #[naked]
| ^^^^^^^^

View File

@ -1,15 +1,19 @@
#![feature(naked_functions)]
#![feature(asm, naked_functions)]
#[track_caller] //~ ERROR cannot use `#[track_caller]` with `#[naked]`
#[naked]
fn f() {}
extern "C" fn f() {
asm!("", options(noreturn));
}
struct S;
impl S {
#[track_caller] //~ ERROR cannot use `#[track_caller]` with `#[naked]`
#[naked]
fn g() {}
extern "C" fn g() {
asm!("", options(noreturn));
}
}
fn main() {}

View File

@ -5,7 +5,7 @@ LL | #[track_caller]
| ^^^^^^^^^^^^^^^
error[E0736]: cannot use `#[track_caller]` with `#[naked]`
--> $DIR/error-with-naked.rs:10:5
--> $DIR/error-with-naked.rs:12:5
|
LL | #[track_caller]
| ^^^^^^^^^^^^^^^

View File

@ -768,7 +768,7 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
ExprKind::InlineAsm(ref asm) => asm
.operands
.iter()
.map(|o| match o {
.map(|(o, _)| match o {
InlineAsmOperand::In { expr, .. }
| InlineAsmOperand::InOut { expr, .. }
| InlineAsmOperand::Const { expr }

View File

@ -517,7 +517,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
}
}
asm.options.hash(&mut self.s);
for op in asm.operands {
for (op, _op_sp) in asm.operands {
match op {
InlineAsmOperand::In { reg, expr } => {
reg.hash(&mut self.s);

View File

@ -293,7 +293,7 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) {
println!("{}template: {}", ind, InlineAsmTemplatePiece::to_string(asm.template));
println!("{}options: {:?}", ind, asm.options);
println!("{}operands:", ind);
for op in asm.operands {
for (op, _op_sp) in asm.operands {
match op {
hir::InlineAsmOperand::In { expr, .. }
| hir::InlineAsmOperand::InOut { expr, .. }