Skip to content

Commit c9687a9

Browse files
committed
Auto merge of #125558 - Amanieu:const-asm-type, r=lcnr
Tweak type inference for `const` operands in inline asm Previously these would be treated like integer literals and default to `i32` if a type could not be determined. To allow for forward-compatibility with `str` constants in the future, this PR changes type inference to use an unbound type variable instead. The actual type checking is deferred until after typeck where we still ensure that the final type for the `const` operand is an integer type. <!-- If this PR is related to an unstable feature or an otherwise tracked effort, please link to the relevant tracking issue here. If you don't know of a related tracking issue or there are none, feel free to ignore this. This PR will get automatically assigned to a reviewer. In case you would like a specific user to review your work, you can assign it to them by using r​? <reviewer name> -->
2 parents b586701 + eb726a5 commit c9687a9

13 files changed

+295
-265
lines changed

compiler/rustc_hir_analysis/src/check/intrinsicck.rs

+15-25
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use rustc_ast::InlineAsmTemplatePiece;
22
use rustc_data_structures::fx::FxIndexSet;
33
use rustc_hir::{self as hir, LangItem};
44
use rustc_middle::bug;
5-
use rustc_middle::ty::{self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, UintTy};
5+
use rustc_middle::ty::{self, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, UintTy};
66
use rustc_session::lint;
77
use rustc_span::def_id::LocalDefId;
88
use rustc_span::Symbol;
@@ -455,32 +455,22 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
455455
);
456456
}
457457
}
458-
// No special checking is needed for these:
459-
// - Typeck has checked that Const operands are integers.
460-
// - AST lowering guarantees that SymStatic points to a static.
461-
hir::InlineAsmOperand::Const { .. } | hir::InlineAsmOperand::SymStatic { .. } => {}
462-
// Check that sym actually points to a function. Later passes
463-
// depend on this.
458+
// Typeck has checked that Const operands are integers.
459+
hir::InlineAsmOperand::Const { anon_const } => {
460+
debug_assert!(matches!(
461+
self.tcx.type_of(anon_const.def_id).instantiate_identity().kind(),
462+
ty::Error(_) | ty::Int(_) | ty::Uint(_)
463+
));
464+
}
465+
// Typeck has checked that SymFn refers to a function.
464466
hir::InlineAsmOperand::SymFn { anon_const } => {
465-
let ty = self.tcx.type_of(anon_const.def_id).instantiate_identity();
466-
match ty.kind() {
467-
ty::Never | ty::Error(_) => {}
468-
ty::FnDef(..) => {}
469-
_ => {
470-
self.tcx
471-
.dcx()
472-
.struct_span_err(*op_sp, "invalid `sym` operand")
473-
.with_span_label(
474-
self.tcx.def_span(anon_const.def_id),
475-
format!("is {} `{}`", ty.kind().article(), ty),
476-
)
477-
.with_help(
478-
"`sym` operands must refer to either a function or a static",
479-
)
480-
.emit();
481-
}
482-
};
467+
debug_assert!(matches!(
468+
self.tcx.type_of(anon_const.def_id).instantiate_identity().kind(),
469+
ty::Error(_) | ty::FnDef(..)
470+
));
483471
}
472+
// AST lowering guarantees that SymStatic points to a static.
473+
hir::InlineAsmOperand::SymStatic { .. } => {}
484474
// No special checking is needed for labels.
485475
hir::InlineAsmOperand::Label { .. } => {}
486476
}

compiler/rustc_hir_analysis/src/collect/type_of.rs

