Skip to content

Commit 174bbfb

Browse files
authored
Rollup merge of #137686 - nbdd0121:asm_const, r=compiler-errors
Handle asm const similar to inline const Previously, asm consts are handled similar to anon consts rather than inline consts. Anon consts are not good at dealing with lifetimes, because `type_of` has lifetimes erased already. Inline consts can deal with lifetimes because they live in an outer typeck context. And since `global_asm!` lacks an outer typeck context, we have implemented asm consts with anon consts while they're in fact more similar to inline consts. This was changed in #137180, and this means that handling asm consts as inline consts are possible. While as `@compiler-errors` pointed out, `const` currently can't be used with any types with lifetime, this is about to change if #128464 is implemented. This PR is a preparatory PR for that feature. As an unintentional side effect, fix #117877. cc `@Amanieu` r? `@compiler-errors`
2 parents 51e0976 + 395b0fb commit 174bbfb

File tree

18 files changed

+133
-100
lines changed

18 files changed

+133
-100
lines changed

Diff for: compiler/rustc_ast_lowering/src/asm.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
195195
}
196196
}
197197
InlineAsmOperand::Const { anon_const } => hir::InlineAsmOperand::Const {
198-
anon_const: self.lower_anon_const_to_anon_const(anon_const),
198+
anon_const: self.lower_const_block(anon_const),
199199
},
200200
InlineAsmOperand::Sym { sym } => {
201201
let static_def_id = self

Diff for: compiler/rustc_hir/src/hir.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3512,7 +3512,7 @@ pub enum InlineAsmOperand<'hir> {
35123512
out_expr: Option<&'hir Expr<'hir>>,
35133513
},
35143514
Const {
3515-
anon_const: &'hir AnonConst,
3515+
anon_const: ConstBlock,
35163516
},
35173517
SymFn {
35183518
expr: &'hir Expr<'hir>,

Diff for: compiler/rustc_hir/src/intravisit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1447,7 +1447,7 @@ pub fn walk_inline_asm<'v, V: Visitor<'v>>(
14471447
visit_opt!(visitor, visit_expr, out_expr);
14481448
}
14491449
InlineAsmOperand::Const { anon_const, .. } => {
1450-
try_visit!(visitor.visit_anon_const(anon_const));
1450+
try_visit!(visitor.visit_inline_const(anon_const));
14511451
}
14521452
InlineAsmOperand::SymFn { expr, .. } => {
14531453
try_visit!(visitor.visit_expr(expr));

Diff for: compiler/rustc_hir_analysis/src/check/intrinsicck.rs

+25-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use std::assert_matches::debug_assert_matches;
2-
31
use rustc_abi::FieldIdx;
42
use rustc_ast::InlineAsmTemplatePiece;
53
use rustc_data_structures::fx::FxIndexSet;
@@ -21,6 +19,7 @@ pub struct InlineAsmCtxt<'a, 'tcx: 'a> {
2119
typing_env: ty::TypingEnv<'tcx>,
2220
target_features: &'tcx FxIndexSet<Symbol>,
2321
expr_ty: Box<dyn Fn(&hir::Expr<'tcx>) -> Ty<'tcx> + 'a>,
22+
node_ty: Box<dyn Fn(hir::HirId) -> Ty<'tcx> + 'a>,
2423
}
2524

2625
enum NonAsmTypeReason<'tcx> {
@@ -35,20 +34,26 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
3534
tcx: TyCtxt<'tcx>,
3635
def_id: LocalDefId,
3736
typing_env: ty::TypingEnv<'tcx>,
38-
get_operand_ty: impl Fn(&hir::Expr<'tcx>) -> Ty<'tcx> + 'a,
37+
expr_ty: impl Fn(&hir::Expr<'tcx>) -> Ty<'tcx> + 'a,
38+
node_ty: impl Fn(hir::HirId) -> Ty<'tcx> + 'a,
3939
) -> Self {
4040
InlineAsmCtxt {
4141
tcx,
4242
typing_env,
4343
target_features: tcx.asm_target_features(def_id),
44-
expr_ty: Box::new(get_operand_ty),
44+
expr_ty: Box::new(expr_ty),
45+
node_ty: Box::new(node_ty),
4546
}
4647
}
4748

4849
fn expr_ty(&self, expr: &hir::Expr<'tcx>) -> Ty<'tcx> {
4950
(self.expr_ty)(expr)
5051
}
5152

53+
fn node_ty(&self, hir_id: hir::HirId) -> Ty<'tcx> {
54+
(self.node_ty)(hir_id)
55+
}
56+
5257
// FIXME(compiler-errors): This could use `<$ty as Pointee>::Metadata == ()`
5358
fn is_thin_ptr_ty(&self, ty: Ty<'tcx>) -> bool {
5459
// Type still may have region variables, but `Sized` does not depend
@@ -487,12 +492,23 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
487492
);
488493
}
489494
}
490-
// Typeck has checked that Const operands are integers.
491495
hir::InlineAsmOperand::Const { anon_const } => {
492-
debug_assert_matches!(
493-
self.tcx.type_of(anon_const.def_id).instantiate_identity().kind(),
494-
ty::Error(_) | ty::Int(_) | ty::Uint(_)
495-
);
496+
let ty = self.node_ty(anon_const.hir_id);
497+
match ty.kind() {
498+
ty::Error(_) => {}
499+
_ if ty.is_integral() => {}
500+
_ => {
501+
self.tcx
502+
.dcx()
503+
.struct_span_err(op_sp, "invalid type for `const` operand")
504+
.with_span_label(
505+
self.tcx.def_span(anon_const.def_id),
506+
format!("is {} `{}`", ty.kind().article(), ty),
507+
)
508+
.with_help("`const` operands must be of an integer type")
509+
.emit();
510+
}
511+
}
496512
}
497513
// Typeck has checked that SymFn refers to a function.
498514
hir::InlineAsmOperand::SymFn { expr } => {

Diff for: compiler/rustc_hir_analysis/src/collect/generics_of.rs

-11
Original file line numberDiff line numberDiff line change
@@ -186,17 +186,6 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
186186
{
187187
Some(parent_did)
188188
}
189-
// Exclude `GlobalAsm` here which cannot have generics.
190-
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
191-
if asm.operands.iter().any(|(op, _op_sp)| match op {
192-
hir::InlineAsmOperand::Const { anon_const } => {
193-
anon_const.hir_id == hir_id
194-
}
195-
_ => false,
196-
}) =>
197-
{
198-
Some(parent_did)
199-
}
200189
Node::TyPat(_) => Some(parent_did),
201190
_ => None,
202191
}

Diff for: compiler/rustc_hir_analysis/src/collect/type_of.rs

+1-33
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc_middle::query::plumbing::CyclePlaceholder;
88
use rustc_middle::ty::fold::fold_regions;
99
use rustc_middle::ty::print::with_forced_trimmed_paths;
1010
use rustc_middle::ty::util::IntTypeExt;
11-
use rustc_middle::ty::{self, Article, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
11+
use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
1212
use rustc_middle::{bug, span_bug};
1313
use rustc_span::{DUMMY_SP, Ident, Span};
1414

@@ -35,13 +35,6 @@ fn anon_const_type_of<'tcx>(icx: &ItemCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx
3535
let parent_node_id = tcx.parent_hir_id(hir_id);
3636
let parent_node = tcx.hir_node(parent_node_id);
3737

38-
let find_const = |&(op, op_sp)| match op {
39-
hir::InlineAsmOperand::Const { anon_const } if anon_const.hir_id == hir_id => {
40-
Some((anon_const, op_sp))
41-
}
42-
_ => None,
43-
};
44-
4538
match parent_node {
4639
// Anon consts "inside" the type system.
4740
Node::ConstArg(&ConstArg {
@@ -50,31 +43,6 @@ fn anon_const_type_of<'tcx>(icx: &ItemCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx
5043
..
5144
}) if anon_hir_id == hir_id => const_arg_anon_type_of(icx, arg_hir_id, span),
5245

53-
// Anon consts outside the type system.
54-
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
55-
| Node::Item(&Item { kind: ItemKind::GlobalAsm { asm, .. }, .. })
56-
if let Some((anon_const, op_sp)) = asm.operands.iter().find_map(find_const) =>
57-
{
58-
let ty = tcx.typeck(def_id).node_type(hir_id);
59-
60-
match ty.kind() {
61-
ty::Error(_) => ty,
62-
ty::Int(_) | ty::Uint(_) => ty,
63-
_ => {
64-
let guar = tcx
65-
.dcx()
66-
.struct_span_err(op_sp, "invalid type for `const` operand")
67-
.with_span_label(
68-
tcx.def_span(anon_const.def_id),
69-
format!("is {} `{}`", ty.kind().article(), ty),
70-
)
71-
.with_help("`const` operands must be of an integer type")
72-
.emit();
73-
74-
Ty::new_error(tcx, guar)
75-
}
76-
}
77-
}
7846
Node::Variant(Variant { disr_expr: Some(e), .. }) if e.hir_id == hir_id => {
7947
tcx.adt_def(tcx.hir_get_parent_item(hir_id)).repr().discr_type().to_ty(tcx)
8048
}

Diff for: compiler/rustc_hir_pretty/src/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1413,7 +1413,8 @@ impl<'a> State<'a> {
14131413
hir::InlineAsmOperand::Const { ref anon_const } => {
14141414
s.word("const");
14151415
s.space();
1416-
s.print_anon_const(anon_const);
1416+
// Not using `print_inline_const` to avoid additional `const { ... }`
1417+
s.ann.nested(s, Nested::Body(anon_const.body))
14171418
}
14181419
hir::InlineAsmOperand::SymFn { ref expr } => {
14191420
s.word("sym_fn");

Diff for: compiler/rustc_hir_typeck/src/expr.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -3774,13 +3774,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
37743774
self.check_expr_asm_operand(out_expr, false);
37753775
}
37763776
}
3777+
hir::InlineAsmOperand::Const { ref anon_const } => {
3778+
self.check_expr_const_block(anon_const, Expectation::NoExpectation);
3779+
}
37773780
hir::InlineAsmOperand::SymFn { expr } => {
37783781
self.check_expr(expr);
37793782
}
3780-
// `AnonConst`s have their own body and is type-checked separately.
3781-
// As they don't flow into the type system we don't need them to
3782-
// be well-formed.
3783-
hir::InlineAsmOperand::Const { .. } => {}
37843783
hir::InlineAsmOperand::SymStatic { .. } => {}
37853784
hir::InlineAsmOperand::Label { block } => {
37863785
let previous_diverges = self.diverges.get();

Diff for: compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
110110
self.tcx.erase_regions(ty)
111111
}
112112
};
113-
InlineAsmCtxt::new(self.tcx, enclosing_id, self.typing_env(self.param_env), expr_ty)
114-
.check_asm(asm);
113+
let node_ty = |hir_id: HirId| self.typeck_results.borrow().node_type(hir_id);
114+
InlineAsmCtxt::new(
115+
self.tcx,
116+
enclosing_id,
117+
self.typing_env(self.param_env),
118+
expr_ty,
119+
node_ty,
120+
)
121+
.check_asm(asm);
115122
}
116123
}
117124

