Reimplement lowering of sym operands for asm! so that it also works with global_asm!

This commit is contained in:
Amanieu d'Antras 2022-03-01 00:50:56 +00:00
parent f9d4d12b6a
commit dc345d8bff
28 changed files with 400 additions and 163 deletions

View File

@ -2061,6 +2061,20 @@ pub fn to_string(s: &[Self]) -> String {
}
}
/// Inline assembly symbol operands get their own AST node that is somewhat
/// similar to `AnonConst`.
///
/// The main difference is that we specifically don't assign it `DefId` in
/// `DefCollector`. Instead this is deferred until AST lowering where we
/// lower it to an `AnonConst` (for functions) or a `Path` (for statics)
/// depending on what the path resolves to.
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct InlineAsmSym {
pub id: NodeId,
pub qself: Option<QSelf>,
pub path: Path,
}
/// Inline assembly operand.
///
/// E.g., `out("eax") result` as in `asm!("mov eax, 2", out("eax") result)`.
@ -2090,7 +2104,7 @@ pub enum InlineAsmOperand {
anon_const: AnonConst,
},
Sym {
expr: P<Expr>,
sym: InlineAsmSym,
},
}

View File

@ -280,6 +280,14 @@ fn visit_span(&mut self, _sp: &mut Span) {
fn flat_map_pat_field(&mut self, fp: PatField) -> SmallVec<[PatField; 1]> {
noop_flat_map_pat_field(fp, self)
}
fn visit_inline_asm(&mut self, asm: &mut InlineAsm) {
noop_visit_inline_asm(asm, self)
}
fn visit_inline_asm_sym(&mut self, sym: &mut InlineAsmSym) {
noop_visit_inline_asm_sym(sym, self)
}
}
/// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful
@ -1019,7 +1027,7 @@ pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) {
}
}
ItemKind::ForeignMod(nm) => vis.visit_foreign_mod(nm),
ItemKind::GlobalAsm(asm) => noop_visit_inline_asm(asm, vis),
ItemKind::GlobalAsm(asm) => vis.visit_inline_asm(asm),
ItemKind::TyAlias(box TyAlias {
defaultness, generics, where_clauses, bounds, ty, ..
}) => {
@ -1237,13 +1245,12 @@ pub fn noop_visit_anon_const<T: MutVisitor>(AnonConst { id, value }: &mut AnonCo
vis.visit_expr(value);
}
fn noop_visit_inline_asm<T: MutVisitor>(asm: &mut InlineAsm, vis: &mut T) {
pub fn noop_visit_inline_asm<T: MutVisitor>(asm: &mut InlineAsm, vis: &mut T) {
for (op, _) in &mut asm.operands {
match op {
InlineAsmOperand::In { expr, .. }
| InlineAsmOperand::Out { expr: Some(expr), .. }
| InlineAsmOperand::InOut { expr, .. }
| InlineAsmOperand::Sym { expr, .. } => vis.visit_expr(expr),
| InlineAsmOperand::InOut { expr, .. } => vis.visit_expr(expr),
InlineAsmOperand::Out { expr: None, .. } => {}
InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => {
vis.visit_expr(in_expr);
@ -1251,11 +1258,21 @@ fn noop_visit_inline_asm<T: MutVisitor>(asm: &mut InlineAsm, vis: &mut T) {
vis.visit_expr(out_expr);
}
}
InlineAsmOperand::Const { anon_const, .. } => vis.visit_anon_const(anon_const),
InlineAsmOperand::Const { anon_const } => vis.visit_anon_const(anon_const),
InlineAsmOperand::Sym { sym } => vis.visit_inline_asm_sym(sym),
}
}
}
pub fn noop_visit_inline_asm_sym<T: MutVisitor>(
InlineAsmSym { id, qself, path }: &mut InlineAsmSym,
vis: &mut T,
) {
vis.visit_id(id);
vis.visit_qself(qself);
vis.visit_path(path);
}
pub fn noop_visit_expr<T: MutVisitor>(
Expr { kind, id, span, attrs, tokens }: &mut Expr,
vis: &mut T,
@ -1374,7 +1391,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
ExprKind::Ret(expr) => {
visit_opt(expr, |expr| vis.visit_expr(expr));
}
ExprKind::InlineAsm(asm) => noop_visit_inline_asm(asm, vis),
ExprKind::InlineAsm(asm) => vis.visit_inline_asm(asm),
ExprKind::MacCall(mac) => vis.visit_mac_call(mac),
ExprKind::Struct(se) => {
let StructExpr { qself, path, fields, rest } = se.deref_mut();

View File

@ -214,6 +214,12 @@ fn visit_pat_field(&mut self, fp: &'ast PatField) {
fn visit_crate(&mut self, krate: &'ast Crate) {
walk_crate(self, krate)
}
fn visit_inline_asm(&mut self, asm: &'ast InlineAsm) {
walk_inline_asm(self, asm)
}
fn visit_inline_asm_sym(&mut self, sym: &'ast InlineAsmSym) {
walk_inline_asm_sym(self, sym)
}
}
#[macro_export]
@ -717,13 +723,12 @@ pub fn walk_anon_const<'a, V: Visitor<'a>>(visitor: &mut V, constant: &'a AnonCo
visitor.visit_expr(&constant.value);
}
fn walk_inline_asm<'a, V: Visitor<'a>>(visitor: &mut V, asm: &'a InlineAsm) {
pub fn walk_inline_asm<'a, V: Visitor<'a>>(visitor: &mut V, asm: &'a InlineAsm) {
for (op, _) in &asm.operands {
match op {
InlineAsmOperand::In { expr, .. }
| InlineAsmOperand::Out { expr: Some(expr), .. }
| InlineAsmOperand::InOut { expr, .. }
| InlineAsmOperand::Sym { expr, .. } => visitor.visit_expr(expr),
| InlineAsmOperand::InOut { expr, .. } => visitor.visit_expr(expr),
InlineAsmOperand::Out { expr: None, .. } => {}
InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => {
visitor.visit_expr(in_expr);
@ -732,10 +737,18 @@ fn walk_inline_asm<'a, V: Visitor<'a>>(visitor: &mut V, asm: &'a InlineAsm) {
}
}
InlineAsmOperand::Const { anon_const, .. } => visitor.visit_anon_const(anon_const),
InlineAsmOperand::Sym { sym } => visitor.visit_inline_asm_sym(sym),
}
}
}
pub fn walk_inline_asm_sym<'a, V: Visitor<'a>>(visitor: &mut V, sym: &'a InlineAsmSym) {
if let Some(ref qself) = sym.qself {
visitor.visit_ty(&qself.ty);
}
visitor.visit_path(&sym.path, sym.id);
}
pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
walk_list!(visitor, visit_attribute, expression.attrs.iter());

View File

@ -1,12 +1,17 @@
use crate::{ImplTraitContext, ImplTraitPosition, ParamMode};
use super::LoweringContext;
use rustc_ast::ptr::P;
use rustc_ast::*;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_set::FxHashSet;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::definitions::DefPathData;
use rustc_session::parse::feature_err;
use rustc_span::{sym, Span};
use rustc_span::{sym, ExpnId, Span};
use rustc_target::asm;
use std::collections::hash_map::Entry;
use std::fmt::Write;
@ -188,7 +193,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
anon_const: self.lower_anon_const(anon_const),
}
}
InlineAsmOperand::Sym { ref expr } => {
InlineAsmOperand::Sym { ref sym } => {
if !self.sess.features_untracked().asm_sym {
feature_err(
&self.sess.parse_sess,
@ -198,7 +203,54 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
)
.emit();
}
hir::InlineAsmOperand::Sym { expr: self.lower_expr_mut(expr) }
let static_def_id = self
.resolver
.get_partial_res(sym.id)
.filter(|res| res.unresolved_segments() == 0)
.and_then(|res| {
if let Res::Def(DefKind::Static(_), def_id) = res.base_res() {
Some(def_id)
} else {
None
}
});
if let Some(def_id) = static_def_id {
let path = self.lower_qpath(
sym.id,
&sym.qself,
&sym.path,
ParamMode::Optional,
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
);
hir::InlineAsmOperand::SymStatic { path, def_id }
} else {
// Replace the InlineAsmSym AST node with an
// Expr using the name node id.
let expr = Expr {
id: sym.id,
kind: ExprKind::Path(sym.qself.clone(), sym.path.clone()),
span: *op_sp,
attrs: AttrVec::new(),
tokens: None,
};
// Wrap the expression in an AnonConst.
let parent_def_id = self.current_hir_id_owner;
let node_id = self.resolver.next_node_id();
self.resolver.create_def(
parent_def_id,
node_id,
DefPathData::AnonConst,
ExpnId::root(),
*op_sp,
);
let anon_const = AnonConst { id: node_id, value: P(expr) };
hir::InlineAsmOperand::SymFn {
anon_const: self.lower_anon_const(&anon_const),
}
}
}
};
(op, self.lower_span(*op_sp))
@ -260,7 +312,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
err.span_label(op_sp, "argument");
err.emit();
}
hir::InlineAsmOperand::Sym { .. } => {
hir::InlineAsmOperand::SymFn { .. }
| hir::InlineAsmOperand::SymStatic { .. } => {
let mut err = sess.struct_span_err(
placeholder_span,
"asm template modifiers are not allowed for `sym` arguments",
@ -308,7 +361,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
hir::InlineAsmOperand::InOut { .. }
| hir::InlineAsmOperand::SplitInOut { .. } => (true, true),
hir::InlineAsmOperand::Const { .. } | hir::InlineAsmOperand::Sym { .. } => {
hir::InlineAsmOperand::Const { .. }
| hir::InlineAsmOperand::SymFn { .. }
| hir::InlineAsmOperand::SymStatic { .. } => {
unreachable!()
}
};

View File

@ -1266,10 +1266,14 @@ enum AsmArg<'a> {
s.space();
s.print_expr(&anon_const.value);
}
InlineAsmOperand::Sym { expr } => {
InlineAsmOperand::Sym { sym } => {
s.word("sym");
s.space();
s.print_expr(expr);
if let Some(qself) = &sym.qself {
s.print_qpath(&sym.path, qself, true);
} else {
s.print_path(&sym.path, true, 0);
}
}
}
}

View File

@ -154,17 +154,19 @@ pub fn parse_asm_args<'a>(
} else if p.eat_keyword(kw::Const) {
let anon_const = p.parse_anon_const_expr()?;
ast::InlineAsmOperand::Const { anon_const }
} else if !is_global_asm && p.eat_keyword(sym::sym) {
} else if p.eat_keyword(sym::sym) {
let expr = p.parse_expr()?;
match expr.kind {
ast::ExprKind::Path(..) => {}
_ => {
let err = diag
.struct_span_err(expr.span, "argument to `sym` must be a path expression");
return Err(err);
}
}
ast::InlineAsmOperand::Sym { expr }
let ast::ExprKind::Path(qself, path) = &expr.kind else {
let err = diag
.struct_span_err(expr.span, "expected a path for argument to `sym`");
return Err(err);
};
let sym = ast::InlineAsmSym {
id: ast::DUMMY_NODE_ID,
qself: qself.clone(),
path: path.clone(),
};
ast::InlineAsmOperand::Sym { sym }
} else if allow_templates {
let template = p.parse_expr()?;
// If it can't possibly expand to a string, provide diagnostics here to include other

View File

@ -2425,8 +2425,12 @@ pub enum InlineAsmOperand<'hir> {
Const {
anon_const: AnonConst,
},
Sym {
expr: Expr<'hir>,
SymFn {
anon_const: AnonConst,
},
SymStatic {
path: QPath<'hir>,
def_id: DefId,
},
}
@ -2437,7 +2441,7 @@ pub fn reg(&self) -> Option<InlineAsmRegOrRegClass> {
| Self::Out { reg, .. }
| Self::InOut { reg, .. }
| Self::SplitInOut { reg, .. } => Some(reg),
Self::Const { .. } | Self::Sym { .. } => None,
Self::Const { .. } | Self::SymFn { .. } | Self::SymStatic { .. } => None,
}
}

View File

@ -484,6 +484,9 @@ fn visit_associated_item_kind(&mut self, kind: &'v AssocItemKind) {
fn visit_defaultness(&mut self, defaultness: &'v Defaultness) {
walk_defaultness(self, defaultness);
}
fn visit_inline_asm(&mut self, asm: &'v InlineAsm<'v>, id: HirId) {
walk_inline_asm(self, asm, id);
}
}
pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod<'v>, mod_hir_id: HirId) {
@ -588,7 +591,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) {
}
ItemKind::GlobalAsm(asm) => {
visitor.visit_id(item.hir_id());
walk_inline_asm(visitor, asm);
visitor.visit_inline_asm(asm, item.hir_id());
}
ItemKind::TyAlias(ref ty, ref generics) => {
visitor.visit_id(item.hir_id());
@ -648,12 +651,12 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) {
}
}
fn walk_inline_asm<'v, V: Visitor<'v>>(visitor: &mut V, asm: &'v InlineAsm<'v>) {
for (op, _op_sp) in asm.operands {
pub fn walk_inline_asm<'v, V: Visitor<'v>>(visitor: &mut V, asm: &'v InlineAsm<'v>, id: HirId) {
for (op, op_sp) in asm.operands {
match op {
InlineAsmOperand::In { expr, .. }
| InlineAsmOperand::InOut { expr, .. }
| InlineAsmOperand::Sym { expr, .. } => visitor.visit_expr(expr),
InlineAsmOperand::In { expr, .. } | InlineAsmOperand::InOut { expr, .. } => {
visitor.visit_expr(expr)
}
InlineAsmOperand::Out { expr, .. } => {
if let Some(expr) = expr {
visitor.visit_expr(expr);
@ -665,7 +668,9 @@ fn walk_inline_asm<'v, V: Visitor<'v>>(visitor: &mut V, asm: &'v InlineAsm<'v>)
visitor.visit_expr(out_expr);
}
}
InlineAsmOperand::Const { anon_const } => visitor.visit_anon_const(anon_const),
InlineAsmOperand::Const { anon_const, .. }
| InlineAsmOperand::SymFn { anon_const, .. } => visitor.visit_anon_const(anon_const),
InlineAsmOperand::SymStatic { path, .. } => visitor.visit_qpath(path, id, *op_sp),
}
}
}
@ -1221,7 +1226,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
walk_list!(visitor, visit_expr, optional_expression);
}
ExprKind::InlineAsm(ref asm) => {
walk_inline_asm(visitor, asm);
visitor.visit_inline_asm(asm, expression.hir_id);
}
ExprKind::Yield(ref subexpression, _) => {
visitor.visit_expr(subexpression);

View File

@ -1352,10 +1352,15 @@ enum AsmArg<'a> {
s.space();
s.print_anon_const(anon_const);
}
hir::InlineAsmOperand::Sym { expr } => {
s.word("sym");
hir::InlineAsmOperand::SymFn { anon_const } => {
s.word("sym_fn");
s.space();
s.print_expr(expr);
s.print_anon_const(anon_const);
}
hir::InlineAsmOperand::SymStatic { path, def_id: _ } => {
s.word("sym_static");
s.space();
s.print_qpath(path, true);
}
},
AsmArg::Options(opts) => {

View File

@ -526,7 +526,8 @@ pub enum InlineAsmOperand<'tcx> {
span: Span,
},
SymFn {
expr: ExprId,
value: mir::ConstantKind<'tcx>,
span: Span,
},
SymStatic {
def_id: DefId,

View File

@ -138,8 +138,7 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp
match op {
In { expr, reg: _ }
| Out { expr: Some(expr), reg: _, late: _ }
| InOut { expr, reg: _, late: _ }
| SymFn { expr } => visitor.visit_expr(&visitor.thir()[*expr]),
| InOut { expr, reg: _, late: _ } => visitor.visit_expr(&visitor.thir()[*expr]),
SplitInOut { in_expr, out_expr, reg: _, late: _ } => {
visitor.visit_expr(&visitor.thir()[*in_expr]);
if let Some(out_expr) = out_expr {
@ -148,6 +147,7 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp
}
Out { expr: None, reg: _, late: _ }
| Const { value: _, span: _ }
| SymFn { value: _, span: _ }
| SymStatic { def_id: _ } => {}
}
}

View File

@ -430,9 +430,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}),
}
}
thir::InlineAsmOperand::SymFn { expr } => mir::InlineAsmOperand::SymFn {
value: Box::new(this.as_constant(&this.thir[expr])),
},
thir::InlineAsmOperand::SymFn { value, span } => {
mir::InlineAsmOperand::SymFn {
value: Box::new(Constant {
span,
user_ty: None,
literal: value.into(),
}),
}
}
thir::InlineAsmOperand::SymStatic { def_id } => {
mir::InlineAsmOperand::SymStatic { def_id }
}

