Skip to content

Commit

Permalink
Auto merge of rust-lang#79653 - tmiasko:naked-functions, r=Amanieu
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bors committed Dec 7, 2020
2 parents 3d6705a + 8065dab commit bda05cc
Show file tree
Hide file tree
Showing 23 changed files with 773 additions and 139 deletions.
10 changes: 4 additions & 6 deletions compiler/rustc_ast_lowering/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1307,7 +1307,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
hir::InlineAsmOperand::Sym { expr: self.lower_expr_mut(expr) }
}
};
Some(op)
Some((op, *op_sp))
})
.collect();

Expand All @@ -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, .. }
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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!(),
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir/src/arena.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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],
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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, .. }
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_pretty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down
45 changes: 45 additions & 0 deletions compiler/rustc_lint_defs/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -2832,6 +2876,7 @@ declare_lint_pass! {
UNINHABITED_STATIC,
FUNCTION_ITEM_REFERENCES,
USELESS_DEPRECATED,
UNSUPPORTED_NAKED_FUNCTIONS,
]
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_build/src/thir/cx/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() }
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_passes/src/intrinsicck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_passes/src/liveness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 { .. }
Expand All @@ -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, .. }
Expand Down Expand Up @@ -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 {
Expand Down
Loading

0 comments on commit bda05cc

Please sign in to comment.