diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 75ccbc92be1f6..136bc199ba378 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -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, + 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, + sym: InlineAsmSym, }, } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 15f7aceb83d7a..cba49835f69cb 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -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(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(AnonConst { id, value }: &mut AnonCo vis.visit_expr(value); } -fn noop_visit_inline_asm(asm: &mut InlineAsm, vis: &mut T) { +pub fn noop_visit_inline_asm(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(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( + 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( Expr { kind, id, span, attrs, tokens }: &mut Expr, vis: &mut T, @@ -1374,7 +1391,7 @@ pub fn noop_visit_expr( 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(); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index ed16c25d921e4..3183612597d13 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -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()); diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index 171cc60dfd77c..ae3e367596258 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -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!() } }; diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 719fd27109321..c2247150d09c2 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -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); + } } } } diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 57ef46475ddd8..030295d3d8dc3 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -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 diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index 8a74c4c07e0cf..2af050f0c7533 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -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); + } } } } diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 03c390b4bd427..dff3200791825 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -290,6 +290,11 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } attributes::apply_to_callsite(result, llvm::AttributePlace::Function, &{ attrs }); + // Switch to the 'normal' basic block if we did an `invoke` instead of a `call` + if let Some((dest, _, _)) = dest_catch_funclet { + self.switch_to_block(dest); + } + // Write results to outputs for (idx, op) in operands.iter().enumerate() { if let InlineAsmOperandRef::Out { reg, place: Some(place), .. } @@ -307,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], ) { @@ -337,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); + } } } } diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 0f5b1c08ec2dc..6bc242b46e043 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -16,7 +16,7 @@ use rustc_errors::{FatalError, Handler}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::bug; use rustc_middle::dep_graph::WorkProduct; -use rustc_middle::middle::exported_symbols::SymbolExportLevel; +use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel}; use rustc_session::cgu_reuse_tracker::CguReuse; use rustc_session::config::{self, CrateType, Lto}; use tracing::{debug, info}; @@ -55,8 +55,8 @@ fn prepare_lto( Lto::No => panic!("didn't request LTO but we're doing LTO"), }; - let symbol_filter = &|&(ref name, level): &(String, SymbolExportLevel)| { - if level.is_below_threshold(export_threshold) { + let symbol_filter = &|&(ref name, info): &(String, SymbolExportInfo)| { + if info.level.is_below_threshold(export_threshold) { Some(CString::new(name.as_str()).unwrap()) } else { None diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs index dd3ada443895f..94655421b8c18 100644 --- a/compiler/rustc_codegen_llvm/src/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -99,7 +99,16 @@ 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 + // Create the llvm.used and llvm.compiler.used variables. + if !cx.used_statics().borrow().is_empty() { + cx.create_used_variable() + } + if !cx.compiler_used_statics().borrow().is_empty() { + 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)); @@ -114,14 +123,6 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol) -> (ModuleCodegen cx.coverageinfo_finalize(); } - // Create the llvm.used and llvm.compiler.used variables. - if !cx.used_statics().borrow().is_empty() { - cx.create_used_variable() - } - if !cx.compiler_used_statics().borrow().is_empty() { - cx.create_compiler_used_variable() - } - // Finalize debuginfo if cx.sess().opts.debuginfo != DebugInfo::None { cx.debuginfo_finalize(); diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index cb4073528e10a..4d3f3f318b80c 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -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.) diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 98cf873ebbdc3..d296ee3b42ce1 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -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, + + /// `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>, } 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(), } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 375b9927c8672..7f533b0552a5d 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2537,4 +2537,6 @@ extern "C" { remark_passes_len: usize, ); + #[allow(improper_ctypes)] + pub fn LLVMRustGetMangledName(V: &Value, out: &RustString); } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index cf32d558d4a51..c1143978c0cf0 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -7,6 +7,7 @@ use rustc_errors::{ErrorGuaranteed, Handler}; use rustc_fs_util::fix_windows_verbatim_for_gcc; use rustc_hir::def_id::CrateNum; use rustc_middle::middle::dependency_format::Linkage; +use rustc_middle::middle::exported_symbols::SymbolExportKind; use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip}; use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, SplitDwarfKind}; use rustc_session::cstore::DllImport; @@ -1655,6 +1656,67 @@ fn add_post_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor } } +/// Add a synthetic object file that contains reference to all symbols that we want to expose to +/// the linker. +/// +/// Background: we implement rlibs as static library (archives). Linkers treat archives +/// differently from object files: all object files participate in linking, while archives will +/// only participate in linking if they can satisfy at least one undefined reference (version +/// scripts doesn't count). This causes `#[no_mangle]` or `#[used]` items to be ignored by the +/// linker, and since they never participate in the linking, using `KEEP` in the linker scripts +/// can't keep them either. This causes #47384. +/// +/// To keep them around, we could use `--whole-archive` and equivalents to force rlib to +/// participate in linking like object files, but this proves to be expensive (#93791). Therefore +/// we instead just introduce an undefined reference to them. This could be done by `-u` command +/// line option to the linker or `EXTERN(...)` in linker scripts, however they does not only +/// introduce an undefined reference, but also make them the GC roots, preventing `--gc-sections` +/// from removing them, and this is especially problematic for embedded programming where every +/// byte counts. +/// +/// This method creates a synthetic object file, which contains undefined references to all symbols +/// that are necessary for the linking. They are only present in symbol table but not actually +/// used in any sections, so the linker will therefore pick relevant rlibs for linking, but +/// unused `#[no_mangle]` or `#[used]` can still be discard by GC sections. +fn add_linked_symbol_object( + cmd: &mut dyn Linker, + sess: &Session, + tmpdir: &Path, + symbols: &[(String, SymbolExportKind)], +) { + if symbols.is_empty() { + return; + } + + let Some(mut file) = super::metadata::create_object_file(sess) else { + return; + }; + + for (sym, kind) in symbols.iter() { + file.add_symbol(object::write::Symbol { + name: sym.clone().into(), + value: 0, + size: 0, + kind: match kind { + SymbolExportKind::Text => object::SymbolKind::Text, + SymbolExportKind::Data => object::SymbolKind::Data, + SymbolExportKind::Tls => object::SymbolKind::Tls, + }, + scope: object::SymbolScope::Unknown, + weak: false, + section: object::write::SymbolSection::Undefined, + flags: object::SymbolFlags::None, + }); + } + + let path = tmpdir.join("symbols.o"); + let result = std::fs::write(&path, file.write().unwrap()); + if let Err(e) = result { + sess.fatal(&format!("failed to write {}: {}", path.display(), e)); + } + cmd.add_object(&path); +} + /// Add object files containing code from the current crate. fn add_local_crate_regular_objects(cmd: &mut dyn Linker, codegen_results: &CodegenResults) { for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) { @@ -1798,6 +1860,13 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( // Sanitizer libraries. add_sanitizer_libraries(sess, crate_type, cmd); + add_linked_symbol_object( + cmd, + sess, + tmpdir, + &codegen_results.crate_info.linked_symbols[&crate_type], + ); + // Object code from the current crate. // Take careful note of the ordering of the arguments we pass to the linker // here. Linkers will assume that things on the left depend on things to the diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 2c15ed831670c..6e13e0d0e43b1 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -12,6 +12,7 @@ use std::{env, mem, str}; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_middle::middle::dependency_format::Linkage; +use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo, SymbolExportKind}; use rustc_middle::ty::TyCtxt; use rustc_serialize::{json, Encoder}; use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip}; @@ -1518,6 +1519,29 @@ impl<'a> L4Bender<'a> { } } +fn for_each_exported_symbols_include_dep<'tcx>( + tcx: TyCtxt<'tcx>, + crate_type: CrateType, + mut callback: impl FnMut(ExportedSymbol<'tcx>, SymbolExportInfo, CrateNum), +) { + for &(symbol, info) in tcx.exported_symbols(LOCAL_CRATE).iter() { + callback(symbol, info, LOCAL_CRATE); + } + + let formats = tcx.dependency_formats(()); + let deps = formats.iter().find_map(|(t, list)| (*t == crate_type).then_some(list)).unwrap(); + + for (index, dep_format) in deps.iter().enumerate() { + let cnum = CrateNum::new(index + 1); + // For each dependency that we are linking to statically ... + if *dep_format == Linkage::Static { + for &(symbol, info) in tcx.exported_symbols(cnum).iter() { + callback(symbol, info, cnum); + } + } + } +} + pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec { if let Some(ref exports) = tcx.sess.target.override_export_symbols { return exports.iter().map(ToString::to_string).collect(); @@ -1526,34 +1550,38 @@ pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec, + crate_type: CrateType, +) -> Vec<(String, SymbolExportKind)> { + match crate_type { + CrateType::Executable | CrateType::Cdylib => (), + CrateType::Staticlib | CrateType::ProcMacro | CrateType::Rlib | CrateType::Dylib => { + return Vec::new(); } } + let mut symbols = Vec::new(); + + let export_threshold = symbol_export::crates_export_threshold(&[crate_type]); + for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| { + if info.level.is_below_threshold(export_threshold) || info.used { + symbols.push(( + symbol_export::symbol_name_for_instance_in_crate(tcx, symbol, cnum), + info.kind, + )); + } + }); + symbols } diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index c52269805c46f..2e42272805682 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -94,7 +94,7 @@ fn search_for_metadata<'a>( .map_err(|e| format!("failed to read {} section in '{}': {}", section, path.display(), e)) } -fn create_object_file(sess: &Session) -> Option> { +pub(crate) fn create_object_file(sess: &Session) -> Option> { let endianness = match sess.target.options.endian { Endian::Little => Endianness::Little, Endian::Big => Endianness::Big, diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 765bd877db169..56159cc2e08c5 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -9,7 +9,7 @@ use rustc_hir::Node; use rustc_index::vec::IndexVec; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::exported_symbols::{ - metadata_symbol_name, ExportedSymbol, SymbolExportLevel, + metadata_symbol_name, ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel, }; use rustc_middle::ty::query::{ExternProviders, Providers}; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; @@ -42,7 +42,7 @@ pub fn crates_export_threshold(crate_types: &[CrateType]) -> SymbolExportLevel { } } -fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap { +fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap { assert_eq!(cnum, LOCAL_CRATE); if !tcx.sess.opts.output_types.should_codegen() { @@ -124,17 +124,38 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap< } else { symbol_export_level(tcx, def_id.to_def_id()) }; + let codegen_attrs = tcx.codegen_fn_attrs(def_id.to_def_id()); debug!( "EXPORTED SYMBOL (local): {} ({:?})", tcx.symbol_name(Instance::mono(tcx, def_id.to_def_id())), export_level ); - (def_id.to_def_id(), export_level) + (def_id.to_def_id(), SymbolExportInfo { + level: export_level, + kind: if tcx.is_static(def_id.to_def_id()) { + if codegen_attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) { + SymbolExportKind::Tls + } else { + SymbolExportKind::Data + } + } else { + SymbolExportKind::Text + }, + used: codegen_attrs.flags.contains(CodegenFnAttrFlags::USED) + || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER), + }) }) .collect(); if let Some(id) = tcx.proc_macro_decls_static(()) { - reachable_non_generics.insert(id.to_def_id(), SymbolExportLevel::C); + reachable_non_generics.insert( + id.to_def_id(), + SymbolExportInfo { + level: SymbolExportLevel::C, + kind: SymbolExportKind::Data, + used: false, + }, + ); } reachable_non_generics @@ -143,8 +164,8 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap< fn is_reachable_non_generic_provider_local(tcx: TyCtxt<'_>, def_id: DefId) -> bool { let export_threshold = threshold(tcx); - if let Some(&level) = tcx.reachable_non_generics(def_id.krate).get(&def_id) { - level.is_below_threshold(export_threshold) + if let Some(&info) = tcx.reachable_non_generics(def_id.krate).get(&def_id) { + info.level.is_below_threshold(export_threshold) } else { false } @@ -157,7 +178,7 @@ fn is_reachable_non_generic_provider_extern(tcx: TyCtxt<'_>, def_id: DefId) -> b fn exported_symbols_provider_local<'tcx>( tcx: TyCtxt<'tcx>, cnum: CrateNum, -) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportLevel)] { +) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] { assert_eq!(cnum, LOCAL_CRATE); if !tcx.sess.opts.output_types.should_codegen() { @@ -167,13 +188,20 @@ fn exported_symbols_provider_local<'tcx>( let mut symbols: Vec<_> = tcx .reachable_non_generics(LOCAL_CRATE) .iter() - .map(|(&def_id, &level)| (ExportedSymbol::NonGeneric(def_id), level)) + .map(|(&def_id, &info)| (ExportedSymbol::NonGeneric(def_id), info)) .collect(); if tcx.entry_fn(()).is_some() { let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, "main")); - symbols.push((exported_symbol, SymbolExportLevel::C)); + symbols.push(( + exported_symbol, + SymbolExportInfo { + level: SymbolExportLevel::C, + kind: SymbolExportKind::Text, + used: false, + }, + )); } if tcx.allocator_kind(()).is_some() { @@ -181,7 +209,14 @@ fn exported_symbols_provider_local<'tcx>( let symbol_name = format!("__rust_{}", method.name); let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name)); - symbols.push((exported_symbol, SymbolExportLevel::Rust)); + symbols.push(( + exported_symbol, + SymbolExportInfo { + level: SymbolExportLevel::Rust, + kind: SymbolExportKind::Text, + used: false, + }, + )); } } @@ -194,7 +229,14 @@ fn exported_symbols_provider_local<'tcx>( symbols.extend(PROFILER_WEAK_SYMBOLS.iter().map(|sym| { let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, sym)); - (exported_symbol, SymbolExportLevel::C) + ( + exported_symbol, + SymbolExportInfo { + level: SymbolExportLevel::C, + kind: SymbolExportKind::Data, + used: false, + }, + ) })); } @@ -204,7 +246,14 @@ fn exported_symbols_provider_local<'tcx>( symbols.extend(MSAN_WEAK_SYMBOLS.iter().map(|sym| { let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, sym)); - (exported_symbol, SymbolExportLevel::C) + ( + exported_symbol, + SymbolExportInfo { + level: SymbolExportLevel::C, + kind: SymbolExportKind::Data, + used: false, + }, + ) })); } @@ -212,7 +261,14 @@ fn exported_symbols_provider_local<'tcx>( let symbol_name = metadata_symbol_name(tcx); let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name)); - symbols.push((exported_symbol, SymbolExportLevel::Rust)); + symbols.push(( + exported_symbol, + SymbolExportInfo { + level: SymbolExportLevel::Rust, + kind: SymbolExportKind::Data, + used: false, + }, + )); } if tcx.sess.opts.share_generics() && tcx.local_crate_exports_generics() { @@ -245,7 +301,14 @@ fn exported_symbols_provider_local<'tcx>( MonoItem::Fn(Instance { def: InstanceDef::Item(def), substs }) => { if substs.non_erasable_generics().next().is_some() { let symbol = ExportedSymbol::Generic(def.did, substs); - symbols.push((symbol, SymbolExportLevel::Rust)); + symbols.push(( + symbol, + SymbolExportInfo { + level: SymbolExportLevel::Rust, + kind: SymbolExportKind::Text, + used: false, + }, + )); } } MonoItem::Fn(Instance { def: InstanceDef::DropGlue(_, Some(ty)), substs }) => { @@ -254,7 +317,14 @@ fn exported_symbols_provider_local<'tcx>( substs.non_erasable_generics().next(), Some(GenericArgKind::Type(ty)) ); - symbols.push((ExportedSymbol::DropGlue(ty), SymbolExportLevel::Rust)); + symbols.push(( + ExportedSymbol::DropGlue(ty), + SymbolExportInfo { + level: SymbolExportLevel::Rust, + kind: SymbolExportKind::Text, + used: false, + }, + )); } _ => { // Any other symbols don't qualify for sharing diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 92c4ab7eb8627..5ef0b072d9427 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -23,7 +23,7 @@ use rustc_incremental::{ }; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; -use rustc_middle::middle::exported_symbols::SymbolExportLevel; +use rustc_middle::middle::exported_symbols::SymbolExportInfo; use rustc_middle::ty::TyCtxt; use rustc_session::cgu_reuse_tracker::CguReuseTracker; use rustc_session::config::{self, CrateType, Lto, OutputFilenames, OutputType}; @@ -304,7 +304,7 @@ pub type TargetMachineFactoryFn = Arc< + Sync, >; -pub type ExportedSymbols = FxHashMap>>; +pub type ExportedSymbols = FxHashMap>>; /// Additional resources used by optimize_and_codegen (not module specific) #[derive(Clone)] diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 7933afb50e8ce..019c9c179d8e1 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -801,6 +801,12 @@ impl CrateInfo { .iter() .map(|&c| (c, crate::back::linker::exported_symbols(tcx, c))) .collect(); + let linked_symbols = tcx + .sess + .crate_types() + .iter() + .map(|&c| (c, crate::back::linker::linked_symbols(tcx, c))) + .collect(); let local_crate_name = tcx.crate_name(LOCAL_CRATE); let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID); let subsystem = tcx.sess.first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem); @@ -834,6 +840,7 @@ impl CrateInfo { let mut info = CrateInfo { target_cpu, exported_symbols, + linked_symbols, local_crate_name, compiler_builtins: None, profiler_runtime: None, diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 5273b6cc83725..d430800220930 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -28,6 +28,7 @@ use rustc_hir::def_id::CrateNum; use rustc_hir::LangItem; use rustc_middle::dep_graph::WorkProduct; use rustc_middle::middle::dependency_format::Dependencies; +use rustc_middle::middle::exported_symbols::SymbolExportKind; use rustc_middle::ty::query::{ExternProviders, Providers}; use rustc_serialize::{opaque, Decodable, Decoder, Encoder}; use rustc_session::config::{CrateType, OutputFilenames, OutputType, RUST_CGU_EXT}; @@ -141,6 +142,7 @@ impl From<&cstore::NativeLib> for NativeLib { pub struct CrateInfo { pub target_cpu: String, pub exported_symbols: FxHashMap>, + pub linked_symbols: FxHashMap>, pub local_crate_name: Symbol, pub compiler_builtins: Option, pub profiler_runtime: Option, diff --git a/compiler/rustc_codegen_ssa/src/mono_item.rs b/compiler/rustc_codegen_ssa/src/mono_item.rs index 5414c619dcbca..5006a2157fcae 100644 --- a/compiler/rustc_codegen_ssa/src/mono_item.rs +++ b/compiler/rustc_codegen_ssa/src/mono_item.rs @@ -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>(&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(); diff --git a/compiler/rustc_codegen_ssa/src/traits/asm.rs b/compiler/rustc_codegen_ssa/src/traits/asm.rs index 11111a7974410..c2ae74b18d81e 100644 --- a/compiler/rustc_codegen_ssa/src/traits/asm.rs +++ b/compiler/rustc_codegen_ssa/src/traits/asm.rs @@ -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], ); diff --git a/compiler/rustc_codegen_ssa/src/traits/mod.rs b/compiler/rustc_codegen_ssa/src/traits/mod.rs index c529fbbf518b6..396768e0a42d0 100644 --- a/compiler/rustc_codegen_ssa/src/traits/mod.rs +++ b/compiler/rustc_codegen_ssa/src/traits/mod.rs @@ -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> diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 15118073b3343..a2ceb69bd8dac 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2391,8 +2391,12 @@ pub enum InlineAsmOperand<'hir> { Const { anon_const: AnonConst, }, - Sym { - expr: Expr<'hir>, + SymFn { + anon_const: AnonConst, + }, + SymStatic { + path: QPath<'hir>, + def_id: DefId, }, } @@ -2403,7 +2407,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, } } diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 1b40f3d390ee5..445b856e513dc 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -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); diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index b3042c61002c4..27f07a479b1b0 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -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) => { diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 51739df067f9d..3ed4396d1e955 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1835,3 +1835,9 @@ extern "C" void LLVMRustContextConfigureDiagnosticHandler( unwrap(C)->setDiagnosticHandler(std::make_unique( DiagnosticHandlerCallback, DiagnosticHandlerContext, RemarkAllPasses, Passes)); } + +extern "C" void LLVMRustGetMangledName(LLVMValueRef V, RustStringRef Str) { + RawRustStringOstream OS(Str); + GlobalValue *GV = unwrap(V); + Mangler().getNameWithPrefix(OS, GV, true); +} diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 3402acccf3f92..6a77d9a0766bd 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -22,7 +22,7 @@ use rustc_hir::lang_items; use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::arena::ArenaAllocatable; use rustc_middle::metadata::ModChild; -use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; +use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; use rustc_middle::middle::stability::DeprecationEntry; use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState}; use rustc_middle::thir; @@ -1409,7 +1409,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { fn exported_symbols( self, tcx: TyCtxt<'tcx>, - ) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportLevel)] { + ) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] { tcx.arena.alloc_from_iter(self.root.exported_symbols.decode((self, tcx))) } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 63bf929fb8639..b3a7dabdc20b2 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -190,9 +190,9 @@ provide! { <'tcx> tcx, def_id, other, cdata, let reachable_non_generics = tcx .exported_symbols(cdata.cnum) .iter() - .filter_map(|&(exported_symbol, export_level)| { + .filter_map(|&(exported_symbol, export_info)| { if let ExportedSymbol::NonGeneric(def_id) = exported_symbol { - Some((def_id, export_level)) + Some((def_id, export_info)) } else { None } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 6c758b8e5b633..9c94dca9ecde2 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -21,7 +21,7 @@ use rustc_index::vec::Idx; use rustc_middle::hir::nested_filter; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::{ - metadata_symbol_name, ExportedSymbol, SymbolExportLevel, + metadata_symbol_name, ExportedSymbol, SymbolExportInfo, }; use rustc_middle::mir::interpret; use rustc_middle::thir; @@ -1844,8 +1844,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // definition (as that's not defined in this crate). fn encode_exported_symbols( &mut self, - exported_symbols: &[(ExportedSymbol<'tcx>, SymbolExportLevel)], - ) -> Lazy<[(ExportedSymbol<'tcx>, SymbolExportLevel)]> { + exported_symbols: &[(ExportedSymbol<'tcx>, SymbolExportInfo)], + ) -> Lazy<[(ExportedSymbol<'tcx>, SymbolExportInfo)]> { empty_proc_macro!(self); // The metadata symbol name is special. It should not show up in // downstream crates. diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 15e8693d71282..c0b7a787b80e0 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -13,7 +13,7 @@ use rustc_hir::definitions::DefKey; use rustc_hir::lang_items; use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec}; use rustc_middle::metadata::ModChild; -use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; +use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; use rustc_middle::mir; use rustc_middle::thir; use rustc_middle::ty::fast_reject::SimplifiedType; @@ -218,7 +218,7 @@ crate struct CrateRoot<'tcx> { tables: LazyTables<'tcx>, - exported_symbols: Lazy!([(ExportedSymbol<'tcx>, SymbolExportLevel)]), + exported_symbols: Lazy!([(ExportedSymbol<'tcx>, SymbolExportInfo)]), syntax_contexts: SyntaxContextTable, expn_data: ExpnDataTable, diff --git a/compiler/rustc_middle/src/middle/exported_symbols.rs b/compiler/rustc_middle/src/middle/exported_symbols.rs index 5ea78e087f845..631fd09ec4cf6 100644 --- a/compiler/rustc_middle/src/middle/exported_symbols.rs +++ b/compiler/rustc_middle/src/middle/exported_symbols.rs @@ -21,6 +21,23 @@ impl SymbolExportLevel { } } +/// Kind of exported symbols. +#[derive(Eq, PartialEq, Debug, Copy, Clone, Encodable, Decodable, HashStable)] +pub enum SymbolExportKind { + Text, + Data, + Tls, +} + +/// The `SymbolExportInfo` of a symbols specifies symbol-related information +/// that is relevant to code generation and linking. +#[derive(Eq, PartialEq, Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)] +pub struct SymbolExportInfo { + pub level: SymbolExportLevel, + pub kind: SymbolExportKind, + pub used: bool, +} + #[derive(Eq, PartialEq, Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)] pub enum ExportedSymbol<'tcx> { NonGeneric(DefId), diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index f38ade1076eac..e6816fb0d92af 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1352,7 +1352,7 @@ rustc_queries! { // Does not include external symbols that don't have a corresponding DefId, // like the compiler-generated `main` function and so on. query reachable_non_generics(_: CrateNum) - -> DefIdMap { + -> DefIdMap { storage(ArenaCacheSelector<'tcx>) desc { "looking up the exported symbols of a crate" } separate_provide_extern @@ -1668,7 +1668,7 @@ rustc_queries! { /// correspond to a publicly visible symbol in `cnum` machine code. /// - The `exported_symbols` sets of different crates do not intersect. query exported_symbols(_: CrateNum) - -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportLevel)] { + -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] { desc { "exported_symbols" } separate_provide_extern } diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index b31cc17a9594d..99f9e74b19072 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -526,7 +526,8 @@ pub enum InlineAsmOperand<'tcx> { span: Span, }, SymFn { - expr: ExprId, + value: Const<'tcx>, + span: Span, }, SymStatic { def_id: DefId, diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 451fa46638771..ea38d8d667966 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -129,8 +129,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 { @@ -139,6 +138,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: _ } => {} } } diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index 9e48c569c253a..6ff061a820ebf 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -3,7 +3,7 @@ use crate::infer::canonical::{self, Canonical}; use crate::lint::LintLevelMap; use crate::metadata::ModChild; use crate::middle::codegen_fn_attrs::CodegenFnAttrs; -use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; +use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; use crate::middle::lib_features::LibFeatures; use crate::middle::privacy::AccessLevels; use crate::middle::region; diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index a8f623dbe4693..3537f39d19c26 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -430,9 +430,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }), } } - thir::InlineAsmOperand::SymFn { expr } => mir::InlineAsmOperand::SymFn { - value: Box::new(this.as_constant(&this.thir[expr])), - }, + thir::InlineAsmOperand::SymFn { value, span } => { + mir::InlineAsmOperand::SymFn { + value: Box::new(Constant { + span, + user_ty: None, + literal: value.into(), + }), + } + } thir::InlineAsmOperand::SymStatic { def_id } => { mir::InlineAsmOperand::SymStatic { def_id } } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index e6afc89baa03b..82da0bc9f362d 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -462,91 +462,48 @@ 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 { - reg, - late, - ref in_expr, - ref out_expr, - } => 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, - 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 = ty::Const::from_anon_const(self.tcx, anon_const_def_id); - let span = self.tcx.hir().span(anon_const.hir_id); - - InlineAsmOperand::Const { value, span } - } - hir::InlineAsmOperand::Sym { ref expr } => { - let hir::ExprKind::Path(ref qpath) = expr.kind else { - span_bug!( - expr.span, - "asm `sym` operand should be a path, found {:?}", - expr.kind - ); - }; - 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), - }), - } - } - - Res::Def(DefKind::Static(_), def_id) => { - InlineAsmOperand::SymStatic { def_id } - } - - _ => { - self.tcx.sess.span_err( - expr.span, - "asm `sym` operand must point to a fn or static", - ); - - // Not a real fn, but we're not reaching codegen anyways... - ty = self.tcx.ty_error(); - InlineAsmOperand::SymFn { - expr: self.thir.exprs.push(Expr { - ty, - temp_lifetime, - span: expr.span, - kind: ExprKind::zero_sized_literal(None), - }), - } - } - } + 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 { + 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 = ty::Const::from_anon_const(self.tcx, anon_const_def_id); + let span = self.tcx.hir().span(anon_const.hir_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 = ty::Const::from_anon_const(self.tcx, anon_const_def_id); + let span = self.tcx.hir().span(anon_const.hir_id); + + InlineAsmOperand::SymFn { value, span } + } + hir::InlineAsmOperand::SymStatic { path: _, def_id } => { + InlineAsmOperand::SymStatic { def_id } + } }) .collect(), options: asm.options, diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 2a659a97db5f9..fdb14e45d981a 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -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 { diff --git a/compiler/rustc_monomorphize/src/partitioning/default.rs b/compiler/rustc_monomorphize/src/partitioning/default.rs index c4ffb19f87a91..02f3efa695c34 100644 --- a/compiler/rustc_monomorphize/src/partitioning/default.rs +++ b/compiler/rustc_monomorphize/src/partitioning/default.rs @@ -5,7 +5,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::definitions::DefPathDataName; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_middle::middle::exported_symbols::SymbolExportLevel; +use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel}; use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, Linkage, Visibility}; use rustc_middle::mir::mono::{InstantiationMode, MonoItem}; use rustc_middle::ty::print::characteristic_def_id_of_type; @@ -554,7 +554,7 @@ fn default_visibility(tcx: TyCtxt<'_>, id: DefId, is_generic: bool) -> Visibilit // C-export level items remain at `Default`, all other internal // items become `Hidden`. match tcx.reachable_non_generics(id.krate).get(&id) { - Some(SymbolExportLevel::C) => Visibility::Default, + Some(SymbolExportInfo { level: SymbolExportLevel::C, .. }) => Visibility::Default, _ => Visibility::Hidden, } } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 5bf6f22b5d064..ca81921faedcc 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -970,7 +970,7 @@ impl<'a> Parser<'a> { } if fixed_crate_name { let fixed_name_sp = ident.span.to(idents.last().unwrap().span); - let mut fixed_name = format!("{}", ident.name); + let mut fixed_name = ident.name.to_string(); for part in idents { fixed_name.push_str(&format!("_{}", part.name)); } diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index c777074df4641..0ceccff7cac52 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -537,6 +537,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); + } _ => (), } } diff --git a/compiler/rustc_passes/src/intrinsicck.rs b/compiler/rustc_passes/src/intrinsicck.rs index 027eac16bad30..7028fc4412648 100644 --- a/compiler/rustc_passes/src/intrinsicck.rs +++ b/compiler/rustc_passes/src/intrinsicck.rs @@ -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> { diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 7298aba7e8763..99ea73fe2fe10 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -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 diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index af78fd5a6f212..e85720952da7a 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -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 { .. } diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index b520e5d04eab9..b65e334261325 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -333,6 +333,11 @@ impl CollectPrivateImplItemsVisitor<'_, '_> { let codegen_attrs = self.tcx.codegen_fn_attrs(def_id); if codegen_attrs.contains_extern_indicator() || codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) + // FIXME(nbdd0121): `#[used]` are marked as reachable here so it's picked up by + // `linked_symbols` in cg_ssa. They won't be exported in binary or cdylib due to their + // `SymbolExportLevel::Rust` export level but may end up being exported in dylibs. + || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED) + || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) { self.worklist.push(def_id); } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 609dbd1fe1b4e..6d051052c80fd 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -621,6 +621,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 + } } } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 6fedabc816cff..b99b76d49ce16 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -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, } } @@ -725,6 +730,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> { @@ -888,7 +910,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { | ConstantItemRibKind(..) | ModuleRibKind(..) | ForwardGenericParamBanRibKind - | ConstParamTyRibKind => { + | ConstParamTyRibKind + | InlineAsmSymRibKind => { return false; } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index a09a225a2b5d7..fb9ee8e47b04b 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -273,6 +273,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> { @@ -2720,6 +2722,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 { @@ -2780,6 +2788,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 { @@ -2844,6 +2868,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. diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index c920c80d1bba1..ead1f0126c465 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1083,20 +1083,31 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let parent_node = hir.get_parent_node(obligation.cause.body_id); let node = hir.find(parent_node); if let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. })) = node - && let body = hir.body(*body_id) - && let hir::ExprKind::Block(blk, _) = &body.value.kind + && let hir::ExprKind::Block(blk, _) = &hir.body(*body_id).value.kind && sig.decl.output.span().overlaps(span) && blk.expr.is_none() - && *trait_pred.self_ty().skip_binder().kind() == ty::Tuple(ty::List::empty()) - // FIXME(estebank): When encountering a method with a trait - // bound not satisfied in the return type with a body that has - // no return, suggest removal of semicolon on last statement. - // Once that is added, close #54771. + && trait_pred.self_ty().skip_binder().is_unit() && let Some(stmt) = blk.stmts.last() - && let hir::StmtKind::Semi(_) = stmt.kind + && let hir::StmtKind::Semi(expr) = stmt.kind + // Only suggest this if the expression behind the semicolon implements the predicate + && let Some(typeck_results) = self.in_progress_typeck_results + && let Some(ty) = typeck_results.borrow().expr_ty_opt(expr) + && self.predicate_may_hold(&self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred, ty)) { - let sp = self.tcx.sess.source_map().end_point(stmt.span); - err.span_label(sp, "consider removing this semicolon"); + err.span_label( + expr.span, + &format!( + "this expression has type `{}`, which implements `{}`", + ty, + trait_pred.print_modifiers_and_trait_path() + ) + ); + err.span_suggestion( + self.tcx.sess.source_map().end_point(stmt.span), + "remove this semicolon", + String::new(), + Applicability::MachineApplicable + ); return true; } false diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 669521bc4725e..fadb782f89368 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -2535,12 +2535,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) { diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 1cc1460750a23..f6a5243274cd2 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -936,7 +936,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { err.span_suggestion_short( span_semi, - "consider removing this semicolon", + "remove this semicolon", String::new(), Applicability::MachineApplicable, ); diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 19d52f430fcd5..fbd86b8e43198 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -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(), }, diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index 785538ab0df3d..fa06ec09fce22 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -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, }) => { diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index 055e391d7069e..2bcf2d3b2ed71 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -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 { .. } => {} } } } diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 00dc7da275a43..52eaee8e9280c 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -1172,9 +1172,9 @@ def check_vendored_status(self): """Check that vendoring is configured properly""" vendor_dir = os.path.join(self.rust_root, 'vendor') if 'SUDO_USER' in os.environ and not self.use_vendored_sources: - if os.environ.get('USER') != os.environ['SUDO_USER']: + if os.getuid() == 0: self.use_vendored_sources = True - print('info: looks like you are running this command under `sudo`') + print('info: looks like you\'re trying to run this command as root') print(' and so in order to preserve your $HOME this will now') print(' use vendored sources by default.') if not os.path.exists(vendor_dir): diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 32def67ed65e3..b3c4a52c414b2 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -31,18 +31,20 @@ All tier 1 targets with host tools support the full standard library. target | notes -------|------- `aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.2, glibc 2.17+) [^missing-stack-probes] -`i686-pc-windows-gnu` | 32-bit MinGW (Windows 7+) -`i686-pc-windows-msvc` | 32-bit MSVC (Windows 7+) +`i686-pc-windows-gnu` | 32-bit MinGW (Windows 7+) [^windows-support] +`i686-pc-windows-msvc` | 32-bit MSVC (Windows 7+) [^windows-support] `i686-unknown-linux-gnu` | 32-bit Linux (kernel 2.6.32+, glibc 2.11+) `x86_64-apple-darwin` | 64-bit macOS (10.7+, Lion+) -`x86_64-pc-windows-gnu` | 64-bit MinGW (Windows 7+) -`x86_64-pc-windows-msvc` | 64-bit MSVC (Windows 7+) +`x86_64-pc-windows-gnu` | 64-bit MinGW (Windows 7+) [^windows-support] +`x86_64-pc-windows-msvc` | 64-bit MSVC (Windows 7+) [^windows-support] `x86_64-unknown-linux-gnu` | 64-bit Linux (kernel 2.6.32+, glibc 2.11+) [^missing-stack-probes]: Stack probes support is missing on `aarch64-unknown-linux-gnu`, but it's planned to be implemented in the near future. The implementation is tracked on [issue #77071][77071]. +[^windows-support]: Only Windows 10 currently undergoes automated testing. Earlier versions of Windows rely on testing and support from the community. + [77071]: https://github.com/rust-lang/rust/issues/77071 ## Tier 1 diff --git a/src/test/assembly/asm/global_asm.rs b/src/test/assembly/asm/global_asm.rs index 0358bc6d27c29..ae47f7ac391cc 100644 --- a/src/test/assembly/asm/global_asm.rs +++ b/src/test/assembly/asm/global_asm.rs @@ -2,14 +2,24 @@ // 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); diff --git a/src/test/codegen/asm-may_unwind.rs b/src/test/codegen/asm-may_unwind.rs index 3b34d79c3a946..bf4202764a7ec 100644 --- a/src/test/codegen/asm-may_unwind.rs +++ b/src/test/codegen/asm-may_unwind.rs @@ -18,10 +18,23 @@ impl Drop for Foo { } } -// CHECK-LABEL: @may_unwind +// CHECK-LABEL: @asm_may_unwind #[no_mangle] -pub unsafe fn may_unwind() { +pub unsafe fn asm_may_unwind() { let _m = Foo; // CHECK: invoke void asm sideeffect alignstack inteldialect unwind "" asm!("", options(may_unwind)); } + +// CHECK-LABEL: @asm_with_result_may_unwind +#[no_mangle] +pub unsafe fn asm_with_result_may_unwind() -> u64 { + let _m = Foo; + let res: u64; + // CHECK: [[RES:%[0-9]+]] = invoke i64 asm sideeffect alignstack inteldialect unwind + // CHECK-NEXT: to label %[[NORMALBB:[a-b0-9]+]] + asm!("mov {}, 1", out(reg) res, options(may_unwind)); + // CHECK: [[NORMALBB]]: + // CHECK: ret i64 [[RES:%[0-9]+]] + res +} diff --git a/src/test/run-make-fulldeps/reproducible-build/linker.rs b/src/test/run-make-fulldeps/reproducible-build/linker.rs index 998d1f328596c..b58614c8b4e1f 100644 --- a/src/test/run-make-fulldeps/reproducible-build/linker.rs +++ b/src/test/run-make-fulldeps/reproducible-build/linker.rs @@ -25,6 +25,12 @@ fn main() { let mut contents = Vec::new(); File::open(path).unwrap().read_to_end(&mut contents).unwrap(); + // This file is produced during linking in a temporary directory. + let arg = if arg.ends_with("/symbols.o") { + "symbols.o" + } else { + &*arg + }; out.push_str(&format!("{}: {}\n", arg, hash(&contents))); } diff --git a/src/test/run-make/issue-47384/Makefile b/src/test/run-make/issue-47384/Makefile new file mode 100644 index 0000000000000..d3d48966b8547 --- /dev/null +++ b/src/test/run-make/issue-47384/Makefile @@ -0,0 +1,12 @@ +-include ../../run-make-fulldeps/tools.mk + +# ignore-windows +# ignore-cross-compile + +all: main.rs + $(RUSTC) --crate-type lib lib.rs + $(RUSTC) --crate-type cdylib -Clink-args="-Tlinker.ld" main.rs + # Ensure `#[used]` and `KEEP`-ed section is there + objdump -s -j".static" $(TMPDIR)/libmain.so + # Ensure `#[no_mangle]` symbol is there + nm $(TMPDIR)/libmain.so | $(CGREP) bar diff --git a/src/test/run-make/issue-47384/lib.rs b/src/test/run-make/issue-47384/lib.rs new file mode 100644 index 0000000000000..99508bcdaf314 --- /dev/null +++ b/src/test/run-make/issue-47384/lib.rs @@ -0,0 +1,12 @@ +mod foo { + #[link_section = ".rodata.STATIC"] + #[used] + static STATIC: [u32; 10] = [1; 10]; +} + +mod bar { + #[no_mangle] + extern "C" fn bar() -> i32 { + 0 + } +} diff --git a/src/test/run-make/issue-47384/linker.ld b/src/test/run-make/issue-47384/linker.ld new file mode 100644 index 0000000000000..2e70acab3f496 --- /dev/null +++ b/src/test/run-make/issue-47384/linker.ld @@ -0,0 +1,7 @@ +SECTIONS +{ + .static : ALIGN(4) + { + KEEP(*(.rodata.STATIC)); + } +} diff --git a/src/test/run-make/issue-47384/main.rs b/src/test/run-make/issue-47384/main.rs new file mode 100644 index 0000000000000..02572632517ec --- /dev/null +++ b/src/test/run-make/issue-47384/main.rs @@ -0,0 +1 @@ +extern crate lib; diff --git a/src/test/ui/asm/aarch64/parse-error.rs b/src/test/ui/asm/aarch64/parse-error.rs index 59d6b28d0fd99..cbc93cd3f7530 100644 --- a/src/test/ui/asm/aarch64/parse-error.rs +++ b/src/test/ui/asm/aarch64/parse-error.rs @@ -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)); diff --git a/src/test/ui/asm/aarch64/parse-error.stderr b/src/test/ui/asm/aarch64/parse-error.stderr index 3f705ba5b64c2..f2013046cda42 100644 --- a/src/test/ui/asm/aarch64/parse-error.stderr +++ b/src/test/ui/asm/aarch64/parse-error.stderr @@ -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 diff --git a/src/test/ui/asm/aarch64/type-check-2.rs b/src/test/ui/asm/aarch64/type-check-2.rs index 1b91f5d0678b4..9e53a2e0c5230 100644 --- a/src/test/ui/asm/aarch64/type-check-2.rs +++ b/src/test/ui/asm/aarch64/type-check-2.rs @@ -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 diff --git a/src/test/ui/asm/aarch64/type-check-2.stderr b/src/test/ui/asm/aarch64/type-check-2.stderr index beb301c7c7417..6047bed6e7802 100644 --- a/src/test/ui/asm/aarch64/type-check-2.stderr +++ b/src/test/ui/asm/aarch64/type-check-2.stderr @@ -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` 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); - | ^ + | ^^^^^ is an `i32` + | + = help: `sym` operands must refer to either a function or a static -error: asm `sym` operand must point to a fn or static - --> $DIR/type-check-2.rs:43:24 +error: invalid `sym` operand + --> $DIR/type-check-2.rs:92:19 + | +LL | global_asm!("{}", sym C); + | ^^^^^ is an `i32` | -LL | asm!("{}", sym x); - | ^ + = 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 diff --git a/src/test/ui/asm/type-check-1.rs b/src/test/ui/asm/type-check-1.rs index 695fd27efd4e3..9f0121e11b447 100644 --- a/src/test/ui/asm/type-check-1.rs +++ b/src/test/ui/asm/type-check-1.rs @@ -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() { + asm!("{}", sym generic::); + //~^ generic parameters may not be used in const operations +} + // Const operands must be integers and must be constants. global_asm!("{}", const 0); diff --git a/src/test/ui/asm/type-check-1.stderr b/src/test/ui/asm/type-check-1.stderr index d774c78ca9a72..7dba69fb74592 100644 --- a/src/test/ui/asm/type-check-1.stderr +++ b/src/test/ui/asm/type-check-1.stderr @@ -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::); + | ^ 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`. diff --git a/src/test/ui/asm/x86_64/parse-error.rs b/src/test/ui/asm/x86_64/parse-error.rs index f0629f9f51cdf..9aeb6b2853fba 100644 --- a/src/test/ui/asm/x86_64/parse-error.rs +++ b/src/test/ui/asm/x86_64/parse-error.rs @@ -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)); diff --git a/src/test/ui/asm/x86_64/parse-error.stderr b/src/test/ui/asm/x86_64/parse-error.stderr index 194cd66a66e96..1fd317a96a8a6 100644 --- a/src/test/ui/asm/x86_64/parse-error.stderr +++ b/src/test/ui/asm/x86_64/parse-error.stderr @@ -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 diff --git a/src/test/ui/asm/x86_64/type-check-2.rs b/src/test/ui/asm/x86_64/type-check-2.rs index f95aebb78b5f8..eb87ea91085f0 100644 --- a/src/test/ui/asm/x86_64/type-check-2.rs +++ b/src/test/ui/asm/x86_64/type-check-2.rs @@ -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 diff --git a/src/test/ui/asm/x86_64/type-check-2.stderr b/src/test/ui/asm/x86_64/type-check-2.stderr index cec750fdf9a55..cb3960acdf9d3 100644 --- a/src/test/ui/asm/x86_64/type-check-2.stderr +++ b/src/test/ui/asm/x86_64/type-check-2.stderr @@ -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` 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); - | ^ + | ^^^^^ is an `i32` + | + = help: `sym` operands must refer to either a function or a static -error: asm `sym` operand must point to a fn or static - --> $DIR/type-check-2.rs:39:24 +error: invalid `sym` operand + --> $DIR/type-check-2.rs:88:19 + | +LL | global_asm!("{}", sym C); + | ^^^^^ is an `i32` | -LL | asm!("{}", sym x); - | ^ + = 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 diff --git a/src/test/ui/block-result/consider-removing-last-semi.stderr b/src/test/ui/block-result/consider-removing-last-semi.stderr index 99a367bfccdcd..2412dcd32f79a 100644 --- a/src/test/ui/block-result/consider-removing-last-semi.stderr +++ b/src/test/ui/block-result/consider-removing-last-semi.stderr @@ -7,7 +7,7 @@ LL | pub fn f() -> String { | implicitly returns `()` as its body has no tail or `return` expression LL | 0u8; LL | "bla".to_string(); - | - help: consider removing this semicolon + | - help: remove this semicolon error[E0308]: mismatched types --> $DIR/consider-removing-last-semi.rs:8:15 @@ -18,7 +18,7 @@ LL | pub fn g() -> String { | implicitly returns `()` as its body has no tail or `return` expression LL | "this won't work".to_string(); LL | "removeme".to_string(); - | - help: consider removing this semicolon + | - help: remove this semicolon error[E0308]: mismatched types --> $DIR/consider-removing-last-semi.rs:13:25 @@ -29,7 +29,7 @@ LL | pub fn macro_tests() -> u32 { | implicitly returns `()` as its body has no tail or `return` expression ... LL | mac!(); - | - help: consider removing this semicolon + | - help: remove this semicolon error: aborting due to 3 previous errors diff --git a/src/test/ui/block-result/issue-11714.stderr b/src/test/ui/block-result/issue-11714.stderr index 61991643a4a56..5b8d96fd4ebe2 100644 --- a/src/test/ui/block-result/issue-11714.stderr +++ b/src/test/ui/block-result/issue-11714.stderr @@ -7,7 +7,7 @@ LL | fn blah() -> i32 { | implicitly returns `()` as its body has no tail or `return` expression ... LL | ; - | - help: consider removing this semicolon + | - help: remove this semicolon error: aborting due to previous error diff --git a/src/test/ui/block-result/issue-13428.stderr b/src/test/ui/block-result/issue-13428.stderr index 2f24679cc9591..a33448edff2bc 100644 --- a/src/test/ui/block-result/issue-13428.stderr +++ b/src/test/ui/block-result/issue-13428.stderr @@ -15,7 +15,7 @@ LL | fn bar() -> String { | implicitly returns `()` as its body has no tail or `return` expression LL | "foobar".to_string() LL | ; - | - help: consider removing this semicolon + | - help: remove this semicolon error: aborting due to 2 previous errors diff --git a/src/test/ui/closures/old-closure-expression-remove-semicolon.fixed b/src/test/ui/closures/old-closure-expression-remove-semicolon.fixed index 5629d4b6e6e5f..623e917da07e8 100644 --- a/src/test/ui/closures/old-closure-expression-remove-semicolon.fixed +++ b/src/test/ui/closures/old-closure-expression-remove-semicolon.fixed @@ -7,6 +7,6 @@ fn foo() -> i32 { fn main() { let _x: i32 = { //~^ ERROR mismatched types - foo() //~ HELP consider removing this semicolon + foo() //~ HELP remove this semicolon }; } diff --git a/src/test/ui/closures/old-closure-expression-remove-semicolon.rs b/src/test/ui/closures/old-closure-expression-remove-semicolon.rs index 33f11b50afca2..4974b08664945 100644 --- a/src/test/ui/closures/old-closure-expression-remove-semicolon.rs +++ b/src/test/ui/closures/old-closure-expression-remove-semicolon.rs @@ -7,6 +7,6 @@ fn foo() -> i32 { fn main() { let _x: i32 = { //~^ ERROR mismatched types - foo(); //~ HELP consider removing this semicolon + foo(); //~ HELP remove this semicolon }; } diff --git a/src/test/ui/closures/old-closure-expression-remove-semicolon.stderr b/src/test/ui/closures/old-closure-expression-remove-semicolon.stderr index ab7983dc9e487..9b73ce4fee346 100644 --- a/src/test/ui/closures/old-closure-expression-remove-semicolon.stderr +++ b/src/test/ui/closures/old-closure-expression-remove-semicolon.stderr @@ -5,7 +5,7 @@ LL | let _x: i32 = { | ___________________^ LL | | LL | | foo(); - | | - help: consider removing this semicolon + | | - help: remove this semicolon LL | | }; | |_____^ expected `i32`, found `()` diff --git a/src/test/ui/coercion/coercion-missing-tail-expected-type.stderr b/src/test/ui/coercion/coercion-missing-tail-expected-type.stderr index df1fb58e25a02..a4843bca58c99 100644 --- a/src/test/ui/coercion/coercion-missing-tail-expected-type.stderr +++ b/src/test/ui/coercion/coercion-missing-tail-expected-type.stderr @@ -6,7 +6,7 @@ LL | fn plus_one(x: i32) -> i32 { | | | implicitly returns `()` as its body has no tail or `return` expression LL | x + 1; - | - help: consider removing this semicolon + | - help: remove this semicolon error[E0308]: mismatched types --> $DIR/coercion-missing-tail-expected-type.rs:8:13 @@ -16,7 +16,7 @@ LL | fn foo() -> Result { | | | implicitly returns `()` as its body has no tail or `return` expression LL | Ok(1); - | - help: consider removing this semicolon + | - help: remove this semicolon | = note: expected enum `Result` found unit type `()` diff --git a/src/test/ui/issues/issue-6458-4.stderr b/src/test/ui/issues/issue-6458-4.stderr index 0cf82d37d5d0b..d6e74d10e03c9 100644 --- a/src/test/ui/issues/issue-6458-4.stderr +++ b/src/test/ui/issues/issue-6458-4.stderr @@ -6,7 +6,7 @@ LL | fn foo(b: bool) -> Result { | | | implicitly returns `()` as its body has no tail or `return` expression LL | Err("bar".to_string()); - | - help: consider removing this semicolon + | - help: remove this semicolon | = note: expected enum `Result` found unit type `()` diff --git a/src/test/ui/liveness/liveness-return-last-stmt-semi.stderr b/src/test/ui/liveness/liveness-return-last-stmt-semi.stderr index 0b33d8d0a2b23..82d136bd318d8 100644 --- a/src/test/ui/liveness/liveness-return-last-stmt-semi.stderr +++ b/src/test/ui/liveness/liveness-return-last-stmt-semi.stderr @@ -14,7 +14,7 @@ LL | fn bar(x: u32) -> u32 { | | | implicitly returns `()` as its body has no tail or `return` expression LL | x * 2; - | - help: consider removing this semicolon + | - help: remove this semicolon error[E0308]: mismatched types --> $DIR/liveness-return-last-stmt-semi.rs:13:19 diff --git a/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.rs b/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.rs index cad7d76c6ab5f..5a17c108ccc13 100644 --- a/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.rs +++ b/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.rs @@ -1,8 +1,25 @@ trait Bar {} -impl Bar for u8 {} + +impl Bar for i32 {} + +struct Qux; + +impl Bar for Qux {} + fn foo() -> impl Bar { - 5; //~^ ERROR the trait bound `(): Bar` is not satisfied + //~^ ERROR the trait bound `(): Bar` is not satisfied + //~| ERROR the trait bound `(): Bar` is not satisfied + //~| HELP the following other types implement trait `Bar`: + 5; + //~^ HELP remove this semicolon +} + +fn bar() -> impl Bar { + //~^ ERROR the trait bound `(): Bar` is not satisfied //~| ERROR the trait bound `(): Bar` is not satisfied + //~| HELP the following other types implement trait `Bar`: + //~| HELP the following other types implement trait `Bar`: + ""; } fn main() {} diff --git a/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.stderr b/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.stderr index 0de765588e5b7..43f8b7c66f07a 100644 --- a/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.stderr +++ b/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.stderr @@ -1,23 +1,58 @@ error[E0277]: the trait bound `(): Bar` is not satisfied - --> $DIR/impl-trait-return-trailing-semicolon.rs:3:13 + --> $DIR/impl-trait-return-trailing-semicolon.rs:9:13 | LL | fn foo() -> impl Bar { | ^^^^^^^^ the trait `Bar` is not implemented for `()` +... LL | 5; - | - consider removing this semicolon + | -- help: remove this semicolon + | | + | this expression has type `{integer}`, which implements `Bar` error[E0277]: the trait bound `(): Bar` is not satisfied - --> $DIR/impl-trait-return-trailing-semicolon.rs:3:22 + --> $DIR/impl-trait-return-trailing-semicolon.rs:9:22 | LL | fn foo() -> impl Bar { | ______________________^ +LL | | +LL | | +LL | | LL | | 5; LL | | LL | | } | |_^ the trait `Bar` is not implemented for `()` | - = help: the trait `Bar` is implemented for `u8` + = help: the following other types implement trait `Bar`: + Qux + i32 + +error[E0277]: the trait bound `(): Bar` is not satisfied + --> $DIR/impl-trait-return-trailing-semicolon.rs:17:13 + | +LL | fn bar() -> impl Bar { + | ^^^^^^^^ the trait `Bar` is not implemented for `()` + | + = help: the following other types implement trait `Bar`: + Qux + i32 + +error[E0277]: the trait bound `(): Bar` is not satisfied + --> $DIR/impl-trait-return-trailing-semicolon.rs:17:22 + | +LL | fn bar() -> impl Bar { + | ______________________^ +LL | | +LL | | +LL | | +LL | | +LL | | ""; +LL | | } + | |_^ the trait `Bar` is not implemented for `()` + | + = help: the following other types implement trait `Bar`: + Qux + i32 -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/suggestions/issue-81098.stderr b/src/test/ui/suggestions/issue-81098.stderr index d62526442e9af..8665f2e70a85c 100644 --- a/src/test/ui/suggestions/issue-81098.stderr +++ b/src/test/ui/suggestions/issue-81098.stderr @@ -27,7 +27,9 @@ LL | fn ok() -> impl core::fmt::Display { | ^^^^^^^^^^^^^^^^^^^^^^^ `()` cannot be formatted with the default formatter LL | LL | 1; - | - consider removing this semicolon + | -- help: remove this semicolon + | | + | this expression has type `{integer}`, which implements `std::fmt::Display` | = help: the trait `std::fmt::Display` is not implemented for `()` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead diff --git a/src/test/ui/suggestions/match-with-different-arm-types-as-stmt-instead-of-expr.stderr b/src/test/ui/suggestions/match-with-different-arm-types-as-stmt-instead-of-expr.stderr index 7dce97468b6dd..60f423a116317 100644 --- a/src/test/ui/suggestions/match-with-different-arm-types-as-stmt-instead-of-expr.stderr +++ b/src/test/ui/suggestions/match-with-different-arm-types-as-stmt-instead-of-expr.stderr @@ -7,7 +7,7 @@ LL | fn not_all_paths(a: &str) -> u32 { | implicitly returns `()` as its body has no tail or `return` expression ... LL | }; - | - help: consider removing this semicolon + | - help: remove this semicolon error[E0308]: `match` arms have incompatible types --> $DIR/match-with-different-arm-types-as-stmt-instead-of-expr.rs:26:14 diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs index a0b2302662e64..9ba9642fcc833 100644 --- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs @@ -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) diff --git a/src/tools/clippy/clippy_lints/src/utils/inspector.rs b/src/tools/clippy/clippy_lints/src/utils/inspector.rs index dc48ea3f4f99d..a04288e0a413e 100644 --- a/src/tools/clippy/clippy_lints/src/utils/inspector.rs +++ b/src/tools/clippy/clippy_lints/src/utils/inspector.rs @@ -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()); + }, + } + } } } }, diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 00594f4d42add..c05317f59b716 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -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), } } },