Auto merge of #94468 - Amanieu:global_asm_sym, r=nagisa
Implement sym operands for global_asm! Tracking issue: #93333 This PR is pretty much a complete rewrite of `sym` operand support for inline assembly so that the same implementation can be shared by `asm!` and `global_asm!`. The main changes are: - At the AST level, `sym` is represented as a special `InlineAsmSym` AST node containing a path instead of an `Expr`. - At the HIR level, `sym` is split into `SymStatic` and `SymFn` depending on whether the path resolves to a static during AST lowering (defaults to `SynFn` if `get_early_res` fails). - `SymFn` is just an `AnonConst`. It runs through typeck and we just collect the resulting type at the end. An error is emitted if the type is not a `FnDef`. - `SymStatic` directly holds a path and the `DefId` of the `static` that it is pointing to. - The representation at the MIR level is mostly unchanged. There is a minor change to THIR where `SymFn` is a constant instead of an expression. - At the codegen level we need to apply the target's symbol mangling to the result of `tcx.symbol_name()` depending on the target. This is done by calling the LLVM name mangler, which handles all of the details. - On Mach-O, all symbols have a leading underscore. - On x86 Windows, different mangling is used for cdecl, stdcall, fastcall and vectorcall. - No mangling is needed on other platforms. r? `@nagisa` cc `@eddyb`
This commit is contained in:
commit
080d5452e1
50 changed files with 654 additions and 245 deletions
|
@ -2061,6 +2061,20 @@ impl InlineAsmTemplatePiece {
|
|||
}
|
||||
}
|
||||
|
||||
/// 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 @@ pub trait MutVisitor: Sized {
|
|||
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 @@ pub trait Visitor<'ast>: Sized {
|
|||
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 @@ impl<'a> State<'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 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
|
||||
|
|
|
@ -258,9 +258,14 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
}
|
||||
|
||||
InlineAsmOperandRef::SymFn { instance } => {
|
||||
// TODO(@Amanieu): Additional mangling is needed on
|
||||
// some targets to add a leading underscore (Mach-O)
|
||||
// or byte count suffixes (x86 Windows).
|
||||
constants_len += self.tcx.symbol_name(instance).name.len();
|
||||
}
|
||||
InlineAsmOperandRef::SymStatic { def_id } => {
|
||||
// TODO(@Amanieu): Additional mangling is needed on
|
||||
// some targets to add a leading underscore (Mach-O).
|
||||
constants_len += self.tcx.symbol_name(Instance::mono(self.tcx, def_id)).name.len();
|
||||
}
|
||||
}
|
||||
|
@ -412,13 +417,16 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
}
|
||||
|
||||
InlineAsmOperandRef::SymFn { instance } => {
|
||||
// TODO(@Amanieu): Additional mangling is needed on
|
||||
// some targets to add a leading underscore (Mach-O)
|
||||
// or byte count suffixes (x86 Windows).
|
||||
let name = self.tcx.symbol_name(instance).name;
|
||||
template_str.push_str(name);
|
||||
}
|
||||
|
||||
InlineAsmOperandRef::SymStatic { def_id } => {
|
||||
// TODO(@Commeownist): This may not be sufficient for all kinds of statics.
|
||||
// Some statics may need the `@plt` suffix, like thread-local vars.
|
||||
// TODO(@Amanieu): Additional mangling is needed on
|
||||
// some targets to add a leading underscore (Mach-O).
|
||||
let instance = Instance::mono(self.tcx, def_id);
|
||||
let name = self.tcx.symbol_name(instance).name;
|
||||
template_str.push_str(name);
|
||||
|
@ -656,8 +664,8 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl
|
|||
}
|
||||
}
|
||||
|
||||
impl<'gcc, 'tcx> AsmMethods for CodegenCx<'gcc, 'tcx> {
|
||||
fn codegen_global_asm(&self, template: &[InlineAsmTemplatePiece], operands: &[GlobalAsmOperandRef], options: InlineAsmOptions, _line_spans: &[Span]) {
|
||||
impl<'gcc, 'tcx> AsmMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
||||
fn codegen_global_asm(&self, template: &[InlineAsmTemplatePiece], operands: &[GlobalAsmOperandRef<'tcx>], options: InlineAsmOptions, _line_spans: &[Span]) {
|
||||
let asm_arch = self.tcx.sess.asm_arch.unwrap();
|
||||
|
||||
// Default to Intel syntax on x86
|
||||
|
@ -690,6 +698,22 @@ impl<'gcc, 'tcx> AsmMethods for CodegenCx<'gcc, 'tcx> {
|
|||
// here unlike normal inline assembly.
|
||||
template_str.push_str(string);
|
||||
}
|
||||
|
||||
GlobalAsmOperandRef::SymFn { instance } => {
|
||||
// TODO(@Amanieu): Additional mangling is needed on
|
||||
// some targets to add a leading underscore (Mach-O)
|
||||
// or byte count suffixes (x86 Windows).
|
||||
let name = self.tcx.symbol_name(instance).name;
|
||||
template_str.push_str(name);
|
||||
}
|
||||
|
||||
GlobalAsmOperandRef::SymStatic { def_id } => {
|
||||
// TODO(@Amanieu): Additional mangling is needed on
|
||||
// some targets to add a leading underscore (Mach-O).
|
||||
let instance = Instance::mono(self.tcx, def_id);
|
||||
let name = self.tcx.symbol_name(instance).name;
|
||||
template_str.push_str(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -312,11 +312,11 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl AsmMethods for CodegenCx<'_, '_> {
|
||||
impl<'tcx> AsmMethods<'tcx> for CodegenCx<'_, 'tcx> {
|
||||
fn codegen_global_asm(
|
||||
&self,
|
||||
template: &[InlineAsmTemplatePiece],
|
||||
operands: &[GlobalAsmOperandRef],
|
||||
operands: &[GlobalAsmOperandRef<'tcx>],
|
||||
options: InlineAsmOptions,
|
||||
_line_spans: &[Span],
|
||||
) {
|
||||
|
@ -342,6 +342,29 @@ impl AsmMethods for CodegenCx<'_, '_> {
|
|||
// here unlike normal inline assembly.
|
||||
template_str.push_str(string);
|
||||
}
|
||||
GlobalAsmOperandRef::SymFn { instance } => {
|
||||
let llval = self.get_fn(instance);
|
||||
self.add_compiler_used_global(llval);
|
||||
let symbol = llvm::build_string(|s| unsafe {
|
||||
llvm::LLVMRustGetMangledName(llval, s);
|
||||
})
|
||||
.expect("symbol is not valid UTF-8");
|
||||
template_str.push_str(&symbol);
|
||||
}
|
||||
GlobalAsmOperandRef::SymStatic { def_id } => {
|
||||
let llval = self
|
||||
.renamed_statics
|
||||
.borrow()
|
||||
.get(&def_id)
|
||||
.copied()
|
||||
.unwrap_or_else(|| self.get_static(def_id));
|
||||
self.add_compiler_used_global(llval);
|
||||
let symbol = llvm::build_string(|s| unsafe {
|
||||
llvm::LLVMRustGetMangledName(llval, s);
|
||||
})
|
||||
.expect("symbol is not valid UTF-8");
|
||||
template_str.push_str(&symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,15 +99,6 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol) -> (ModuleCodegen
|
|||
attributes::apply_to_llfn(entry, llvm::AttributePlace::Function, &attrs);
|
||||
}
|
||||
|
||||
// Run replace-all-uses-with for statics that need it
|
||||
for &(old_g, new_g) in cx.statics_to_rauw().borrow().iter() {
|
||||
unsafe {
|
||||
let bitcast = llvm::LLVMConstPointerCast(new_g, cx.val_ty(old_g));
|
||||
llvm::LLVMReplaceAllUsesWith(old_g, bitcast);
|
||||
llvm::LLVMDeleteGlobal(old_g);
|
||||
}
|
||||
}
|
||||
|
||||
// Finalize code coverage by injecting the coverage map. Note, the coverage map will
|
||||
// also be added to the `llvm.compiler.used` variable, created next.
|
||||
if cx.sess().instrument_coverage() {
|
||||
|
@ -122,6 +113,16 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol) -> (ModuleCodegen
|
|||
cx.create_compiler_used_variable()
|
||||
}
|
||||
|
||||
// Run replace-all-uses-with for statics that need it. This must
|
||||
// happen after the llvm.used variables are created.
|
||||
for &(old_g, new_g) in cx.statics_to_rauw().borrow().iter() {
|
||||
unsafe {
|
||||
let bitcast = llvm::LLVMConstPointerCast(new_g, cx.val_ty(old_g));
|
||||
llvm::LLVMReplaceAllUsesWith(old_g, bitcast);
|
||||
llvm::LLVMDeleteGlobal(old_g);
|
||||
}
|
||||
}
|
||||
|
||||
// Finalize debuginfo
|
||||
if cx.sess().opts.debuginfo != DebugInfo::None {
|
||||
cx.debuginfo_finalize();
|
||||
|
|
|
@ -412,6 +412,13 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> {
|
|||
llvm::LLVMRustSetLinkage(new_g, linkage);
|
||||
llvm::LLVMRustSetVisibility(new_g, visibility);
|
||||
|
||||
// The old global has had its name removed but is returned by
|
||||
// get_static since it is in the instance cache. Provide an
|
||||
// alternative lookup that points to the new global so that
|
||||
// global_asm! can compute the correct mangled symbol name
|
||||
// for the global.
|
||||
self.renamed_statics.borrow_mut().insert(def_id, new_g);
|
||||
|
||||
// To avoid breaking any invariants, we leave around the old
|
||||
// global for the moment; we'll replace all references to it
|
||||
// with the new global later. (See base::codegen_backend.)
|
||||
|
|
|
@ -14,6 +14,7 @@ use rustc_codegen_ssa::traits::*;
|
|||
use rustc_data_structures::base_n;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::small_c_str::SmallCStr;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::mir::mono::CodegenUnit;
|
||||
use rustc_middle::ty::layout::{
|
||||
FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, LayoutError, LayoutOfHelpers,
|
||||
|
@ -105,6 +106,12 @@ pub struct CodegenCx<'ll, 'tcx> {
|
|||
|
||||
/// A counter that is used for generating local symbol names
|
||||
local_gen_sym_counter: Cell<usize>,
|
||||
|
||||
/// `codegen_static` will sometimes create a second global variable with a
|
||||
/// different type and clear the symbol name of the original global.
|
||||
/// `global_asm!` needs to be able to find this new global so that it can
|
||||
/// compute the correct mangled symbol name to insert into the asm.
|
||||
pub renamed_statics: RefCell<FxHashMap<DefId, &'ll Value>>,
|
||||
}
|
||||
|
||||
pub struct TypeLowering<'ll> {
|
||||
|
@ -436,6 +443,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
|
|||
rust_try_fn: Cell::new(None),
|
||||
intrinsics: Default::default(),
|
||||
local_gen_sym_counter: Cell::new(0),
|
||||
renamed_statics: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2537,4 +2537,6 @@ extern "C" {
|
|||
remark_passes_len: usize,
|
||||
);
|
||||
|
||||
#[allow(improper_ctypes)]
|
||||
pub fn LLVMRustGetMangledName(V: &Value, out: &RustString);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,9 @@ use crate::traits::*;
|
|||
use rustc_hir as hir;
|
||||
use rustc_middle::mir::mono::MonoItem;
|
||||
use rustc_middle::mir::mono::{Linkage, Visibility};
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
|
||||
use rustc_middle::ty::Instance;
|
||||
|
||||
pub trait MonoItemExt<'a, 'tcx> {
|
||||
fn define<Bx: BuilderMethods<'a, 'tcx>>(&self, cx: &'a Bx::CodegenCx);
|
||||
|
@ -56,7 +58,27 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {
|
|||
);
|
||||
GlobalAsmOperandRef::Const { string }
|
||||
}
|
||||
_ => span_bug!(*op_sp, "invalid operand type for global_asm!"),
|
||||
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, substs) => Instance::new(def_id, substs),
|
||||
_ => 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();
|
||||
|
||||
|
|
|
@ -36,8 +36,10 @@ pub enum InlineAsmOperandRef<'tcx, B: BackendTypes + ?Sized> {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum GlobalAsmOperandRef {
|
||||
pub enum GlobalAsmOperandRef<'tcx> {
|
||||
Const { string: String },
|
||||
SymFn { instance: Instance<'tcx> },
|
||||
SymStatic { def_id: DefId },
|
||||
}
|
||||
|
||||
pub trait AsmBuilderMethods<'tcx>: BackendTypes {
|
||||
|
@ -53,11 +55,11 @@ pub trait AsmBuilderMethods<'tcx>: BackendTypes {
|
|||
);
|
||||
}
|
||||
|
||||
pub trait AsmMethods {
|
||||
pub trait AsmMethods<'tcx> {
|
||||
fn codegen_global_asm(
|
||||
&self,
|
||||
template: &[InlineAsmTemplatePiece],
|
||||
operands: &[GlobalAsmOperandRef],
|
||||
operands: &[GlobalAsmOperandRef<'tcx>],
|
||||
options: InlineAsmOptions,
|
||||
line_spans: &[Span],
|
||||
);
|
||||
|
|
|
@ -60,7 +60,7 @@ pub trait CodegenMethods<'tcx>:
|
|||
+ StaticMethods
|
||||
+ CoverageInfoMethods<'tcx>
|
||||
+ DebugInfoMethods<'tcx>
|
||||
+ AsmMethods
|
||||
+ AsmMethods<'tcx>
|
||||
+ PreDefineMethods<'tcx>
|
||||
+ HasParamEnv<'tcx>
|
||||
+ HasTyCtxt<'tcx>
|
||||
|
@ -76,7 +76,7 @@ impl<'tcx, T> CodegenMethods<'tcx> for T where
|
|||
+ StaticMethods
|
||||
+ CoverageInfoMethods<'tcx>
|
||||
+ DebugInfoMethods<'tcx>
|
||||
+ AsmMethods
|
||||
+ AsmMethods<'tcx>
|
||||
+ PreDefineMethods<'tcx>
|
||||
+ HasParamEnv<'tcx>
|
||||
+ HasTyCtxt<'tcx>
|
||||
|
|
|
@ -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 @@ impl<'hir> InlineAsmOperand<'hir> {
|
|||
| 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 @@ pub trait Visitor<'v>: Sized {
|
|||
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 @@ impl<'a> State<'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) => {
|
||||
|
|
|
@ -1835,3 +1835,9 @@ extern "C" void LLVMRustContextConfigureDiagnosticHandler(
|
|||
unwrap(C)->setDiagnosticHandler(std::make_unique<RustDiagnosticHandler>(
|
||||
DiagnosticHandlerCallback, DiagnosticHandlerContext, RemarkAllPasses, Passes));
|
||||
}
|
||||
|
||||
extern "C" void LLVMRustGetMangledName(LLVMValueRef V, RustStringRef Str) {
|
||||
RawRustStringOstream OS(Str);
|
||||
GlobalValue *GV = unwrap<GlobalValue>(V);
|
||||
Mangler().getNameWithPrefix(OS, GV, true);
|
||||
}
|
||||
|
|
|
@ -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: _ } => {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -426,9 +426,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
value: Box::new(Constant { span, user_ty: None, literal: value }),
|
||||
}
|
||||
}
|
||||
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,94 +462,55 @@ impl<'tcx> Cx<'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(),
|
||||
|
|
|
@ -435,7 +435,27 @@ fn collect_items_rec<'tcx>(
|
|||
// are supported. Therefore the value should not
|
||||
// depend on any other items.
|
||||
}
|
||||
_ => span_bug!(*op_sp, "invalid operand type for global_asm!"),
|
||||
hir::InlineAsmOperand::SymFn { anon_const } => {
|
||||
let def_id = tcx.hir().body_owner_def_id(anon_const.body).to_def_id();
|
||||
if let Ok(val) = tcx.const_eval_poly(def_id) {
|
||||
rustc_data_structures::stack::ensure_sufficient_stack(|| {
|
||||
collect_const_value(tcx, val, &mut neighbors);
|
||||
});
|
||||
}
|
||||
}
|
||||
hir::InlineAsmOperand::SymStatic { path: _, def_id } => {
|
||||
let instance = Instance::mono(tcx, *def_id);
|
||||
if should_codegen_locally(tcx, &instance) {
|
||||
trace!("collecting static {:?}", def_id);
|
||||
neighbors.push(dummy_spanned(MonoItem::Static(*def_id)));
|
||||
}
|
||||
}
|
||||
hir::InlineAsmOperand::In { .. }
|
||||
| hir::InlineAsmOperand::Out { .. }
|
||||
| hir::InlineAsmOperand::InOut { .. }
|
||||
| hir::InlineAsmOperand::SplitInOut { .. } => {
|
||||
span_bug!(*op_sp, "invalid operand type for global_asm!")
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -536,6 +536,10 @@ impl<'v, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'tcx> {
|
|||
.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 @@ impl<'tcx> ExprVisitor<'tcx> {
|
|||
);
|
||||
}
|
||||
}
|
||||
hir::InlineAsmOperand::Const { .. } | hir::InlineAsmOperand::Sym { .. } => {}
|
||||
// These are checked in ItemVisitor.
|
||||
hir::InlineAsmOperand::Const { .. }
|
||||
| hir::InlineAsmOperand::SymFn { .. }
|
||||
| hir::InlineAsmOperand::SymStatic { .. } => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -498,6 +502,42 @@ impl<'tcx> Visitor<'tcx> for ItemVisitor<'tcx> {
|
|||
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 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
|||
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 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
|||
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 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
|||
}
|
||||
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 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
|
|||
.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 @@ impl<'a> Resolver<'a> {
|
|||
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 @@ impl<'a> Resolver<'a> {
|
|||
}
|
||||
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 @@ impl<'a> Resolver<'a> {
|
|||
}
|
||||
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 @@ impl<'a> Resolver<'a> {
|
|||
}
|
||||
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 @@ crate enum RibKind<'a> {
|
|||
/// 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 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
|||
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 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
|||
| 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> {
|
||||
|
|
|
@ -2520,12 +2520,11 @@ impl<'a, 'tcx> FnCtxt<'a, '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,
|
||||
}) =>
|
||||
{
|
||||
// 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(),
|
||||
},
|
||||
|
|
|
@ -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 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
|
|||
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 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
hir::InlineAsmOperand::Out { expr: None, .. }
|
||||
| hir::InlineAsmOperand::Const { .. } => {}
|
||||
| hir::InlineAsmOperand::Const { .. }
|
||||
| hir::InlineAsmOperand::SymFn { .. }
|
||||
| hir::InlineAsmOperand::SymStatic { .. } => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,26 @@
|
|||
// only-x86_64
|
||||
// only-linux
|
||||
// assembly-output: emit-asm
|
||||
// compile-flags: -C llvm-args=--x86-asm-syntax=intel
|
||||
|
||||
#![feature(asm_const)]
|
||||
#![feature(asm_const, asm_sym)]
|
||||
#![crate_type = "rlib"]
|
||||
|
||||
use std::arch::global_asm;
|
||||
|
||||
#[no_mangle]
|
||||
fn my_func() {}
|
||||
|
||||
#[no_mangle]
|
||||
static MY_STATIC: i32 = 0;
|
||||
|
||||
// CHECK: mov eax, eax
|
||||
global_asm!("mov eax, eax");
|
||||
// CHECK: mov ebx, 5
|
||||
global_asm!("mov ebx, {}", const 5);
|
||||
// CHECK: mov ecx, 5
|
||||
global_asm!("movl ${}, %ecx", const 5, options(att_syntax));
|
||||
// CHECK: call my_func
|
||||
global_asm!("call {}", sym my_func);
|
||||
// CHECK: lea rax, [rip + MY_STATIC]
|
||||
global_asm!("lea rax, [rip + {}]", sym MY_STATIC);
|
||||
|
|
|
@ -29,7 +29,7 @@ fn main() {
|
|||
asm!("{}", in(reg) foo => bar);
|
||||
//~^ ERROR expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>`
|
||||
asm!("{}", sym foo + bar);
|
||||
//~^ ERROR argument to `sym` must be a path expression
|
||||
//~^ ERROR expected a path for argument to `sym`
|
||||
asm!("", options(foo));
|
||||
//~^ ERROR expected one of
|
||||
asm!("", options(nomem foo));
|
||||
|
|
|
@ -58,7 +58,7 @@ error: expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>`
|
|||
LL | asm!("{}", in(reg) foo => bar);
|
||||
| ^^ expected one of 7 possible tokens
|
||||
|
||||
error: argument to `sym` must be a path expression
|
||||
error: expected a path for argument to `sym`
|
||||
--> $DIR/parse-error.rs:31:24
|
||||
|
|
||||
LL | asm!("{}", sym foo + bar);
|
||||
|
@ -350,17 +350,17 @@ LL | global_asm!("{a}", a = const FOO, a = const BAR);
|
|||
|
|
||||
= help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"`
|
||||
|
||||
error: expected one of `clobber_abi`, `const`, or `options`, found `""`
|
||||
error: expected one of `clobber_abi`, `const`, `options`, or `sym`, found `""`
|
||||
--> $DIR/parse-error.rs:126:28
|
||||
|
|
||||
LL | global_asm!("", options(), "");
|
||||
| ^^ expected one of `clobber_abi`, `const`, or `options`
|
||||
| ^^ expected one of `clobber_abi`, `const`, `options`, or `sym`
|
||||
|
||||
error: expected one of `clobber_abi`, `const`, or `options`, found `"{}"`
|
||||
error: expected one of `clobber_abi`, `const`, `options`, or `sym`, found `"{}"`
|
||||
--> $DIR/parse-error.rs:128:30
|
||||
|
|
||||
LL | global_asm!("{}", const FOO, "{}", const FOO);
|
||||
| ^^^^ expected one of `clobber_abi`, `const`, or `options`
|
||||
| ^^^^ expected one of `clobber_abi`, `const`, `options`, or `sym`
|
||||
|
||||
error: asm template must be a string literal
|
||||
--> $DIR/parse-error.rs:130:13
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#![feature(repr_simd, never_type, asm_sym)]
|
||||
|
||||
use std::arch::asm;
|
||||
use std::arch::{asm, global_asm};
|
||||
|
||||
#[repr(simd)]
|
||||
#[derive(Clone, Copy)]
|
||||
|
@ -39,9 +39,7 @@ fn main() {
|
|||
asm!("{}", sym S);
|
||||
asm!("{}", sym main);
|
||||
asm!("{}", sym C);
|
||||
//~^ ERROR asm `sym` operand must point to a fn or static
|
||||
asm!("{}", sym x);
|
||||
//~^ ERROR asm `sym` operand must point to a fn or static
|
||||
//~^ ERROR invalid `sym` operand
|
||||
|
||||
// Register operands must be Copy
|
||||
|
||||
|
@ -84,3 +82,12 @@ fn main() {
|
|||
asm!("{}", in(reg) u);
|
||||
}
|
||||
}
|
||||
|
||||
// Sym operands must point to a function or static
|
||||
|
||||
const C: i32 = 0;
|
||||
static S: i32 = 0;
|
||||
global_asm!("{}", sym S);
|
||||
global_asm!("{}", sym main);
|
||||
global_asm!("{}", sym C);
|
||||
//~^ ERROR invalid `sym` operand
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
error: arguments for inline assembly must be copyable
|
||||
--> $DIR/type-check-2.rs:48:31
|
||||
--> $DIR/type-check-2.rs:46:31
|
||||
|
|
||||
LL | asm!("{:v}", in(vreg) SimdNonCopy(0.0, 0.0, 0.0, 0.0));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `SimdNonCopy` does not implement the Copy trait
|
||||
|
||||
error: cannot use value of type `[closure@$DIR/type-check-2.rs:60:28: 60:38]` for inline assembly
|
||||
--> $DIR/type-check-2.rs:60:28
|
||||
error: cannot use value of type `[closure@$DIR/type-check-2.rs:58:28: 58:38]` for inline assembly
|
||||
--> $DIR/type-check-2.rs:58:28
|
||||
|
|
||||
LL | asm!("{}", in(reg) |x: i32| x);
|
||||
| ^^^^^^^^^^
|
||||
|
@ -15,7 +15,7 @@ LL | asm!("{}", in(reg) |x: i32| x);
|
|||
= note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
|
||||
|
||||
error: cannot use value of type `Vec<i32>` for inline assembly
|
||||
--> $DIR/type-check-2.rs:62:28
|
||||
--> $DIR/type-check-2.rs:60:28
|
||||
|
|
||||
LL | asm!("{}", in(reg) vec![0]);
|
||||
| ^^^^^^^
|
||||
|
@ -24,7 +24,7 @@ LL | asm!("{}", in(reg) vec![0]);
|
|||
= note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: cannot use value of type `(i32, i32, i32)` for inline assembly
|
||||
--> $DIR/type-check-2.rs:64:28
|
||||
--> $DIR/type-check-2.rs:62:28
|
||||
|
|
||||
LL | asm!("{}", in(reg) (1, 2, 3));
|
||||
| ^^^^^^^^^
|
||||
|
@ -32,7 +32,7 @@ LL | asm!("{}", in(reg) (1, 2, 3));
|
|||
= note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
|
||||
|
||||
error: cannot use value of type `[i32; 3]` for inline assembly
|
||||
--> $DIR/type-check-2.rs:66:28
|
||||
--> $DIR/type-check-2.rs:64:28
|
||||
|
|
||||
LL | asm!("{}", in(reg) [1, 2, 3]);
|
||||
| ^^^^^^^^^
|
||||
|
@ -40,7 +40,7 @@ LL | asm!("{}", in(reg) [1, 2, 3]);
|
|||
= note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
|
||||
|
||||
error: cannot use value of type `fn() {main}` for inline assembly
|
||||
--> $DIR/type-check-2.rs:74:31
|
||||
--> $DIR/type-check-2.rs:72:31
|
||||
|
|
||||
LL | asm!("{}", inout(reg) f);
|
||||
| ^
|
||||
|
@ -48,24 +48,28 @@ LL | asm!("{}", inout(reg) f);
|
|||
= note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
|
||||
|
||||
error: cannot use value of type `&mut i32` for inline assembly
|
||||
--> $DIR/type-check-2.rs:77:31
|
||||
--> $DIR/type-check-2.rs:75:31
|
||||
|
|
||||
LL | asm!("{}", inout(reg) r);
|
||||
| ^
|
||||
|
|
||||
= note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
|
||||
|
||||
error: asm `sym` operand must point to a fn or static
|
||||
--> $DIR/type-check-2.rs:41:24
|
||||
error: invalid `sym` operand
|
||||
--> $DIR/type-check-2.rs:41:20
|
||||
|
|
||||
LL | asm!("{}", sym C);
|
||||
| ^
|
||||
|
||||
error: asm `sym` operand must point to a fn or static
|
||||
--> $DIR/type-check-2.rs:43:24
|
||||
| ^^^^^ is an `i32`
|
||||
|
|
||||
LL | asm!("{}", sym x);
|
||||
| ^
|
||||
= help: `sym` operands must refer to either a function or a static
|
||||
|
||||
error: invalid `sym` operand
|
||||
--> $DIR/type-check-2.rs:92:19
|
||||
|
|
||||
LL | global_asm!("{}", sym C);
|
||||
| ^^^^^ is an `i32`
|
||||
|
|
||||
= help: `sym` operands must refer to either a function or a static
|
||||
|
||||
error[E0381]: use of possibly-uninitialized variable: `x`
|
||||
--> $DIR/type-check-2.rs:19:28
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
// ignore-spirv
|
||||
// ignore-wasm32
|
||||
|
||||
#![feature(asm_const)]
|
||||
#![feature(asm_const, asm_sym)]
|
||||
|
||||
use std::arch::{asm, global_asm};
|
||||
|
||||
|
@ -44,6 +44,8 @@ fn main() {
|
|||
asm!("{}", const const_bar(0));
|
||||
asm!("{}", const const_bar(x));
|
||||
//~^ ERROR attempt to use a non-constant value in a constant
|
||||
asm!("{}", sym x);
|
||||
//~^ ERROR invalid `sym` operand
|
||||
|
||||
// Const operands must be integers and must be constants.
|
||||
|
||||
|
@ -59,6 +61,11 @@ fn main() {
|
|||
}
|
||||
}
|
||||
|
||||
unsafe fn generic<T>() {
|
||||
asm!("{}", sym generic::<T>);
|
||||
//~^ generic parameters may not be used in const operations
|
||||
}
|
||||
|
||||
// Const operands must be integers and must be constants.
|
||||
|
||||
global_asm!("{}", const 0);
|
||||
|
|
|
@ -25,14 +25,31 @@ LL | let x = 0;
|
|||
LL | asm!("{}", const const_bar(x));
|
||||
| ^ non-constant value
|
||||
|
||||
error: invalid `sym` operand
|
||||
--> $DIR/type-check-1.rs:47:24
|
||||
|
|
||||
LL | asm!("{}", sym x);
|
||||
| ^ is a local variable
|
||||
|
|
||||
= help: `sym` operands must refer to either a function or a static
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/type-check-1.rs:65:30
|
||||
|
|
||||
LL | asm!("{}", sym generic::<T>);
|
||||
| ^ cannot perform const operation using `T`
|
||||
|
|
||||
= note: type parameters may not be used in const expressions
|
||||
= help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/type-check-1.rs:53:26
|
||||
--> $DIR/type-check-1.rs:55:26
|
||||
|
|
||||
LL | asm!("{}", const 0f32);
|
||||
| ^^^^ expected integer, found `f32`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/type-check-1.rs:55:26
|
||||
--> $DIR/type-check-1.rs:57:26
|
||||
|
|
||||
LL | asm!("{}", const 0 as *mut u8);
|
||||
| ^^^^^^^^^^^^ expected integer, found *-ptr
|
||||
|
@ -41,7 +58,7 @@ LL | asm!("{}", const 0 as *mut u8);
|
|||
found raw pointer `*mut u8`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/type-check-1.rs:57:26
|
||||
--> $DIR/type-check-1.rs:59:26
|
||||
|
|
||||
LL | asm!("{}", const &0);
|
||||
| ^^ expected integer, found `&{integer}`
|
||||
|
@ -92,13 +109,13 @@ LL | asm!("{}", inout(reg) v[..]);
|
|||
= note: all inline asm arguments must have a statically known size
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/type-check-1.rs:67:25
|
||||
--> $DIR/type-check-1.rs:74:25
|
||||
|
|
||||
LL | global_asm!("{}", const 0f32);
|
||||
| ^^^^ expected integer, found `f32`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/type-check-1.rs:69:25
|
||||
--> $DIR/type-check-1.rs:76:25
|
||||
|
|
||||
LL | global_asm!("{}", const 0 as *mut u8);
|
||||
| ^^^^^^^^^^^^ expected integer, found *-ptr
|
||||
|
@ -106,7 +123,7 @@ LL | global_asm!("{}", const 0 as *mut u8);
|
|||
= note: expected type `{integer}`
|
||||
found raw pointer `*mut u8`
|
||||
|
||||
error: aborting due to 13 previous errors
|
||||
error: aborting due to 15 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0277, E0308, E0435.
|
||||
For more information about an error, try `rustc --explain E0277`.
|
||||
|
|
|
@ -29,7 +29,7 @@ fn main() {
|
|||
asm!("{}", in(reg) foo => bar);
|
||||
//~^ ERROR expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>`
|
||||
asm!("{}", sym foo + bar);
|
||||
//~^ ERROR argument to `sym` must be a path expression
|
||||
//~^ ERROR expected a path for argument to `sym`
|
||||
asm!("", options(foo));
|
||||
//~^ ERROR expected one of
|
||||
asm!("", options(nomem foo));
|
||||
|
|
|
@ -58,7 +58,7 @@ error: expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>`
|
|||
LL | asm!("{}", in(reg) foo => bar);
|
||||
| ^^ expected one of 7 possible tokens
|
||||
|
||||
error: argument to `sym` must be a path expression
|
||||
error: expected a path for argument to `sym`
|
||||
--> $DIR/parse-error.rs:31:24
|
||||
|
|
||||
LL | asm!("{}", sym foo + bar);
|
||||
|
@ -362,17 +362,17 @@ LL | global_asm!("{a}", a = const FOO, a = const BAR);
|
|||
|
|
||||
= help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"`
|
||||
|
||||
error: expected one of `clobber_abi`, `const`, or `options`, found `""`
|
||||
error: expected one of `clobber_abi`, `const`, `options`, or `sym`, found `""`
|
||||
--> $DIR/parse-error.rs:130:28
|
||||
|
|
||||
LL | global_asm!("", options(), "");
|
||||
| ^^ expected one of `clobber_abi`, `const`, or `options`
|
||||
| ^^ expected one of `clobber_abi`, `const`, `options`, or `sym`
|
||||
|
||||
error: expected one of `clobber_abi`, `const`, or `options`, found `"{}"`
|
||||
error: expected one of `clobber_abi`, `const`, `options`, or `sym`, found `"{}"`
|
||||
--> $DIR/parse-error.rs:132:30
|
||||
|
|
||||
LL | global_asm!("{}", const FOO, "{}", const FOO);
|
||||
| ^^^^ expected one of `clobber_abi`, `const`, or `options`
|
||||
| ^^^^ expected one of `clobber_abi`, `const`, `options`, or `sym`
|
||||
|
||||
error: asm template must be a string literal
|
||||
--> $DIR/parse-error.rs:134:13
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#![feature(repr_simd, never_type, asm_sym)]
|
||||
|
||||
use std::arch::asm;
|
||||
use std::arch::{asm, global_asm};
|
||||
|
||||
#[repr(simd)]
|
||||
struct SimdNonCopy(f32, f32, f32, f32);
|
||||
|
@ -35,9 +35,7 @@ fn main() {
|
|||
asm!("{}", sym S);
|
||||
asm!("{}", sym main);
|
||||
asm!("{}", sym C);
|
||||
//~^ ERROR asm `sym` operand must point to a fn or static
|
||||
asm!("{}", sym x);
|
||||
//~^ ERROR asm `sym` operand must point to a fn or static
|
||||
//~^ ERROR invalid `sym` operand
|
||||
|
||||
// Register operands must be Copy
|
||||
|
||||
|
@ -80,3 +78,12 @@ fn main() {
|
|||
asm!("{}", in(reg) u);
|
||||
}
|
||||
}
|
||||
|
||||
// Sym operands must point to a function or static
|
||||
|
||||
const C: i32 = 0;
|
||||
static S: i32 = 0;
|
||||
global_asm!("{}", sym S);
|
||||
global_asm!("{}", sym main);
|
||||
global_asm!("{}", sym C);
|
||||
//~^ ERROR invalid `sym` operand
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
error: arguments for inline assembly must be copyable
|
||||
--> $DIR/type-check-2.rs:44:32
|
||||
--> $DIR/type-check-2.rs:42:32
|
||||
|
|
||||
LL | asm!("{}", in(xmm_reg) SimdNonCopy(0.0, 0.0, 0.0, 0.0));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `SimdNonCopy` does not implement the Copy trait
|
||||
|
||||
error: cannot use value of type `[closure@$DIR/type-check-2.rs:56:28: 56:38]` for inline assembly
|
||||
--> $DIR/type-check-2.rs:56:28
|
||||
error: cannot use value of type `[closure@$DIR/type-check-2.rs:54:28: 54:38]` for inline assembly
|
||||
--> $DIR/type-check-2.rs:54:28
|
||||
|
|
||||
LL | asm!("{}", in(reg) |x: i32| x);
|
||||
| ^^^^^^^^^^
|
||||
|
@ -15,7 +15,7 @@ LL | asm!("{}", in(reg) |x: i32| x);
|
|||
= note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
|
||||
|
||||
error: cannot use value of type `Vec<i32>` for inline assembly
|
||||
--> $DIR/type-check-2.rs:58:28
|
||||
--> $DIR/type-check-2.rs:56:28
|
||||
|
|
||||
LL | asm!("{}", in(reg) vec![0]);
|
||||
| ^^^^^^^
|
||||
|
@ -24,7 +24,7 @@ LL | asm!("{}", in(reg) vec![0]);
|
|||
= note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: cannot use value of type `(i32, i32, i32)` for inline assembly
|
||||
--> $DIR/type-check-2.rs:60:28
|
||||
--> $DIR/type-check-2.rs:58:28
|
||||
|
|
||||
LL | asm!("{}", in(reg) (1, 2, 3));
|
||||
| ^^^^^^^^^
|
||||
|
@ -32,7 +32,7 @@ LL | asm!("{}", in(reg) (1, 2, 3));
|
|||
= note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
|
||||
|
||||
error: cannot use value of type `[i32; 3]` for inline assembly
|
||||
--> $DIR/type-check-2.rs:62:28
|
||||
--> $DIR/type-check-2.rs:60:28
|
||||
|
|
||||
LL | asm!("{}", in(reg) [1, 2, 3]);
|
||||
| ^^^^^^^^^
|
||||
|
@ -40,7 +40,7 @@ LL | asm!("{}", in(reg) [1, 2, 3]);
|
|||
= note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
|
||||
|
||||
error: cannot use value of type `fn() {main}` for inline assembly
|
||||
--> $DIR/type-check-2.rs:70:31
|
||||
--> $DIR/type-check-2.rs:68:31
|
||||
|
|
||||
LL | asm!("{}", inout(reg) f);
|
||||
| ^
|
||||
|
@ -48,24 +48,28 @@ LL | asm!("{}", inout(reg) f);
|
|||
= note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
|
||||
|
||||
error: cannot use value of type `&mut i32` for inline assembly
|
||||
--> $DIR/type-check-2.rs:73:31
|
||||
--> $DIR/type-check-2.rs:71:31
|
||||
|
|
||||
LL | asm!("{}", inout(reg) r);
|
||||
| ^
|
||||
|
|
||||
= note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
|
||||
|
||||
error: asm `sym` operand must point to a fn or static
|
||||
--> $DIR/type-check-2.rs:37:24
|
||||
error: invalid `sym` operand
|
||||
--> $DIR/type-check-2.rs:37:20
|
||||
|
|
||||
LL | asm!("{}", sym C);
|
||||
| ^
|
||||
|
||||
error: asm `sym` operand must point to a fn or static
|
||||
--> $DIR/type-check-2.rs:39:24
|
||||
| ^^^^^ is an `i32`
|
||||
|
|
||||
LL | asm!("{}", sym x);
|
||||
| ^
|
||||
= help: `sym` operands must refer to either a function or a static
|
||||
|
||||
error: invalid `sym` operand
|
||||
--> $DIR/type-check-2.rs:88:19
|
||||
|
|
||||
LL | global_asm!("{}", sym C);
|
||||
| ^^^^^ is an `i32`
|
||||
|
|
||||
= help: `sym` operands must refer to either a function or a static
|
||||
|
||||
error[E0381]: use of possibly-uninitialized variable: `x`
|
||||
--> $DIR/type-check-2.rs:15:28
|
||||
|
|
|
@ -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 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
|||
}
|
||||
},
|
||||
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…
Add table
Reference in a new issue