View File

@ -462,94 +462,55 @@ fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx>
operands: asm
.operands
.iter()
.map(|(op, _op_sp)| {
match *op {
hir::InlineAsmOperand::In { reg, ref expr } => {
InlineAsmOperand::In { reg, expr: self.mirror_expr(expr) }
}
hir::InlineAsmOperand::Out { reg, late, ref expr } => {
InlineAsmOperand::Out {
reg,
late,
expr: expr.as_ref().map(|expr| self.mirror_expr(expr)),
}
}
hir::InlineAsmOperand::InOut { reg, late, ref expr } => {
InlineAsmOperand::InOut { reg, late, expr: self.mirror_expr(expr) }
}
hir::InlineAsmOperand::SplitInOut {
.map(|(op, _op_sp)| match *op {
hir::InlineAsmOperand::In { reg, ref expr } => {
InlineAsmOperand::In { reg, expr: self.mirror_expr(expr) }
}
hir::InlineAsmOperand::Out { reg, late, ref expr } => {
InlineAsmOperand::Out {
reg,
late,
ref in_expr,
ref out_expr,
} => InlineAsmOperand::SplitInOut {
reg,
late,
in_expr: self.mirror_expr(in_expr),
out_expr: out_expr.as_ref().map(|expr| self.mirror_expr(expr)),
},
hir::InlineAsmOperand::Const { ref anon_const } => {
let anon_const_def_id =
self.tcx.hir().local_def_id(anon_const.hir_id);
let value = mir::ConstantKind::from_anon_const(
self.tcx,
anon_const_def_id,
self.param_env,
);
let span = self.tcx.hir().span(anon_const.hir_id);
InlineAsmOperand::Const { value, span }
expr: expr.as_ref().map(|expr| self.mirror_expr(expr)),
}
hir::InlineAsmOperand::Sym { ref expr } => {
let hir::ExprKind::Path(ref qpath) = expr.kind else {
span_bug!(
expr.span,
"asm `sym` operand should be a path, found {:?}",
expr.kind
);
};
let temp_lifetime =
self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
let res = self.typeck_results().qpath_res(qpath, expr.hir_id);
let ty;
match res {
Res::Def(DefKind::Fn, _) | Res::Def(DefKind::AssocFn, _) => {
ty = self.typeck_results().node_type(expr.hir_id);
let user_ty =
self.user_substs_applied_to_res(expr.hir_id, res);
InlineAsmOperand::SymFn {
expr: self.thir.exprs.push(Expr {
ty,
temp_lifetime,
span: expr.span,
kind: ExprKind::zero_sized_literal(user_ty),
}),
}
}
}
hir::InlineAsmOperand::InOut { reg, late, ref expr } => {
InlineAsmOperand::InOut { reg, late, expr: self.mirror_expr(expr) }
}
hir::InlineAsmOperand::SplitInOut {
reg,
late,
ref in_expr,
ref out_expr,
} => InlineAsmOperand::SplitInOut {
reg,
late,
in_expr: self.mirror_expr(in_expr),
out_expr: out_expr.as_ref().map(|expr| self.mirror_expr(expr)),
},
hir::InlineAsmOperand::Const { ref anon_const } => {
let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
let value = mir::ConstantKind::from_anon_const(
self.tcx,
anon_const_def_id,
self.param_env,
);
let span = self.tcx.hir().span(anon_const.hir_id);
Res::Def(DefKind::Static(_), def_id) => {
InlineAsmOperand::SymStatic { def_id }
}
InlineAsmOperand::Const { value, span }
}
hir::InlineAsmOperand::SymFn { ref anon_const } => {
let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
let value = mir::ConstantKind::from_anon_const(
self.tcx,
anon_const_def_id,
self.param_env,
);
let span = self.tcx.hir().span(anon_const.hir_id);
_ => {
self.tcx.sess.span_err(
expr.span,
"asm `sym` operand must point to a fn or static",
);
// Not a real fn, but we're not reaching codegen anyways...
ty = self.tcx.ty_error();
InlineAsmOperand::SymFn {
expr: self.thir.exprs.push(Expr {
ty,
temp_lifetime,
span: expr.span,
kind: ExprKind::zero_sized_literal(None),
}),
}
}
}
}
InlineAsmOperand::SymFn { value, span }
}
hir::InlineAsmOperand::SymStatic { path: _, def_id } => {
InlineAsmOperand::SymStatic { def_id }
}
})
.collect(),

View File

@ -537,6 +537,10 @@ fn visit_item(&mut self, item: &hir::Item<'_>) {
.insert(self.tcx.hir().local_def_id(ctor_hir_id), item.def_id);
}
}
hir::ItemKind::GlobalAsm(_) => {
// global_asm! is always live.
self.worklist.push(item.def_id);
}
_ => (),
}
}

View File

@ -1,3 +1,4 @@
use hir::intravisit::walk_inline_asm;
use rustc_ast::InlineAsmTemplatePiece;
use rustc_data_structures::stable_set::FxHashSet;
use rustc_errors::struct_span_err;
@ -483,7 +484,10 @@ fn check_asm(&self, asm: &hir::InlineAsm<'tcx>, hir_id: hir::HirId) {
);
}
}
hir::InlineAsmOperand::Const { .. } | hir::InlineAsmOperand::Sym { .. } => {}
// These are checked in ItemVisitor.
hir::InlineAsmOperand::Const { .. }
| hir::InlineAsmOperand::SymFn { .. }
| hir::InlineAsmOperand::SymStatic { .. } => {}
}
}
}
@ -498,6 +502,42 @@ fn visit_nested_body(&mut self, body_id: hir::BodyId) {
ExprVisitor { tcx: self.tcx, param_env, typeck_results }.visit_body(body);
self.visit_body(body);
}
fn visit_inline_asm(&mut self, asm: &'tcx hir::InlineAsm<'tcx>, id: hir::HirId) {
for (op, op_sp) in asm.operands.iter() {
match *op {
// These are checked in ExprVisitor.
hir::InlineAsmOperand::In { .. }
| hir::InlineAsmOperand::Out { .. }
| hir::InlineAsmOperand::InOut { .. }
| hir::InlineAsmOperand::SplitInOut { .. } => {}
// No special checking is needed for these:
// - Typeck has checked that Const operands are integers.
// - AST lowering guarantees that SymStatic points to a static.
hir::InlineAsmOperand::Const { .. } | hir::InlineAsmOperand::SymStatic { .. } => {}
// Check that sym actually points to a function. Later passes
// depend on this.
hir::InlineAsmOperand::SymFn { anon_const } => {
let ty = self.tcx.typeck_body(anon_const.body).node_type(anon_const.hir_id);
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(
self.tcx.hir().span(anon_const.body.hir_id),
&format!("is {} `{}`", ty.kind().article(), ty),
);
err.help("`sym` operands must refer to either a function or a static");
err.emit();
}
};
}
}
}
walk_inline_asm(self, asm, id);
}
}
impl<'tcx> Visitor<'tcx> for ExprVisitor<'tcx> {

