Reimplement lowering of sym operands for asm! so that it also works with global_asm!
This commit is contained in:
parent
f9d4d12b6a
commit
dc345d8bff
@ -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,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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!()
|
||||
}
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 ast::ExprKind::Path(qself, path) = &expr.kind else {
|
||||
let err = diag
|
||||
.struct_span_err(expr.span, "argument to `sym` must be a path expression");
|
||||
.struct_span_err(expr.span, "expected a path for argument to `sym`");
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
ast::InlineAsmOperand::Sym { expr }
|
||||
};
|
||||
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
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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) => {
|
||||
|
@ -526,7 +526,8 @@ pub enum InlineAsmOperand<'tcx> {
|
||||
span: Span,
|
||||
},
|
||||
SymFn {
|
||||
expr: ExprId,
|
||||
value: mir::ConstantKind<'tcx>,
|
||||
span: Span,
|
||||
},
|
||||
SymStatic {
|
||||
def_id: DefId,
|
||||
|
@ -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: _ } => {}
|
||||
}
|
||||
}
|
||||
|
@ -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 }
|
||||
}
|
||||
|
@ -462,8 +462,7 @@ fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx>
|
||||
operands: asm
|
||||
.operands
|
||||
.iter()
|
||||
.map(|(op, _op_sp)| {
|
||||
match *op {
|
||||
.map(|(op, _op_sp)| match *op {
|
||||
hir::InlineAsmOperand::In { reg, ref expr } => {
|
||||
InlineAsmOperand::In { reg, expr: self.mirror_expr(expr) }
|
||||
}
|
||||
@ -489,8 +488,7 @@ fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx>
|
||||
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 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,
|
||||
@ -500,57 +498,20 @@ fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx>
|
||||
|
||||
InlineAsmOperand::Const { value, span }
|
||||
}
|
||||
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
|
||||
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 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),
|
||||
}),
|
||||
}
|
||||
}
|
||||
let span = self.tcx.hir().span(anon_const.hir_id);
|
||||
|
||||
Res::Def(DefKind::Static(_), def_id) => {
|
||||
InlineAsmOperand::SymFn { value, span }
|
||||
}
|
||||
hir::InlineAsmOperand::SymStatic { path: _, def_id } => {
|
||||
InlineAsmOperand::SymStatic { def_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),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
options: asm.options,
|
||||
|
@ -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);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
@ -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> {
|
||||
|
@ -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
|
||||
|
@ -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 { .. }
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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> {
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
}) =>
|
||||
| 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.
|
||||
fcx.next_int_var()
|
||||
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(),
|
||||
},
|
||||
|
@ -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,
|
||||
}) =>
|
||||
{
|
||||
|
@ -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 { .. } => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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());
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user