Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle lifetimes correctly in sym in inline and global asm #116087

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 } => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not reachable here since this is only reached for ExprKind::InlineAsm, not `ItemKind::GlobalAsm``.

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