Skip to content

Commit bda05cc

Browse files
committedDec 7, 2020
Auto merge of rust-lang#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 rust-lang#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. rust-lang/rfcs#2774 rust-lang/rfcs#2972
2 parents 3d6705a + 8065dab commit bda05cc

File tree

23 files changed

+773
-139
lines changed

23 files changed

+773
-139
lines changed
 

‎compiler/rustc_ast_lowering/src/expr.rs

+4-6
Original file line numberDiff line numberDiff line change
@@ -1307,7 +1307,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
13071307
hir::InlineAsmOperand::Sym { expr: self.lower_expr_mut(expr) }
13081308
}
13091309
};
1310-
Some(op)
1310+
Some((op, *op_sp))
13111311
})
13121312
.collect();
13131313

@@ -1326,7 +1326,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
13261326
} = *p
13271327
{
13281328
let op_sp = asm.operands[operand_idx].1;
1329-
match &operands[operand_idx] {
1329+
match &operands[operand_idx].0 {
13301330
hir::InlineAsmOperand::In { reg, .. }
13311331
| hir::InlineAsmOperand::Out { reg, .. }
13321332
| hir::InlineAsmOperand::InOut { reg, .. }
@@ -1385,8 +1385,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
13851385
let mut used_input_regs = FxHashMap::default();
13861386
let mut used_output_regs = FxHashMap::default();
13871387
let mut required_features: Vec<&str> = vec![];
1388-
for (idx, op) in operands.iter().enumerate() {
1389-
let op_sp = asm.operands[idx].1;
1388+
for (idx, &(ref op, op_sp)) in operands.iter().enumerate() {
13901389
if let Some(reg) = op.reg() {
13911390
// Make sure we don't accidentally carry features from the
13921391
// previous iteration.
@@ -1458,8 +1457,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
14581457
skip = true;
14591458

14601459
let idx2 = *o.get();
1461-
let op2 = &operands[idx2];
1462-
let op_sp2 = asm.operands[idx2].1;
1460+
let &(ref op2, op_sp2) = &operands[idx2];
14631461
let reg2 = match op2.reg() {
14641462
Some(asm::InlineAsmRegOrRegClass::Reg(r)) => r,
14651463
_ => unreachable!(),

‎compiler/rustc_hir/src/arena.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ macro_rules! arena_types {
1414
// HIR types
1515
[few] hir_krate: rustc_hir::Crate<$tcx>,
1616
[] arm: rustc_hir::Arm<$tcx>,
17-
[] asm_operand: rustc_hir::InlineAsmOperand<$tcx>,
17+
[] asm_operand: (rustc_hir::InlineAsmOperand<$tcx>, Span),
1818
[] asm_template: rustc_ast::InlineAsmTemplatePiece,
1919
[] attribute: rustc_ast::Attribute,
2020
[] block: rustc_hir::Block<$tcx>,

‎compiler/rustc_hir/src/hir.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2143,7 +2143,7 @@ impl<'hir> InlineAsmOperand<'hir> {
21432143
#[derive(Debug, HashStable_Generic)]
21442144
pub struct InlineAsm<'hir> {
21452145
pub template: &'hir [InlineAsmTemplatePiece],
2146-
pub operands: &'hir [InlineAsmOperand<'hir>],
2146+
pub operands: &'hir [(InlineAsmOperand<'hir>, Span)],
21472147
pub options: InlineAsmOptions,
21482148
pub line_spans: &'hir [Span],
21492149
}

‎compiler/rustc_hir/src/intravisit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1191,7 +1191,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
11911191
walk_list!(visitor, visit_expr, optional_expression);
11921192
}
11931193
ExprKind::InlineAsm(ref asm) => {
1194-
for op in asm.operands {
1194+
for (op, _op_sp) in asm.operands {
11951195
match op {
11961196
InlineAsmOperand::In { expr, .. }
11971197
| InlineAsmOperand::InOut { expr, .. }

‎compiler/rustc_hir_pretty/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1462,7 +1462,7 @@ impl<'a> State<'a> {
14621462

14631463
let mut args = vec![];
14641464
args.push(AsmArg::Template(ast::InlineAsmTemplatePiece::to_string(&a.template)));
1465-
args.extend(a.operands.iter().map(|o| AsmArg::Operand(o)));
1465+
args.extend(a.operands.iter().map(|(o, _)| AsmArg::Operand(o)));
14661466
if !a.options.is_empty() {
14671467
args.push(AsmArg::Options(a.options));
14681468
}

‎compiler/rustc_lint_defs/src/builtin.rs

+45
Original file line numberDiff line numberDiff line change
@@ -2742,6 +2742,50 @@ declare_lint! {
27422742
"detects deprecation attributes with no effect",
27432743
}
27442744

2745+
declare_lint! {
2746+
/// The `unsupported_naked_functions` lint detects naked function
2747+
/// definitions that are unsupported but were previously accepted.
2748+
///
2749+
/// ### Example
2750+
///
2751+
/// ```rust
2752+
/// #![feature(naked_functions)]
2753+
///
2754+
/// #[naked]
2755+
/// pub fn f() -> u32 {
2756+
/// 42
2757+
/// }
2758+
/// ```
2759+
///
2760+
/// {{produces}}
2761+
///
2762+
/// ### Explanation
2763+
///
2764+
/// The naked functions must be defined using a single inline assembly
2765+
/// block.
2766+
///
2767+
/// The execution must never fall through past the end of the assembly
2768+
/// code so the block must use `noreturn` option. The asm block can also
2769+
/// use `att_syntax` option, but other options are not allowed.
2770+
///
2771+
/// The asm block must not contain any operands other than `const` and
2772+
/// `sym`. Additionally, naked function should specify a non-Rust ABI.
2773+
///
2774+
/// While other definitions of naked functions were previously accepted,
2775+
/// they are unsupported and might not work reliably. This is a
2776+
/// [future-incompatible] lint that will transition into hard error in
2777+
/// the future.
2778+
///
2779+
/// [future-incompatible]: ../index.md#future-incompatible-lints
2780+
pub UNSUPPORTED_NAKED_FUNCTIONS,
2781+
Warn,
2782+
"unsupported naked function definitions",
2783+
@future_incompatible = FutureIncompatibleInfo {
2784+
reference: "issue #32408 <https://github.com/rust-lang/rust/issues/32408>",
2785+
edition: None,
2786+
};
2787+
}
2788+
27452789
declare_tool_lint! {
27462790
pub rustc::INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
27472791
Deny,
@@ -2832,6 +2876,7 @@ declare_lint_pass! {
28322876
UNINHABITED_STATIC,
28332877
FUNCTION_ITEM_REFERENCES,
28342878
USELESS_DEPRECATED,
2879+
UNSUPPORTED_NAKED_FUNCTIONS,
28352880
]
28362881
}
28372882

‎compiler/rustc_mir_build/src/thir/cx/expr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
408408
operands: asm
409409
.operands
410410
.iter()
411-
.map(|op| {
411+
.map(|(op, _op_sp)| {
412412
match *op {
413413
hir::InlineAsmOperand::In { reg, ref expr } => {
414414
InlineAsmOperand::In { reg, expr: expr.to_ref() }

‎compiler/rustc_passes/src/intrinsicck.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ impl ExprVisitor<'tcx> {
347347
}
348348

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

‎compiler/rustc_passes/src/liveness.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1174,7 +1174,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
11741174
};
11751175

11761176
// Do a first pass for writing outputs only
1177-
for op in asm.operands.iter().rev() {
1177+
for (op, _op_sp) in asm.operands.iter().rev() {
11781178
match op {
11791179
hir::InlineAsmOperand::In { .. }
11801180
| hir::InlineAsmOperand::Const { .. }
@@ -1197,7 +1197,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
11971197

11981198
// Then do a second pass for inputs
11991199
let mut succ = succ;
1200-
for op in asm.operands.iter().rev() {
1200+
for (op, _op_sp) in asm.operands.iter().rev() {
12011201
match op {
12021202
hir::InlineAsmOperand::In { expr, .. }
12031203
| hir::InlineAsmOperand::Const { expr, .. }
@@ -1454,7 +1454,7 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) {
14541454
}
14551455

14561456
hir::ExprKind::InlineAsm(ref asm) => {
1457-
for op in asm.operands {
1457+
for (op, _op_sp) in asm.operands {
14581458
match op {
14591459
hir::InlineAsmOperand::Out { expr, .. } => {
14601460
if let Some(expr) = expr {

0 commit comments

Comments
 (0)