Handle asm const similar to inline const
This commit is contained in:
parent
6e4adbed76
commit
f482460f92
11 changed files with 95 additions and 68 deletions
|
@ -195,7 +195,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
}
|
||||
InlineAsmOperand::Const { anon_const } => hir::InlineAsmOperand::Const {
|
||||
anon_const: self.lower_anon_const_to_anon_const(anon_const),
|
||||
anon_const: self.lower_const_block(anon_const),
|
||||
},
|
||||
InlineAsmOperand::Sym { sym } => {
|
||||
let static_def_id = self
|
||||
|
|
|
@ -3506,7 +3506,7 @@ pub enum InlineAsmOperand<'hir> {
|
|||
out_expr: Option<&'hir Expr<'hir>>,
|
||||
},
|
||||
Const {
|
||||
anon_const: &'hir AnonConst,
|
||||
anon_const: ConstBlock,
|
||||
},
|
||||
SymFn {
|
||||
expr: &'hir Expr<'hir>,
|
||||
|
|
|
@ -1447,7 +1447,7 @@ pub fn walk_inline_asm<'v, V: Visitor<'v>>(
|
|||
visit_opt!(visitor, visit_expr, out_expr);
|
||||
}
|
||||
InlineAsmOperand::Const { anon_const, .. } => {
|
||||
try_visit!(visitor.visit_anon_const(anon_const));
|
||||
try_visit!(visitor.visit_inline_const(anon_const));
|
||||
}
|
||||
InlineAsmOperand::SymFn { expr, .. } => {
|
||||
try_visit!(visitor.visit_expr(expr));
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
use std::assert_matches::debug_assert_matches;
|
||||
|
||||
use rustc_abi::FieldIdx;
|
||||
use rustc_ast::InlineAsmTemplatePiece;
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
|
@ -21,6 +19,7 @@ pub struct InlineAsmCtxt<'a, 'tcx: 'a> {
|
|||
typing_env: ty::TypingEnv<'tcx>,
|
||||
target_features: &'tcx FxIndexSet<Symbol>,
|
||||
expr_ty: Box<dyn Fn(&hir::Expr<'tcx>) -> Ty<'tcx> + 'a>,
|
||||
node_ty: Box<dyn Fn(hir::HirId) -> Ty<'tcx> + 'a>,
|
||||
}
|
||||
|
||||
enum NonAsmTypeReason<'tcx> {
|
||||
|
@ -35,13 +34,15 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
tcx: TyCtxt<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
typing_env: ty::TypingEnv<'tcx>,
|
||||
get_operand_ty: impl Fn(&hir::Expr<'tcx>) -> Ty<'tcx> + 'a,
|
||||
expr_ty: impl Fn(&hir::Expr<'tcx>) -> Ty<'tcx> + 'a,
|
||||
node_ty: impl Fn(hir::HirId) -> Ty<'tcx> + 'a,
|
||||
) -> Self {
|
||||
InlineAsmCtxt {
|
||||
tcx,
|
||||
typing_env,
|
||||
target_features: tcx.asm_target_features(def_id),
|
||||
expr_ty: Box::new(get_operand_ty),
|
||||
expr_ty: Box::new(expr_ty),
|
||||
node_ty: Box::new(node_ty),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,6 +50,10 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
(self.expr_ty)(expr)
|
||||
}
|
||||
|
||||
fn node_ty(&self, hir_id: hir::HirId) -> Ty<'tcx> {
|
||||
(self.node_ty)(hir_id)
|
||||
}
|
||||
|
||||
// FIXME(compiler-errors): This could use `<$ty as Pointee>::Metadata == ()`
|
||||
fn is_thin_ptr_ty(&self, ty: Ty<'tcx>) -> bool {
|
||||
// Type still may have region variables, but `Sized` does not depend
|
||||
|
@ -487,12 +492,23 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
);
|
||||
}
|
||||
}
|
||||
// Typeck has checked that Const operands are integers.
|
||||
hir::InlineAsmOperand::Const { anon_const } => {
|
||||
debug_assert_matches!(
|
||||
self.tcx.type_of(anon_const.def_id).instantiate_identity().kind(),
|
||||
ty::Error(_) | ty::Int(_) | ty::Uint(_)
|
||||
);
|
||||
let ty = self.node_ty(anon_const.hir_id);
|
||||
match ty.kind() {
|
||||
ty::Error(_) => {}
|
||||
_ if ty.is_integral() => {}
|
||||
_ => {
|
||||
self.tcx
|
||||
.dcx()
|
||||
.struct_span_err(op_sp, "invalid type for `const` operand")
|
||||
.with_span_label(
|
||||
self.tcx.def_span(anon_const.def_id),
|
||||
format!("is {} `{}`", ty.kind().article(), ty),
|
||||
)
|
||||
.with_help("`const` operands must be of an integer type")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Typeck has checked that SymFn refers to a function.
|
||||
hir::InlineAsmOperand::SymFn { expr } => {
|
||||
|
|
|
@ -186,17 +186,6 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
|||
{
|
||||
Some(parent_did)
|
||||
}
|
||||
// Exclude `GlobalAsm` here which cannot have generics.
|
||||
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
|
||||
if asm.operands.iter().any(|(op, _op_sp)| match op {
|
||||
hir::InlineAsmOperand::Const { anon_const } => {
|
||||
anon_const.hir_id == hir_id
|
||||
}
|
||||
_ => false,
|
||||
}) =>
|
||||
{
|
||||
Some(parent_did)
|
||||
}
|
||||
Node::TyPat(_) => Some(parent_did),
|
||||
_ => None,
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ use rustc_middle::query::plumbing::CyclePlaceholder;
|
|||
use rustc_middle::ty::fold::fold_regions;
|
||||
use rustc_middle::ty::print::with_forced_trimmed_paths;
|
||||
use rustc_middle::ty::util::IntTypeExt;
|
||||
use rustc_middle::ty::{self, Article, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::{DUMMY_SP, Ident, Span};
|
||||
|
||||
|
@ -35,13 +35,6 @@ fn anon_const_type_of<'tcx>(icx: &ItemCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx
|
|||
let parent_node_id = tcx.parent_hir_id(hir_id);
|
||||
let parent_node = tcx.hir_node(parent_node_id);
|
||||
|
||||
let find_const = |&(op, op_sp)| match op {
|
||||
hir::InlineAsmOperand::Const { anon_const } if anon_const.hir_id == hir_id => {
|
||||
Some((anon_const, op_sp))
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
match parent_node {
|
||||
// Anon consts "inside" the type system.
|
||||
Node::ConstArg(&ConstArg {
|
||||
|
@ -50,31 +43,6 @@ fn anon_const_type_of<'tcx>(icx: &ItemCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx
|
|||
..
|
||||
}) if anon_hir_id == hir_id => const_arg_anon_type_of(icx, arg_hir_id, span),
|
||||
|
||||
// Anon consts outside the type system.
|
||||
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
|
||||
| Node::Item(&Item { kind: ItemKind::GlobalAsm { asm, .. }, .. })
|
||||
if let Some((anon_const, op_sp)) = asm.operands.iter().find_map(find_const) =>
|
||||
{
|
||||
let ty = tcx.typeck(def_id).node_type(hir_id);
|
||||
|
||||
match ty.kind() {
|
||||
ty::Error(_) => ty,
|
||||
ty::Int(_) | ty::Uint(_) => ty,
|
||||
_ => {
|
||||
let guar = tcx
|
||||
.dcx()
|
||||
.struct_span_err(op_sp, "invalid type for `const` operand")
|
||||
.with_span_label(
|
||||
tcx.def_span(anon_const.def_id),
|
||||
format!("is {} `{}`", ty.kind().article(), ty),
|
||||
)
|
||||
.with_help("`const` operands must be of an integer type")
|
||||
.emit();
|
||||
|
||||
Ty::new_error(tcx, guar)
|
||||
}
|
||||
}
|
||||
}
|
||||
Node::Variant(Variant { disr_expr: Some(e), .. }) if e.hir_id == hir_id => {
|
||||
tcx.adt_def(tcx.hir_get_parent_item(hir_id)).repr().discr_type().to_ty(tcx)
|
||||
}
|
||||
|
|
|
@ -1414,7 +1414,8 @@ impl<'a> State<'a> {
|
|||
hir::InlineAsmOperand::Const { ref anon_const } => {
|
||||
s.word("const");
|
||||
s.space();
|
||||
s.print_anon_const(anon_const);
|
||||
// Not using `print_inline_const` to avoid additional `const { ... }`
|
||||
s.ann.nested(s, Nested::Body(anon_const.body))
|
||||
}
|
||||
hir::InlineAsmOperand::SymFn { ref expr } => {
|
||||
s.word("sym_fn");
|
||||
|
|
|
@ -3778,13 +3778,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.check_expr_asm_operand(out_expr, false);
|
||||
}
|
||||
}
|
||||
hir::InlineAsmOperand::Const { ref anon_const } => {
|
||||
self.check_expr_const_block(anon_const, Expectation::NoExpectation);
|
||||
}
|
||||
hir::InlineAsmOperand::SymFn { expr } => {
|
||||
self.check_expr(expr);
|
||||
}
|
||||
// `AnonConst`s have their own body and is type-checked separately.
|
||||
// As they don't flow into the type system we don't need them to
|
||||
// be well-formed.
|
||||
hir::InlineAsmOperand::Const { .. } => {}
|
||||
hir::InlineAsmOperand::SymStatic { .. } => {}
|
||||
hir::InlineAsmOperand::Label { block } => {
|
||||
let previous_diverges = self.diverges.get();
|
||||
|
|
|
@ -110,8 +110,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.tcx.erase_regions(ty)
|
||||
}
|
||||
};
|
||||
InlineAsmCtxt::new(self.tcx, enclosing_id, self.typing_env(self.param_env), expr_ty)
|
||||
.check_asm(asm);
|
||||
let node_ty = |hir_id: HirId| self.typeck_results.borrow().node_type(hir_id);
|
||||
InlineAsmCtxt::new(
|
||||
self.tcx,
|
||||
enclosing_id,
|
||||
self.typing_env(self.param_env),
|
||||
expr_ty,
|
||||
node_ty,
|
||||
)
|
||||
.check_asm(asm);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -730,12 +730,20 @@ impl<'tcx> ThirBuildCx<'tcx> {
|
|||
}
|
||||
}
|
||||
hir::InlineAsmOperand::Const { ref anon_const } => {
|
||||
let value =
|
||||
mir::Const::from_unevaluated(tcx, anon_const.def_id.to_def_id())
|
||||
.instantiate_identity();
|
||||
let span = tcx.def_span(anon_const.def_id);
|
||||
let ty = self.typeck_results.node_type(anon_const.hir_id);
|
||||
let did = anon_const.def_id.to_def_id();
|
||||
let typeck_root_def_id = tcx.typeck_root_def_id(did);
|
||||
let parent_args = tcx.erase_regions(GenericArgs::identity_for_item(
|
||||
tcx,
|
||||
typeck_root_def_id,
|
||||
));
|
||||
let args =
|
||||
InlineConstArgs::new(tcx, InlineConstArgsParts { parent_args, ty })
|
||||
.args;
|
||||
|
||||
InlineAsmOperand::Const { value, span }
|
||||
let uneval = mir::UnevaluatedConst::new(did, args);
|
||||
let value = mir::Const::Unevaluated(uneval, ty);
|
||||
InlineAsmOperand::Const { value, span: tcx.def_span(did) }
|
||||
}
|
||||
hir::InlineAsmOperand::SymFn { expr } => {
|
||||
InlineAsmOperand::SymFn { value: self.mirror_expr(expr) }
|
||||
|
|
|
@ -459,4 +459,43 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
|
|||
visit::walk_attribute(self, attr);
|
||||
self.in_attr = orig_in_attr;
|
||||
}
|
||||
|
||||
fn visit_inline_asm(&mut self, asm: &'a InlineAsm) {
|
||||
let InlineAsm {
|
||||
asm_macro: _,
|
||||
template: _,
|
||||
template_strs: _,
|
||||
operands,
|
||||
clobber_abis: _,
|
||||
options: _,
|
||||
line_spans: _,
|
||||
} = asm;
|
||||
for (op, _span) in operands {
|
||||
match op {
|
||||
InlineAsmOperand::In { expr, reg: _ }
|
||||
| InlineAsmOperand::Out { expr: Some(expr), reg: _, late: _ }
|
||||
| InlineAsmOperand::InOut { expr, reg: _, late: _ } => {
|
||||
self.visit_expr(expr);
|
||||
}
|
||||
InlineAsmOperand::Out { expr: None, reg: _, late: _ } => {}
|
||||
InlineAsmOperand::SplitInOut { in_expr, out_expr, reg: _, late: _ } => {
|
||||
self.visit_expr(in_expr);
|
||||
if let Some(expr) = out_expr {
|
||||
self.visit_expr(expr);
|
||||
}
|
||||
}
|
||||
InlineAsmOperand::Const { anon_const } => {
|
||||
let def = self.create_def(
|
||||
anon_const.id,
|
||||
kw::Empty,
|
||||
DefKind::InlineConst,
|
||||
anon_const.value.span,
|
||||
);
|
||||
self.with_parent(def, |this| visit::walk_anon_const(this, anon_const));
|
||||
}
|
||||
InlineAsmOperand::Sym { sym } => self.visit_inline_asm_sym(sym),
|
||||
InlineAsmOperand::Label { block } => self.visit_block(block),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue