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 all commits
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
13 changes: 12 additions & 1 deletion compiler/rustc_borrowck/src/universal_regions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::Diagnostic;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::lang_items::LangItem;
use rustc_hir::BodyOwnerKind;
Expand Down Expand Up @@ -711,7 +712,17 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
// For a constant body, there are no inputs, and one
// "output" (the type of the constant).
assert_eq!(self.mir_def.to_def_id(), def_id);
let ty = tcx.type_of(self.mir_def).instantiate_identity();
let mut ty = tcx.type_of(self.mir_def).instantiate_identity();
// `SymFn` in global asm may only reference `'static`, but those
// regions are erased as part of computing the type of the anon
// const. Put them back, since the `UniversalRegionsBuilder` is
// not setup to handle erased regions.
if tcx.def_kind(tcx.parent(def_id)) == DefKind::GlobalAsm {
ty = tcx.fold_regions(ty, |re, _| {
assert_eq!(re, tcx.lifetimes.re_erased);
tcx.lifetimes.re_static
});
}
let ty = indices.fold_to_region_vids(tcx, ty);
ty::Binder::dummy(tcx.mk_type_list(&[ty]))
}
Expand Down
10 changes: 8 additions & 2 deletions compiler/rustc_codegen_cranelift/src/global_asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,11 @@ pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String,
);
global_asm.push_str(&string);
}
InlineAsmOperand::SymFn { anon_const } => {
let ty = tcx.typeck_body(anon_const.body).node_type(anon_const.hir_id);
InlineAsmOperand::SymFnInGlobal { anon_const } => {
let ty = tcx
.type_of(anon_const.def_id)
.no_bound_vars()
.expect("`sym` in `global_asm!` should not have generics");
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"),
Expand All @@ -50,6 +53,9 @@ pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String,
// current codegen unit
global_asm.push_str(symbol.name);
}
InlineAsmOperand::SymFnInInline { .. } => {
bug!("should not encounter `SymFnInInline` in `global_asm!`");
}
InlineAsmOperand::SymStatic { path: _, def_id } => {
let instance = Instance::mono(tcx, def_id).polymorphize(tcx);
let symbol = tcx.symbol_name(instance);
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
Loading
Loading