diff --git a/compiler/rustc_passes/src/intrinsicck.rs b/compiler/rustc_passes/src/intrinsicck.rs index 012d97ef106..96e9a40df36 100644 --- a/compiler/rustc_passes/src/intrinsicck.rs +++ b/compiler/rustc_passes/src/intrinsicck.rs @@ -139,6 +139,7 @@ impl ExprVisitor<'tcx> { reg: InlineAsmRegOrRegClass, expr: &hir::Expr<'tcx>, template: &[InlineAsmTemplatePiece], + is_input: bool, tied_input: Option<(&hir::Expr<'tcx>, Option)>, ) -> Option { // Check the type against the allowed types for inline asm. @@ -150,7 +151,9 @@ impl ExprVisitor<'tcx> { _ => unreachable!(), }; let asm_ty = match *ty.kind() { - ty::Never | ty::Error(_) => return None, + // `!` is allowed for input but not for output (issue #87802) + ty::Never if is_input => return None, + ty::Error(_) => return None, ty::Int(IntTy::I8) | ty::Uint(UintTy::U8) => Some(InlineAsmType::I8), ty::Int(IntTy::I16) | ty::Uint(UintTy::U16) => Some(InlineAsmType::I16), ty::Int(IntTy::I32) | ty::Uint(UintTy::U32) => Some(InlineAsmType::I32), @@ -350,24 +353,26 @@ impl ExprVisitor<'tcx> { for (idx, (op, _)) in asm.operands.iter().enumerate() { match *op { hir::InlineAsmOperand::In { reg, ref expr } => { - self.check_asm_operand_type(idx, reg, expr, asm.template, None); + self.check_asm_operand_type(idx, reg, expr, asm.template, true, None); } hir::InlineAsmOperand::Out { reg, late: _, ref expr } => { if let Some(expr) = expr { - self.check_asm_operand_type(idx, reg, expr, asm.template, None); + self.check_asm_operand_type(idx, reg, expr, asm.template, false, None); } } hir::InlineAsmOperand::InOut { reg, late: _, ref expr } => { - self.check_asm_operand_type(idx, reg, expr, asm.template, None); + self.check_asm_operand_type(idx, reg, expr, asm.template, false, None); } hir::InlineAsmOperand::SplitInOut { reg, late: _, ref in_expr, ref out_expr } => { - let in_ty = self.check_asm_operand_type(idx, reg, in_expr, asm.template, None); + let in_ty = + self.check_asm_operand_type(idx, reg, in_expr, asm.template, true, None); if let Some(out_expr) = out_expr { self.check_asm_operand_type( idx, reg, out_expr, asm.template, + false, Some((in_expr, in_ty)), ); } diff --git a/src/test/ui/asm/issue-87802.rs b/src/test/ui/asm/issue-87802.rs new file mode 100644 index 00000000000..b1fc13b6a7e --- /dev/null +++ b/src/test/ui/asm/issue-87802.rs @@ -0,0 +1,17 @@ +// only-x86_64 +// Make sure rustc doesn't ICE on asm! when output type is !. + +#![feature(asm)] + +fn hmm() -> ! { + let x; + unsafe { + asm!("/* {0} */", out(reg) x); + //~^ ERROR cannot use value of type `!` for inline assembly + } + x +} + +fn main() { + hmm(); +} diff --git a/src/test/ui/asm/issue-87802.stderr b/src/test/ui/asm/issue-87802.stderr new file mode 100644 index 00000000000..1eb72b68a7f --- /dev/null +++ b/src/test/ui/asm/issue-87802.stderr @@ -0,0 +1,10 @@ +error: cannot use value of type `!` for inline assembly + --> $DIR/issue-87802.rs:9:36 + | +LL | asm!("/* {0} */", out(reg) x); + | ^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + +error: aborting due to previous error +