View File

@ -1043,7 +1043,8 @@ fn propagate_through_expr(&mut self, expr: &Expr<'_>, succ: LiveNode) -> LiveNod
match op {
hir::InlineAsmOperand::In { .. }
| hir::InlineAsmOperand::Const { .. }
| hir::InlineAsmOperand::Sym { .. } => {}
| hir::InlineAsmOperand::SymFn { .. }
| hir::InlineAsmOperand::SymStatic { .. } => {}
hir::InlineAsmOperand::Out { expr, .. } => {
if let Some(expr) = expr {
succ = self.write_place(expr, succ, ACC_WRITE);
@ -1064,8 +1065,7 @@ fn propagate_through_expr(&mut self, expr: &Expr<'_>, succ: LiveNode) -> LiveNod
let mut succ = succ;
for (op, _op_sp) in asm.operands.iter().rev() {
match op {
hir::InlineAsmOperand::In { expr, .. }
| hir::InlineAsmOperand::Sym { expr, .. } => {
hir::InlineAsmOperand::In { expr, .. } => {
succ = self.propagate_through_expr(expr, succ)
}
hir::InlineAsmOperand::Out { expr, .. } => {
@ -1082,7 +1082,9 @@ fn propagate_through_expr(&mut self, expr: &Expr<'_>, succ: LiveNode) -> LiveNod
}
succ = self.propagate_through_expr(in_expr, succ);
}
hir::InlineAsmOperand::Const { .. } => {}
hir::InlineAsmOperand::Const { .. }
| hir::InlineAsmOperand::SymFn { .. }
| hir::InlineAsmOperand::SymStatic { .. } => {}
}
}
succ

View File

@ -252,7 +252,9 @@ fn check_inline_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>, span: Span) {
.operands
.iter()
.filter_map(|&(ref op, op_sp)| match op {
InlineAsmOperand::Const { .. } | InlineAsmOperand::Sym { .. } => None,
InlineAsmOperand::Const { .. }
| InlineAsmOperand::SymFn { .. }
| InlineAsmOperand::SymStatic { .. } => None,
InlineAsmOperand::In { .. }
| InlineAsmOperand::Out { .. }
| InlineAsmOperand::InOut { .. }

View File

@ -1012,6 +1012,12 @@ fn add_suggestion_for_duplicate_nested_use(
err.span_label(trait_item_span, "item in trait");
err
}
ResolutionError::InvalidAsmSym => {
let mut err = self.session.struct_span_err(span, "invalid `sym` operand");
err.span_label(span, &format!("is a local variable"));
err.help("`sym` operands must refer to either a function or a static");
err
}
}
}

View File

@ -1182,6 +1182,12 @@ fn validate_res_from_ribs(
}
return Res::Err;
}
InlineAsmSymRibKind => {
if let Some(span) = finalize {
self.report_error(span, InvalidAsmSym);
}
return Res::Err;
}
}
}
if let Some((span, res_err)) = res_err {
@ -1242,6 +1248,22 @@ fn validate_res_from_ribs(
}
return Res::Err;
}
InlineAsmSymRibKind => {
let features = self.session.features_untracked();
if !features.generic_const_exprs {
if let Some(span) = finalize {
self.report_error(
span,
ResolutionError::ParamInNonTrivialAnonConst {
name: rib_ident.name,
is_type: true,
},
);
}
return Res::Err;
}
continue;
}
};
if let Some(span) = finalize {
@ -1306,6 +1328,22 @@ fn validate_res_from_ribs(
}
return Res::Err;
}
InlineAsmSymRibKind => {
let features = self.session.features_untracked();
if !features.generic_const_exprs {
if let Some(span) = finalize {
self.report_error(
span,
ResolutionError::ParamInNonTrivialAnonConst {
name: rib_ident.name,
is_type: false,
},
);
}
return Res::Err;
}
continue;
}
};
// This was an attempt to use a const parameter outside its scope.

View File

@ -140,6 +140,10 @@ enum PatBoundCtx {
/// We are inside of the type of a const parameter. Can't refer to any
/// parameters.
ConstParamTyRibKind,
/// We are inside a `sym` inline assembly operand. Can only refer to
/// globals.
InlineAsmSymRibKind,
}
impl RibKind<'_> {
@ -153,7 +157,8 @@ impl RibKind<'_> {
| ConstantItemRibKind(..)
| ModuleRibKind(_)
| MacroDefinition(_)
| ConstParamTyRibKind => false,
| ConstParamTyRibKind
| InlineAsmSymRibKind => false,
AssocItemRibKind | ItemRibKind(_) | ForwardGenericParamBanRibKind => true,
}
}
@ -722,6 +727,23 @@ fn visit_where_predicate(&mut self, p: &'ast WherePredicate) {
visit::walk_where_predicate(self, p);
self.diagnostic_metadata.current_where_predicate = previous_value;
}
fn visit_inline_asm_sym(&mut self, sym: &'ast InlineAsmSym) {
// This is similar to the code for AnonConst.
self.with_rib(ValueNS, InlineAsmSymRibKind, |this| {
this.with_rib(TypeNS, InlineAsmSymRibKind, |this| {
this.with_label_rib(InlineAsmSymRibKind, |this| {
this.smart_resolve_path(
sym.id,
sym.qself.as_ref(),
&sym.path,
PathSource::Expr(None),
);
visit::walk_inline_asm_sym(this, sym);
});
})
});
}
}
impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
@ -909,7 +931,8 @@ fn is_label_valid_from_rib(&self, rib_index: usize) -> bool {
| ConstantItemRibKind(..)
| ModuleRibKind(..)
| ForwardGenericParamBanRibKind
| ConstParamTyRibKind => {
| ConstParamTyRibKind
| InlineAsmSymRibKind => {
return false;
}
}

View File

@ -260,6 +260,8 @@ enum ResolutionError<'a> {
trait_item_span: Span,
code: rustc_errors::DiagnosticId,
},
/// Inline asm `sym` operand must refer to a `fn` or `static`.
InvalidAsmSym,
}
enum VisResolutionError<'a> {

