Skip to content

Commit

Permalink
Handle lifetimes correctly in in sym in line-asm
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed Sep 23, 2023
1 parent f6bbc80 commit 10e62c3
Show file tree
Hide file tree
Showing 25 changed files with 248 additions and 119 deletions.
37 changes: 23 additions & 14 deletions compiler/rustc_ast_lowering/src/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
&mut self,
sp: Span,
asm: &InlineAsm,
is_global: bool,
) -> &'hir hir::InlineAsm<'hir> {
// Rustdoc needs to support asm! from foreign architectures: don't try
// lowering the register constraints in this case.
Expand Down Expand Up @@ -221,18 +222,24 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
tokens: None,
};

// Wrap the expression in an AnonConst.
let parent_def_id = self.current_hir_id_owner;
let node_id = self.next_node_id();
self.create_def(
parent_def_id.def_id,
node_id,
DefPathData::AnonConst,
*op_sp,
);
let anon_const = AnonConst { id: node_id, value: P(expr) };
hir::InlineAsmOperand::SymFn {
anon_const: self.lower_anon_const(&anon_const),
if is_global {
// Wrap the expression in an AnonConst.
let parent_def_id = self.current_hir_id_owner;
let node_id = self.next_node_id();
self.create_def(
parent_def_id.def_id,
node_id,
DefPathData::AnonConst,
*op_sp,
);
let anon_const = AnonConst { id: node_id, value: P(expr) };
hir::InlineAsmOperand::SymFnInGlobal {
anon_const: self.lower_anon_const(&anon_const),
}
} else {
hir::InlineAsmOperand::SymFnInInline {
expr: self.lower_expr(&expr),
}
}
}
}
Expand Down Expand Up @@ -288,7 +295,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
op_span: op_sp,
});
}
hir::InlineAsmOperand::SymFn { .. }
hir::InlineAsmOperand::SymFnInGlobal { .. }
| hir::InlineAsmOperand::SymFnInInline { .. }
| hir::InlineAsmOperand::SymStatic { .. } => {
sess.emit_err(InvalidAsmTemplateModifierSym {
placeholder_span,
Expand Down Expand Up @@ -333,7 +341,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
| hir::InlineAsmOperand::SplitInOut { .. } => (true, true),

hir::InlineAsmOperand::Const { .. }
| hir::InlineAsmOperand::SymFn { .. }
| hir::InlineAsmOperand::SymFnInGlobal { .. }
| hir::InlineAsmOperand::SymFnInInline { .. }
| hir::InlineAsmOperand::SymStatic { .. } => {
unreachable!()
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_ast_lowering/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
hir::ExprKind::Become(sub_expr)
}
ExprKind::InlineAsm(asm) => {
hir::ExprKind::InlineAsm(self.lower_inline_asm(e.span, asm))
hir::ExprKind::InlineAsm(self.lower_inline_asm(e.span, asm, false))
}
ExprKind::FormatArgs(fmt) => self.lower_format_args(e.span, fmt),
ExprKind::OffsetOf(container, fields) => hir::ExprKind::OffsetOf(
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
.arena
.alloc_from_iter(fm.items.iter().map(|x| self.lower_foreign_item_ref(x))),
},
ItemKind::GlobalAsm(asm) => hir::ItemKind::GlobalAsm(self.lower_inline_asm(span, asm)),
ItemKind::GlobalAsm(asm) => {
hir::ItemKind::GlobalAsm(self.lower_inline_asm(span, asm, true))
}
ItemKind::TyAlias(box TyAlias { generics, where_clauses, ty, .. }) => {
// We lower
//
Expand Down
93 changes: 48 additions & 45 deletions compiler/rustc_codegen_ssa/src/mono_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,52 +35,55 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {
MonoItem::GlobalAsm(item_id) => {
let item = cx.tcx().hir().item(item_id);
if let hir::ItemKind::GlobalAsm(ref asm) = item.kind {
let operands: Vec<_> = asm
.operands
.iter()
.map(|(op, op_sp)| match *op {
hir::InlineAsmOperand::Const { ref anon_const } => {
let const_value = cx
.tcx()
.const_eval_poly(anon_const.def_id.to_def_id())
.unwrap_or_else(|_| {
span_bug!(*op_sp, "asm const cannot be resolved")
});
let ty = cx
.tcx()
.typeck_body(anon_const.body)
.node_type(anon_const.hir_id);
let string = common::asm_const_to_str(
cx.tcx(),
*op_sp,
const_value,
cx.layout_of(ty),
);
GlobalAsmOperandRef::Const { string }
}
hir::InlineAsmOperand::SymFn { ref anon_const } => {
let ty = cx
.tcx()
.typeck_body(anon_const.body)
.node_type(anon_const.hir_id);
let instance = match ty.kind() {
&ty::FnDef(def_id, args) => Instance::new(def_id, args),
_ => span_bug!(*op_sp, "asm sym is not a function"),
};
let operands: Vec<_> =
asm.operands
.iter()
.map(|(op, op_sp)| match *op {
hir::InlineAsmOperand::Const { ref anon_const } => {
let const_value = cx
.tcx()
.const_eval_poly(anon_const.def_id.to_def_id())
.unwrap_or_else(|_| {
span_bug!(*op_sp, "asm const cannot be resolved")
});
let ty = cx
.tcx()
.typeck_body(anon_const.body)
.node_type(anon_const.hir_id);
let string = common::asm_const_to_str(
cx.tcx(),
*op_sp,
const_value,
cx.layout_of(ty),
);
GlobalAsmOperandRef::Const { string }
}
hir::InlineAsmOperand::SymFnInGlobal { ref anon_const } => {
let fn_ty =
cx.tcx().type_of(anon_const.def_id).no_bound_vars().expect(
"`sym` in `global_asm!` should not have generics",
);
let instance = match fn_ty.kind() {
&ty::FnDef(def_id, args) => Instance::new(def_id, args),
_ => span_bug!(*op_sp, "asm sym is not a function"),
};

GlobalAsmOperandRef::SymFn { instance }
}
hir::InlineAsmOperand::SymStatic { path: _, def_id } => {
GlobalAsmOperandRef::SymStatic { def_id }
}
hir::InlineAsmOperand::In { .. }
| hir::InlineAsmOperand::Out { .. }
| hir::InlineAsmOperand::InOut { .. }
| hir::InlineAsmOperand::SplitInOut { .. } => {
span_bug!(*op_sp, "invalid operand type for global_asm!")
}
})
.collect();
GlobalAsmOperandRef::SymFn { instance }
}
hir::InlineAsmOperand::SymFnInInline { .. } => {
bug!("should not encounter `SymFnInInline` in `global_asm!`");
}
hir::InlineAsmOperand::SymStatic { path: _, def_id } => {
GlobalAsmOperandRef::SymStatic { def_id }
}
hir::InlineAsmOperand::In { .. }
| hir::InlineAsmOperand::Out { .. }
| hir::InlineAsmOperand::InOut { .. }
| hir::InlineAsmOperand::SplitInOut { .. } => {
span_bug!(*op_sp, "invalid operand type for global_asm!")
}
})
.collect();

cx.codegen_global_asm(asm.template, &operands, asm.options, asm.line_spans);
} else {
Expand Down
10 changes: 8 additions & 2 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2766,9 +2766,12 @@ pub enum InlineAsmOperand<'hir> {
Const {
anon_const: AnonConst,
},
SymFn {
SymFnInGlobal {
anon_const: AnonConst,
},
SymFnInInline {
expr: &'hir Expr<'hir>,
},
SymStatic {
path: QPath<'hir>,
def_id: DefId,
Expand All @@ -2782,7 +2785,10 @@ impl<'hir> InlineAsmOperand<'hir> {
| Self::Out { reg, .. }
| Self::InOut { reg, .. }
| Self::SplitInOut { reg, .. } => Some(reg),
Self::Const { .. } | Self::SymFn { .. } | Self::SymStatic { .. } => None,
Self::Const { .. }
| Self::SymFnInGlobal { .. }
| Self::SymFnInInline { .. }
| Self::SymStatic { .. } => None,
}
}

Expand Down
7 changes: 6 additions & 1 deletion compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1219,7 +1219,12 @@ pub fn walk_inline_asm<'v, V: Visitor<'v>>(visitor: &mut V, asm: &'v InlineAsm<'
}
}
InlineAsmOperand::Const { anon_const, .. }
| InlineAsmOperand::SymFn { anon_const, .. } => visitor.visit_anon_const(anon_const),
| InlineAsmOperand::SymFnInGlobal { anon_const, .. } => {
visitor.visit_anon_const(anon_const)
}
InlineAsmOperand::SymFnInInline { expr } => {
visitor.visit_expr(expr);
}
InlineAsmOperand::SymStatic { path, .. } => visitor.visit_qpath(path, id, *op_sp),
}
}
Expand Down
31 changes: 24 additions & 7 deletions compiler/rustc_hir_analysis/src/check/intrinsicck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,24 @@ use rustc_target::asm::{InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass,
pub struct InlineAsmCtxt<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
get_operand_ty: Box<dyn Fn(&'tcx hir::Expr<'tcx>) -> Ty<'tcx> + 'a>,
get_expr_ty: Box<dyn Fn(&'tcx hir::Expr<'tcx>) -> Ty<'tcx> + 'a>,
}

impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
pub fn new_global_asm(tcx: TyCtxt<'tcx>) -> Self {
InlineAsmCtxt {
tcx,
param_env: ty::ParamEnv::empty(),
get_operand_ty: Box::new(|e| bug!("asm operand in global asm: {e:?}")),
get_expr_ty: Box::new(|e| bug!("asm operand in global asm: {e:?}")),
}
}

pub fn new_in_fn(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
get_operand_ty: impl Fn(&'tcx hir::Expr<'tcx>) -> Ty<'tcx> + 'a,
get_expr_ty: impl Fn(&'tcx hir::Expr<'tcx>) -> Ty<'tcx> + 'a,
) -> Self {
InlineAsmCtxt { tcx, param_env, get_operand_ty: Box::new(get_operand_ty) }
InlineAsmCtxt { tcx, param_env, get_expr_ty: Box::new(get_expr_ty) }
}

// FIXME(compiler-errors): This could use `<$ty as Pointee>::Metadata == ()`
Expand Down Expand Up @@ -124,7 +124,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
tied_input: Option<(&'tcx hir::Expr<'tcx>, Option<InlineAsmType>)>,
target_features: &FxIndexSet<Symbol>,
) -> Option<InlineAsmType> {
let ty = (self.get_operand_ty)(expr);
let ty = (self.get_expr_ty)(expr);
if ty.has_non_region_infer() {
bug!("inference variable in asm operand ty: {:?} {:?}", expr, ty);
}
Expand Down Expand Up @@ -178,7 +178,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
let msg = "incompatible types for asm inout argument";
let mut err = self.tcx.sess.struct_span_err(vec![in_expr.span, expr.span], msg);

let in_expr_ty = (self.get_operand_ty)(in_expr);
let in_expr_ty = (self.get_expr_ty)(in_expr);
err.span_label(in_expr.span, format!("type `{in_expr_ty}`"));
err.span_label(expr.span, format!("type `{ty}`"));
err.note(
Expand Down Expand Up @@ -437,7 +437,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
hir::InlineAsmOperand::Const { .. } | hir::InlineAsmOperand::SymStatic { .. } => {}
// Check that sym actually points to a function. Later passes
// depend on this.
hir::InlineAsmOperand::SymFn { anon_const } => {
hir::InlineAsmOperand::SymFnInGlobal { anon_const } => {
let ty = self.tcx.type_of(anon_const.def_id).instantiate_identity();
match ty.kind() {
ty::Never | ty::Error(_) => {}
Expand All @@ -454,6 +454,23 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
}
};
}
hir::InlineAsmOperand::SymFnInInline { expr } => {
let ty = (self.get_expr_ty)(expr);
match ty.kind() {
ty::Never | ty::Error(_) => {}
ty::FnDef(..) => {}
_ => {
let mut err =
self.tcx.sess.struct_span_err(*op_sp, "invalid `sym` operand");
err.span_label(
expr.span,
format!("is {} `{}`", ty.kind().article(), ty),
);
err.help("`sym` operands must refer to either a function or a static");
err.emit();
}
};
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/collect/generics_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
if asm.operands.iter().any(|(op, _op_sp)| match op {
hir::InlineAsmOperand::Const { anon_const }
| hir::InlineAsmOperand::SymFn { anon_const } => {
| hir::InlineAsmOperand::SymFnInGlobal { anon_const } => {
anon_const.hir_id == hir_id
}
_ => false,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/collect/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
| Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. })
if asm.operands.iter().any(|(op, _op_sp)| match op {
hir::InlineAsmOperand::Const { anon_const }
| hir::InlineAsmOperand::SymFn { anon_const } => anon_const.hir_id == hir_id,
| hir::InlineAsmOperand::SymFnInGlobal { anon_const } => anon_const.hir_id == hir_id,
_ => false,
}) =>
{
Expand Down
7 changes: 6 additions & 1 deletion compiler/rustc_hir_pretty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1309,11 +1309,16 @@ impl<'a> State<'a> {
s.space();
s.print_anon_const(anon_const);
}
hir::InlineAsmOperand::SymFn { ref anon_const } => {
hir::InlineAsmOperand::SymFnInGlobal { ref anon_const } => {
s.word("sym_fn");
s.space();
s.print_anon_const(anon_const);
}
hir::InlineAsmOperand::SymFnInInline { ref expr } => {
s.word("sym_fn");
s.space();
s.print_expr(expr);
}
hir::InlineAsmOperand::SymStatic { ref path, def_id: _ } => {
s.word("sym_static");
s.space();
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_hir_typeck/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3113,10 +3113,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.check_expr_asm_operand(out_expr, false);
}
}
hir::InlineAsmOperand::SymFnInInline { 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::SymFn { .. } => {}
hir::InlineAsmOperand::Const { .. }
| hir::InlineAsmOperand::SymFnInGlobal { .. } => {}
hir::InlineAsmOperand::SymStatic { .. } => {}
}
}
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_hir_typeck/src/expr_use_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,10 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
}
hir::InlineAsmOperand::Out { expr: None, .. }
| hir::InlineAsmOperand::Const { .. }
| hir::InlineAsmOperand::SymFn { .. }
| hir::InlineAsmOperand::SymFnInGlobal { .. }
// `sym`, even in body, operates like a constant,
// so no need to consume or mutate anything here.
| hir::InlineAsmOperand::SymFnInInline { .. }
| hir::InlineAsmOperand::SymStatic { .. } => {}
}
}
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_hir_typeck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,9 @@ fn typeck_with_fallback<'tcx>(
// Inline assembly constants must be integers.
Some(fcx.next_int_var())
}
hir::InlineAsmOperand::SymFn { anon_const } if anon_const.hir_id == id => {
hir::InlineAsmOperand::SymFnInGlobal { anon_const }
if anon_const.hir_id == id =>
{
Some(fcx.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::MiscVariable,
span,
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_middle/src/thir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -566,10 +566,13 @@ pub enum InlineAsmOperand<'tcx> {
value: mir::Const<'tcx>,
span: Span,
},
SymFn {
SymFnInGlobal {
value: mir::Const<'tcx>,
span: Span,
},
SymFnInInline {
expr: ExprId,
},
SymStatic {
def_id: DefId,
},
Expand Down
Loading

0 comments on commit 10e62c3

Please sign in to comment.