Diff for: compiler/rustc_hir_typeck/src/writeback.rs

+8-13
Original file line numberDiff line numberDiff line change
@@ -248,13 +248,6 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
248248
}
249249
}
250250
}
251-
252-
fn visit_const_block(&mut self, span: Span, anon_const: &hir::ConstBlock) {
253-
self.visit_node_id(span, anon_const.hir_id);
254-
255-
let body = self.tcx().hir_body(anon_const.body);
256-
self.visit_body(body);
257-
}
258251
}
259252

260253
///////////////////////////////////////////////////////////////////////////
@@ -284,9 +277,6 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
284277
hir::ExprKind::Field(..) | hir::ExprKind::OffsetOf(..) => {
285278
self.visit_field_id(e.hir_id);
286279
}
287-
hir::ExprKind::ConstBlock(ref anon_const) => {
288-
self.visit_const_block(e.span, anon_const);
289-
}
290280
_ => {}
291281
}
292282

@@ -297,6 +287,14 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
297287
self.fix_index_builtin_expr(e);
298288
}
299289

290+
fn visit_inline_const(&mut self, anon_const: &hir::ConstBlock) {
291+
let span = self.tcx().def_span(anon_const.def_id);
292+
self.visit_node_id(span, anon_const.hir_id);
293+
294+
let body = self.tcx().hir_body(anon_const.body);
295+
self.visit_body(body);
296+
}
297+
300298
fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
301299
match &p.kind {
302300
hir::GenericParamKind::Lifetime { .. } => {
@@ -340,9 +338,6 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
340338

341339
fn visit_pat_expr(&mut self, expr: &'tcx hir::PatExpr<'tcx>) {
342340
self.visit_node_id(expr.span, expr.hir_id);
343-
if let hir::PatExprKind::ConstBlock(c) = &expr.kind {
344-
self.visit_const_block(expr.span, c);
345-
}
346341
intravisit::walk_pat_expr(self, expr);
347342
}
348343

Diff for: compiler/rustc_mir_build/src/thir/cx/expr.rs

+14-6
Original file line numberDiff line numberDiff line change
@@ -730,12 +730,20 @@ impl<'tcx> ThirBuildCx<'tcx> {
730730
}
731731
}
732732
hir::InlineAsmOperand::Const { ref anon_const } => {
733-
let value =
734-
mir::Const::from_unevaluated(tcx, anon_const.def_id.to_def_id())
735-
.instantiate_identity();
736-
let span = tcx.def_span(anon_const.def_id);
737-
738-
InlineAsmOperand::Const { value, span }
733+
let ty = self.typeck_results.node_type(anon_const.hir_id);
734+
let did = anon_const.def_id.to_def_id();
735+
let typeck_root_def_id = tcx.typeck_root_def_id(did);
736+
let parent_args = tcx.erase_regions(GenericArgs::identity_for_item(
737+
tcx,
738+
typeck_root_def_id,
739+
));
740+
let args =
741+
InlineConstArgs::new(tcx, InlineConstArgsParts { parent_args, ty })
742+
.args;
743+
744+
let uneval = mir::UnevaluatedConst::new(did, args);
745+
let value = mir::Const::Unevaluated(uneval, ty);
746+
InlineAsmOperand::Const { value, span: tcx.def_span(did) }
739747
}
740748
hir::InlineAsmOperand::SymFn { expr } => {
741749
InlineAsmOperand::SymFn { value: self.mirror_expr(expr) }

Diff for: compiler/rustc_resolve/src/def_collector.rs

+39
Original file line numberDiff line numberDiff line change
@@ -459,4 +459,43 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
459459
visit::walk_attribute(self, attr);
460460
self.in_attr = orig_in_attr;
461461
}
462+
463+
fn visit_inline_asm(&mut self, asm: &'a InlineAsm) {
464+
let InlineAsm {
465+
asm_macro: _,
466+
template: _,
467+
template_strs: _,
468+
operands,
469+
clobber_abis: _,
470+
options: _,
471+
line_spans: _,
472+
} = asm;
473+
for (op, _span) in operands {
474+
match op {
475+
InlineAsmOperand::In { expr, reg: _ }
476+
| InlineAsmOperand::Out { expr: Some(expr), reg: _, late: _ }
477+
| InlineAsmOperand::InOut { expr, reg: _, late: _ } => {
478+
self.visit_expr(expr);
479+
}
480+
InlineAsmOperand::Out { expr: None, reg: _, late: _ } => {}
481+
InlineAsmOperand::SplitInOut { in_expr, out_expr, reg: _, late: _ } => {
482+
self.visit_expr(in_expr);
483+
if let Some(expr) = out_expr {
484+
self.visit_expr(expr);
485+
}
486+
}
487+
InlineAsmOperand::Const { anon_const } => {
488+
let def = self.create_def(
489+
anon_const.id,
490+
kw::Empty,
491+
DefKind::InlineConst,
492+
anon_const.value.span,
493+
);
494+
self.with_parent(def, |this| visit::walk_anon_const(this, anon_const));
495+
}
496+
InlineAsmOperand::Sym { sym } => self.visit_inline_asm_sym(sym),
497+
InlineAsmOperand::Label { block } => self.visit_block(block),
498+
}
499+
}
500+
}
462501
}