View File

@ -2535,12 +2535,11 @@ fn check_expr_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>) -> Ty<'tcx> {
self.check_expr_asm_operand(out_expr, false);
}
}
hir::InlineAsmOperand::Const { anon_const } => {
hir::InlineAsmOperand::Const { anon_const }
| hir::InlineAsmOperand::SymFn { anon_const } => {
self.to_const(anon_const);
}
hir::InlineAsmOperand::Sym { expr } => {
self.check_expr(expr);
}
hir::InlineAsmOperand::SymStatic { .. } => {}
}
}
if asm.options.contains(ast::InlineAsmOptions::NORETURN) {

View File

@ -427,16 +427,29 @@ fn typeck_with_fallback<'tcx>(
span,
}),
Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), .. })
| Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), .. })
if asm.operands.iter().any(|(op, _op_sp)| match op {
hir::InlineAsmOperand::Const { anon_const } => {
anon_const.hir_id == id
}
_ => false,
}) =>
{
// Inline assembly constants must be integers.
fcx.next_int_var()
| Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), .. }) => {
let operand_ty = asm
.operands
.iter()
.filter_map(|(op, _op_sp)| match op {
hir::InlineAsmOperand::Const { anon_const }
if anon_const.hir_id == id =>
{
// Inline assembly constants must be integers.
Some(fcx.next_int_var())
}
hir::InlineAsmOperand::SymFn { anon_const }
if anon_const.hir_id == id =>
{
Some(fcx.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::MiscVariable,
span,
}))
}
_ => None,
})
.next();
operand_ty.unwrap_or_else(fallback)
}
_ => fallback(),
},