+59-7
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use rustc_hir::HirId;
77
use rustc_middle::query::plumbing::CyclePlaceholder;
88
use rustc_middle::ty::print::with_forced_trimmed_paths;
99
use rustc_middle::ty::util::IntTypeExt;
10-
use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
10+
use rustc_middle::ty::{self, Article, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
1111
use rustc_middle::{bug, span_bug};
1212
use rustc_span::symbol::Ident;
1313
use rustc_span::{Span, DUMMY_SP};
@@ -34,6 +34,20 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
3434
let parent_node_id = tcx.parent_hir_id(hir_id);
3535
let parent_node = tcx.hir_node(parent_node_id);
3636

37+
let find_sym_fn = |&(op, op_sp)| match op {
38+
hir::InlineAsmOperand::SymFn { anon_const } if anon_const.hir_id == hir_id => {
39+
Some((anon_const, op_sp))
40+
}
41+
_ => None,
42+
};
43+
44+
let find_const = |&(op, op_sp)| match op {
45+
hir::InlineAsmOperand::Const { anon_const } if anon_const.hir_id == hir_id => {
46+
Some((anon_const, op_sp))
47+
}
48+
_ => None,
49+
};
50+
3751
match parent_node {
3852
// Anon consts "inside" the type system.
3953
Node::ConstArg(&ConstArg {
@@ -45,13 +59,51 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
4559
// Anon consts outside the type system.
4660
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
4761
| Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. })
48-
if asm.operands.iter().any(|(op, _op_sp)| match op {
49-
hir::InlineAsmOperand::Const { anon_const }
50-
| hir::InlineAsmOperand::SymFn { anon_const } => anon_const.hir_id == hir_id,
51-
_ => false,
52-
}) =>
62+
if let Some((anon_const, op_sp)) = asm.operands.iter().find_map(find_sym_fn) =>
5363
{
54-
tcx.typeck(def_id).node_type(hir_id)
64+
let ty = tcx.typeck(def_id).node_type(hir_id);
65+
66+
match ty.kind() {
67+
ty::Error(_) => ty,
68+
ty::FnDef(..) => ty,
69+
_ => {
70+
let guar = tcx
71+
.dcx()
72+
.struct_span_err(op_sp, "invalid `sym` operand")
73+
.with_span_label(
74+
tcx.def_span(anon_const.def_id),
75+
format!("is {} `{}`", ty.kind().article(), ty),
76+
)
77+
.with_help("`sym` operands must refer to either a function or a static")
78+
.emit();
79+
80+
Ty::new_error(tcx, guar)
81+
}
82+
}
83+
}
84+
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
85+
| Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. })
86+
if let Some((anon_const, op_sp)) = asm.operands.iter().find_map(find_const) =>
87+
{
88+
let ty = tcx.typeck(def_id).node_type(hir_id);
89+
90+
match ty.kind() {
91+
ty::Error(_) => ty,
92+
ty::Int(_) | ty::Uint(_) => ty,
93+
_ => {
94+
let guar = tcx
95+
.dcx()
96+
.struct_span_err(op_sp, "invalid type for `const` operand")
97+
.with_span_label(
98+
tcx.def_span(anon_const.def_id),
99+
format!("is {} `{}`", ty.kind().article(), ty),
100+
)
101+
.with_help("`const` operands must be of an integer type")
102+
.emit();
103+
104+
Ty::new_error(tcx, guar)
105+
}
106+
}
55107
}
56108
Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => {
57109
tcx.adt_def(tcx.hir().get_parent_item(hir_id)).repr().discr_type().to_ty(tcx)

compiler/rustc_hir_typeck/src/lib.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -265,11 +265,10 @@ fn infer_type_if_missing<'tcx>(fcx: &FnCtxt<'_, 'tcx>, node: Node<'tcx>) -> Opti
265265
Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), span, .. })
266266
| Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), span, .. }) => {
267267
asm.operands.iter().find_map(|(op, _op_sp)| match op {
268-
hir::InlineAsmOperand::Const { anon_const } if anon_const.hir_id == id => {
269-
// Inline assembly constants must be integers.
270-
Some(fcx.next_int_var())
271-
}
272-
hir::InlineAsmOperand::SymFn { anon_const } if anon_const.hir_id == id => {
268+
hir::InlineAsmOperand::Const { anon_const }
269+
| hir::InlineAsmOperand::SymFn { anon_const }
270+
if anon_const.hir_id == id =>
271+
{
273272
Some(fcx.next_ty_var(span))
274273
}
275274
_ => None,

tests/ui/asm/aarch64/type-check-2.rs

-18
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,6 @@ fn main() {
1515
unsafe {
1616
// Inputs must be initialized
1717

18-
// Sym operands must point to a function or static
19-
20-
const C: i32 = 0;
21-
static S: i32 = 0;
22-
asm!("{}", sym S);
23-
asm!("{}", sym main);
24-
asm!("{}", sym C);
25-
//~^ ERROR invalid `sym` operand
26-
2718
// Register operands must be Copy
2819

2920
asm!("{:v}", in(vreg) SimdNonCopy(0.0, 0.0, 0.0, 0.0));
@@ -65,12 +56,3 @@ fn main() {
6556
asm!("{}", in(reg) u);
6657
}
6758
}
68-
69-
// Sym operands must point to a function or static
70-
71-
const C: i32 = 0;
72-
static S: i32 = 0;
73-
global_asm!("{}", sym S);
74-
global_asm!("{}", sym main);
75-
global_asm!("{}", sym C);
76-
//~^ ERROR invalid `sym` operand
+9-25
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,21 @@
1-
error: invalid `sym` operand
2-
--> $DIR/type-check-2.rs:75:19
3-
|
4-
LL | global_asm!("{}", sym C);
5-
| ^^^^^ is an `i32`
6-
|
7-
= help: `sym` operands must refer to either a function or a static
8-
9-
error: invalid `sym` operand
10-
--> $DIR/type-check-2.rs:24:20
11-
|
12-
LL | asm!("{}", sym C);
13-
| ^^^^^ is an `i32`
14-
|
15-
= help: `sym` operands must refer to either a function or a static
16-
171
error: arguments for inline assembly must be copyable
18-
--> $DIR/type-check-2.rs:29:31
2+
--> $DIR/type-check-2.rs:20:31
193
|
204
LL | asm!("{:v}", in(vreg) SimdNonCopy(0.0, 0.0, 0.0, 0.0));
215
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
226
|
237
= note: `SimdNonCopy` does not implement the Copy trait
248

25-
error: cannot use value of type `{closure@$DIR/type-check-2.rs:41:28: 41:36}` for inline assembly
26-
--> $DIR/type-check-2.rs:41:28
9+
error: cannot use value of type `{closure@$DIR/type-check-2.rs:32:28: 32:36}` for inline assembly
10+
--> $DIR/type-check-2.rs:32:28
2711
|
2812
LL | asm!("{}", in(reg) |x: i32| x);
2913
| ^^^^^^^^^^
3014
|
3115
= note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
3216

3317
error: cannot use value of type `Vec<i32>` for inline assembly
34-
--> $DIR/type-check-2.rs:43:28
18+
--> $DIR/type-check-2.rs:34:28
3519
|
3620
LL | asm!("{}", in(reg) vec![0]);
3721
| ^^^^^^^
@@ -40,36 +24,36 @@ LL | asm!("{}", in(reg) vec![0]);
4024
= note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
4125

4226
error: cannot use value of type `(i32, i32, i32)` for inline assembly
43-
--> $DIR/type-check-2.rs:45:28
27+
--> $DIR/type-check-2.rs:36:28
4428
|
4529
LL | asm!("{}", in(reg) (1, 2, 3));
4630
| ^^^^^^^^^
4731
|
4832
= note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
4933

5034
error: cannot use value of type `[i32; 3]` for inline assembly
51-
--> $DIR/type-check-2.rs:47:28
35+
--> $DIR/type-check-2.rs:38:28
5236
|
5337
LL | asm!("{}", in(reg) [1, 2, 3]);
5438
| ^^^^^^^^^
5539
|
5640
= note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
5741

5842
error: cannot use value of type `fn() {main}` for inline assembly
59-
--> $DIR/type-check-2.rs:55:31
43+
--> $DIR/type-check-2.rs:46:31
6044
|
6145
LL | asm!("{}", inout(reg) f);
6246
| ^
6347
|
6448
= note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
6549

6650
error: cannot use value of type `&mut i32` for inline assembly
67-
--> $DIR/type-check-2.rs:58:31
51+
--> $DIR/type-check-2.rs:49:31
6852
|
6953
LL | asm!("{}", inout(reg) r);
7054
| ^
7155
|
7256
= note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
7357

74-
error: aborting due to 9 previous errors
58+
error: aborting due to 7 previous errors
7559

tests/ui/asm/invalid-const-operand.rs

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//@ needs-asm-support
2+
//@ ignore-nvptx64
3+
//@ ignore-spirv
4+
5+
#![feature(asm_const)]
6+
7+
use std::arch::{asm, global_asm};
8+
9+
// Const operands must be integers and must be constants.
10+
11+
global_asm!("{}", const 0);
12+
global_asm!("{}", const 0i32);
13+
global_asm!("{}", const 0i128);
14+
global_asm!("{}", const 0f32);
15+
//~^ ERROR invalid type for `const` operand
16+
global_asm!("{}", const 0 as *mut u8);
17+
//~^ ERROR invalid type for `const` operand
18+
19+
fn main() {
20+
unsafe {
21+
// Const operands must be integers and must be constants.
22+
23+
asm!("{}", const 0);
24+
asm!("{}", const 0i32);
25+
asm!("{}", const 0i128);
26+
asm!("{}", const 0f32);
27+
//~^ ERROR invalid type for `const` operand
28+
asm!("{}", const 0 as *mut u8);
29+
//~^ ERROR invalid type for `const` operand
30+
asm!("{}", const &0);
31+
//~^ ERROR invalid type for `const` operand
32+
33+
// Constants must be... constant
34+
35+
let x = 0;
36+
const fn const_foo(x: i32) -> i32 {
37+
x
38+
}
39+
const fn const_bar<T>(x: T) -> T {
40+
x
41+
}
42+
asm!("{}", const x);
43+
//~^ ERROR attempt to use a non-constant value in a constant
44+
asm!("{}", const const_foo(0));
45+
asm!("{}", const const_foo(x));
46+
//~^ ERROR attempt to use a non-constant value in a constant
47+
asm!("{}", const const_bar(0));
48+
asm!("{}", const const_bar(x));
49+
//~^ ERROR attempt to use a non-constant value in a constant
50+
}
51+
}

0 commit comments

Comments
 (0)