Diff for: tests/crashes/117877.rs

-13
This file was deleted.

Diff for: tests/ui/asm/const-resolve-error.rs

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
//@ edition:2021
2+
//@ needs-asm-support
3+
4+
use std::arch::asm;
5+
6+
async unsafe fn foo<'a>() {
7+
asm!("/* {0} */", const N); //~ ERROR E0425
8+
}
9+
10+
fn main() {}

Diff for: tests/ui/asm/const-resolve-error.stderr

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0425]: cannot find value `N` in this scope
2+
--> $DIR/const-resolve-error.rs:7:29
3+
|
4+
LL | asm!("/* {0} */", const N);
5+
| ^ not found in this scope
6+
|
7+
help: you might be missing a const parameter
8+
|
9+
LL | async unsafe fn foo<'a, const N: /* Type */>() {
10+
| +++++++++++++++++++++
11+
12+
error: aborting due to 1 previous error
13+
14+
For more information about this error, try `rustc --explain E0425`.

Diff for: tests/ui/asm/fail-const-eval-issue-121099.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@ use std::arch::global_asm;
55

66
fn main() {}
77

8-
global_asm!("/* {} */", const 1 << 500); //~ ERROR evaluation of constant value failed [E0080]
8+
global_asm!("/* {} */", const 1 << 500); //~ ERROR E0080
99

10-
global_asm!("/* {} */", const 1 / 0); //~ ERROR evaluation of constant value failed [E0080]
10+
global_asm!("/* {} */", const 1 / 0); //~ ERROR E0080

Diff for: tests/ui/asm/fail-const-eval-issue-121099.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
error[E0080]: evaluation of constant value failed
1+
error[E0080]: evaluation of `{global_asm#0}::{constant#0}` failed
22
--> $DIR/fail-const-eval-issue-121099.rs:8:31
33
|
44
LL | global_asm!("/* {} */", const 1 << 500);
55
| ^^^^^^^^ attempt to shift left by `500_i32`, which would overflow
66

7-
error[E0080]: evaluation of constant value failed
7+
error[E0080]: evaluation of `{global_asm#1}::{constant#0}` failed
88
--> $DIR/fail-const-eval-issue-121099.rs:10:31
99
|
1010
LL | global_asm!("/* {} */", const 1 / 0);

0 commit comments

Comments
 (0)