View File

@ -450,7 +450,8 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
| Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. })
if asm.operands.iter().any(|(op, _op_sp)| match op {
hir::InlineAsmOperand::Const { anon_const } => anon_const.hir_id == hir_id,
hir::InlineAsmOperand::Const { anon_const }
| hir::InlineAsmOperand::SymFn { anon_const } => anon_const.hir_id == hir_id,
_ => false,
}) =>
{

View File

@ -358,8 +358,7 @@ pub fn walk_expr(&mut self, expr: &hir::Expr<'_>) {
hir::ExprKind::InlineAsm(asm) => {
for (op, _op_sp) in asm.operands {
match op {
hir::InlineAsmOperand::In { expr, .. }
| hir::InlineAsmOperand::Sym { expr, .. } => self.consume_expr(expr),
hir::InlineAsmOperand::In { expr, .. } => self.consume_expr(expr),
hir::InlineAsmOperand::Out { expr: Some(expr), .. }
| hir::InlineAsmOperand::InOut { expr, .. } => {
self.mutate_expr(expr);
@ -371,7 +370,9 @@ pub fn walk_expr(&mut self, expr: &hir::Expr<'_>) {
}
}
hir::InlineAsmOperand::Out { expr: None, .. }
| hir::InlineAsmOperand::Const { .. } => {}
| hir::InlineAsmOperand::Const { .. }
| hir::InlineAsmOperand::SymFn { .. }
| hir::InlineAsmOperand::SymStatic { .. } => {}
}
}
}

View File

@ -169,13 +169,14 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
.iter()
.map(|(o, _)| match o {
InlineAsmOperand::In { expr, .. }
| InlineAsmOperand::InOut { expr, .. }
| InlineAsmOperand::Sym { expr } => never_loop_expr(expr, main_loop_id),
| InlineAsmOperand::InOut { expr, .. } => never_loop_expr(expr, main_loop_id),
InlineAsmOperand::Out { expr, .. } => never_loop_expr_all(&mut expr.iter(), main_loop_id),
InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => {
never_loop_expr_all(&mut once(in_expr).chain(out_expr.iter()), main_loop_id)
},
InlineAsmOperand::Const { .. } => NeverLoopResult::Otherwise,
InlineAsmOperand::Const { .. }
| InlineAsmOperand::SymFn { .. }
| InlineAsmOperand::SymStatic { .. } => NeverLoopResult::Otherwise,
})
.fold(NeverLoopResult::Otherwise, combine_both),
ExprKind::Struct(_, _, None)

View File

@ -281,8 +281,9 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) {
for (op, _op_sp) in asm.operands {
match op {
hir::InlineAsmOperand::In { expr, .. }
| hir::InlineAsmOperand::InOut { expr, .. }
| hir::InlineAsmOperand::Sym { expr } => print_expr(cx, expr, indent + 1),
| hir::InlineAsmOperand::InOut { expr, .. } => {
print_expr(cx, expr, indent + 1);
}
hir::InlineAsmOperand::Out { expr, .. } => {
if let Some(expr) = expr {
print_expr(cx, expr, indent + 1);
@ -294,10 +295,26 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) {
print_expr(cx, out_expr, indent + 1);
}
},
hir::InlineAsmOperand::Const { anon_const } => {
hir::InlineAsmOperand::Const { anon_const }
| hir::InlineAsmOperand::SymFn { anon_const } => {
println!("{}anon_const:", ind);
print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1);
},
hir::InlineAsmOperand::SymStatic { path, .. } => {
match path {
hir::QPath::Resolved(ref ty, path) => {
println!("{}Resolved Path, {:?}", ind, ty);
println!("{}path: {:?}", ind, path);
},
hir::QPath::TypeRelative(ty, seg) => {
println!("{}Relative Path, {:?}", ind, ty);
println!("{}seg: {:?}", ind, seg);
},
hir::QPath::LangItem(lang_item, ..) => {
println!("{}Lang Item Path, {:?}", ind, lang_item.name());
},
}
}
}
}
},

View File

@ -675,7 +675,8 @@ pub fn hash_expr(&mut self, e: &Expr<'_>) {
}
},
InlineAsmOperand::Const { anon_const } => self.hash_body(anon_const.body),
InlineAsmOperand::Sym { expr } => self.hash_expr(expr),
InlineAsmOperand::SymFn { anon_const } => self.hash_body(anon_const.body),
InlineAsmOperand::SymStatic { path, def_id: _ } => self.hash_qpath(path),
}
}
},