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:
bors 2022-04-16 04:46:01 +00:00
commit 080d5452e1
50 changed files with 654 additions and 245 deletions

View file

@ -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,
},
}

View file

@ -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();

View file

@ -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());

View file

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

View file

@ -1266,10 +1266,14 @@ 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);
}
}
}
}

View file

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

View file

@ -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);
}
}
}
}

View file

@ -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);
}
}
}
}

View file

@ -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();

View file

@ -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.)

View file

@ -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(),
}
}

View file

@ -2537,4 +2537,6 @@ extern "C" {
remark_passes_len: usize,
);
#[allow(improper_ctypes)]
pub fn LLVMRustGetMangledName(V: &Value, out: &RustString);
}

View file

@ -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();

View file

@ -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],
);

View file

@ -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>

View file

@ -2425,8 +2425,12 @@ pub enum InlineAsmOperand<'hir> {
Const {
anon_const: AnonConst,
},
Sym {
expr: Expr<'hir>,
SymFn {
anon_const: AnonConst,
},
SymStatic {
path: QPath<'hir>,
def_id: DefId,
},
}
@ -2437,7 +2441,7 @@ 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,
}
}

View file

@ -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);

View file

@ -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) => {

View file

@ -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);
}

View file

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

View file

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

View file

@ -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 }
}

View file

@ -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(),

View file

@ -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 {

View file

@ -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);
}
_ => (),
}
}

View file

@ -1,3 +1,4 @@
use hir::intravisit::walk_inline_asm;
use rustc_ast::InlineAsmTemplatePiece;
use rustc_data_structures::stable_set::FxHashSet;
use rustc_errors::struct_span_err;
@ -483,7 +484,10 @@ 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> {

View file

@ -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

View file

@ -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 { .. }

View file

@ -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
}
}
}

View file

@ -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.

View file

@ -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;
}
}

View file

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

View file

@ -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) {

View file

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

View file

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

View file

@ -358,8 +358,7 @@ 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 { .. } => {}
}
}
}

View file

@ -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);

View file

@ -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));

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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`.

View file

@ -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));

View file

@ -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

View file

@ -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

View file

@ -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

View file

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

View file

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

View file

@ -675,7 +675,8 @@ 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),
}
}
},