From a867b8dd1cb48146d24883a26c5fd961c160d84e Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Wed, 9 Feb 2022 00:02:51 +0000 Subject: [PATCH 01/16] Add a test for issue 47384 --- src/test/run-make/issue-47384/Makefile | 12 ++++++++++++ src/test/run-make/issue-47384/lib.rs | 12 ++++++++++++ src/test/run-make/issue-47384/linker.ld | 7 +++++++ src/test/run-make/issue-47384/main.rs | 1 + 4 files changed, 32 insertions(+) create mode 100644 src/test/run-make/issue-47384/Makefile create mode 100644 src/test/run-make/issue-47384/lib.rs create mode 100644 src/test/run-make/issue-47384/linker.ld create mode 100644 src/test/run-make/issue-47384/main.rs 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; From aa8413cd26f1eab00d781893c8e426dbc564eaf1 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sat, 2 Apr 2022 22:27:33 +0100 Subject: [PATCH 02/16] Add `SymbolExportInfo` This is currently a wrapper to `SymbolExportLevel` but it allows later addition of extra information. --- compiler/rustc_codegen_llvm/src/back/lto.rs | 6 +- compiler/rustc_codegen_ssa/src/back/linker.rs | 8 +-- .../src/back/symbol_export.rs | 60 ++++++++++++++----- compiler/rustc_codegen_ssa/src/back/write.rs | 4 +- compiler/rustc_metadata/src/rmeta/decoder.rs | 4 +- .../src/rmeta/decoder/cstore_impl.rs | 4 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 6 +- compiler/rustc_metadata/src/rmeta/mod.rs | 4 +- .../src/middle/exported_symbols.rs | 7 +++ compiler/rustc_middle/src/query/mod.rs | 4 +- compiler/rustc_middle/src/ty/query.rs | 2 +- .../src/partitioning/default.rs | 4 +- 12 files changed, 75 insertions(+), 38 deletions(-) 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_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 3a66bfafaf3f4..a90b8a62c623a 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -1526,8 +1526,8 @@ pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec, crate_type: CrateType) -> Vec 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() { @@ -129,12 +129,17 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap< 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, + }) }) .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 }, + ); } reachable_non_generics @@ -143,8 +148,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 +162,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 +172,16 @@ 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 }, + )); } if tcx.allocator_kind(()).is_some() { @@ -181,7 +189,10 @@ 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 }, + )); } } @@ -194,7 +205,10 @@ 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 }, + ) })); } @@ -204,7 +218,10 @@ 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 }, + ) })); } @@ -212,7 +229,10 @@ 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 }, + )); } if tcx.sess.opts.share_generics() && tcx.local_crate_exports_generics() { @@ -245,7 +265,12 @@ 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, + }, + )); } } MonoItem::Fn(Instance { def: InstanceDef::DropGlue(_, Some(ty)), substs }) => { @@ -254,7 +279,12 @@ 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, + }, + )); } _ => { // 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 d4eaf6389dfe9..7a6e9bfd2b7c6 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_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 046322a42d85b..d7a4547bcc606 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; @@ -1405,7 +1405,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 cd3a1d72d41d2..1a7c458b6a267 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -188,9 +188,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..a605e6dfdc1d3 100644 --- a/compiler/rustc_middle/src/middle/exported_symbols.rs +++ b/compiler/rustc_middle/src/middle/exported_symbols.rs @@ -21,6 +21,13 @@ impl SymbolExportLevel { } } +/// 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, +} + #[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 89761bf4e27a0..97f1d96404b5e 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1355,7 +1355,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 @@ -1672,7 +1672,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/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_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, } } From 08b70292737b6da048ae15b3333b8b5eb1c83b67 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sat, 2 Apr 2022 22:29:59 +0100 Subject: [PATCH 03/16] Make `#[used]` considered reachable --- compiler/rustc_passes/src/reachable.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index b520e5d04eab9..55745248c9389 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -332,6 +332,8 @@ impl CollectPrivateImplItemsVisitor<'_, '_> { // which are currently akin to allocator symbols. let codegen_attrs = self.tcx.codegen_fn_attrs(def_id); if codegen_attrs.contains_extern_indicator() + || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED) + || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) || codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) { self.worklist.push(def_id); From c34473bceaa7cb6a87c20e47f76ff4f282258840 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Tue, 1 Mar 2022 00:50:56 +0000 Subject: [PATCH 04/16] Reimplement lowering of sym operands for asm! so that it also works with global_asm! --- compiler/rustc_ast/src/ast.rs | 16 ++- compiler/rustc_ast/src/mut_visit.rs | 29 ++++- compiler/rustc_ast/src/visit.rs | 19 ++- compiler/rustc_ast_lowering/src/asm.rs | 65 +++++++++- compiler/rustc_ast_pretty/src/pprust/state.rs | 8 +- compiler/rustc_builtin_macros/src/asm.rs | 22 ++-- compiler/rustc_hir/src/hir.rs | 10 +- compiler/rustc_hir/src/intravisit.rs | 21 ++-- compiler/rustc_hir_pretty/src/lib.rs | 11 +- compiler/rustc_middle/src/thir.rs | 3 +- compiler/rustc_middle/src/thir/visit.rs | 4 +- .../rustc_mir_build/src/build/expr/into.rs | 12 +- compiler/rustc_mir_build/src/thir/cx/expr.rs | 119 ++++++------------ compiler/rustc_passes/src/dead.rs | 4 + compiler/rustc_passes/src/intrinsicck.rs | 42 ++++++- compiler/rustc_passes/src/liveness.rs | 10 +- compiler/rustc_passes/src/naked_functions.rs | 4 +- compiler/rustc_resolve/src/diagnostics.rs | 6 + compiler/rustc_resolve/src/late.rs | 27 +++- compiler/rustc_resolve/src/lib.rs | 40 ++++++ compiler/rustc_typeck/src/check/expr.rs | 7 +- compiler/rustc_typeck/src/check/mod.rs | 33 +++-- compiler/rustc_typeck/src/collect/type_of.rs | 3 +- compiler/rustc_typeck/src/expr_use_visitor.rs | 7 +- .../clippy_lints/src/loops/never_loop.rs | 7 +- .../clippy_lints/src/utils/inspector.rs | 23 +++- .../clippy/clippy_utils/src/hir_utils.rs | 3 +- 27 files changed, 394 insertions(+), 161 deletions(-) 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 32621eb5f2f66..a65f860d24084 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 @@ -1017,7 +1025,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, .. }) => { @@ -1235,13 +1243,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); @@ -1249,11 +1256,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, @@ -1372,7 +1389,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_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 10871df3ab9d0..cab1d2f096523 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2390,8 +2390,12 @@ pub enum InlineAsmOperand<'hir> { Const { anon_const: AnonConst, }, - Sym { - expr: Expr<'hir>, + SymFn { + anon_const: AnonConst, + }, + SymStatic { + path: QPath<'hir>, + def_id: DefId, }, } @@ -2402,7 +2406,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_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_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_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_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 6c7d4afea67ee..c5cb6ebdacab2 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 400adf20cba7c..c19ccffec98ec 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 1f0a6e5ce9716..250d4fc1f06b9 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> { @@ -2719,6 +2721,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 { @@ -2779,6 +2787,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 { @@ -2843,6 +2867,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_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 82641a489f66a..4bbfd5f168b03 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/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index bf0bf2ed59b5b..3dbf83a453dbd 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 cb32e88588af2..9cc7a65a98c6e 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/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), } } }, From c1fa773c88109d534509db69ab988109cf4a3a2d Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Tue, 1 Mar 2022 00:53:25 +0000 Subject: [PATCH 05/16] Add codegen for global_asm! sym operands --- compiler/rustc_codegen_gcc/src/asm.rs | 32 ++++++++++++++++--- compiler/rustc_codegen_llvm/src/asm.rs | 27 ++++++++++++++-- compiler/rustc_codegen_llvm/src/base.rs | 19 +++++------ compiler/rustc_codegen_llvm/src/consts.rs | 7 ++++ compiler/rustc_codegen_llvm/src/context.rs | 8 +++++ compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 2 ++ compiler/rustc_codegen_ssa/src/mono_item.rs | 24 +++++++++++++- compiler/rustc_codegen_ssa/src/traits/asm.rs | 8 +++-- compiler/rustc_codegen_ssa/src/traits/mod.rs | 4 +-- .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 6 ++++ compiler/rustc_monomorphize/src/collector.rs | 22 ++++++++++++- 11 files changed, 137 insertions(+), 22 deletions(-) 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 96c7d884b7b20..564465a3edb1c 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -307,11 +307,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 +337,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/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 413ef0ba76464..27ef8a490a593 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -409,6 +409,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/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_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_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 { From e0ed0f4371265a6ab41a20d4d1b70b4b29e9d238 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Tue, 1 Mar 2022 00:54:28 +0000 Subject: [PATCH 06/16] Update tests for sym support in global_asm! --- src/test/assembly/asm/global_asm.rs | 12 +++++++- src/test/ui/asm/aarch64/parse-error.rs | 2 +- src/test/ui/asm/aarch64/parse-error.stderr | 10 +++--- src/test/ui/asm/aarch64/type-check-2.rs | 15 ++++++--- src/test/ui/asm/aarch64/type-check-2.stderr | 34 ++++++++++++--------- src/test/ui/asm/type-check-1.rs | 9 +++++- src/test/ui/asm/type-check-1.stderr | 29 ++++++++++++++---- src/test/ui/asm/x86_64/parse-error.rs | 2 +- src/test/ui/asm/x86_64/parse-error.stderr | 10 +++--- src/test/ui/asm/x86_64/type-check-2.rs | 15 ++++++--- src/test/ui/asm/x86_64/type-check-2.stderr | 34 ++++++++++++--------- 11 files changed, 114 insertions(+), 58 deletions(-) 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/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 From fefc69ab15cdeae2242a2ea4d7d09a73217a98a6 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sat, 2 Apr 2022 22:54:51 +0100 Subject: [PATCH 07/16] Synthesis object file for `#[used]` and exported symbols --- compiler/rustc_codegen_ssa/src/back/link.rs | 69 +++++++++++++++++++ compiler/rustc_codegen_ssa/src/back/linker.rs | 46 +++++++++++++ .../rustc_codegen_ssa/src/back/metadata.rs | 2 +- .../src/back/symbol_export.rs | 54 +++++++++++++-- compiler/rustc_codegen_ssa/src/base.rs | 7 ++ compiler/rustc_codegen_ssa/src/lib.rs | 2 + .../src/middle/exported_symbols.rs | 10 +++ 7 files changed, 182 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 548ae0e411da7..a88f861311861 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; @@ -1654,6 +1655,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()) { @@ -1797,6 +1859,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 a90b8a62c623a..044dd9556fed0 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::SymbolExportKind; use rustc_middle::ty::TyCtxt; use rustc_serialize::{json, Encoder}; use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip}; @@ -1557,6 +1558,51 @@ 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 &(symbol, info) in tcx.exported_symbols(LOCAL_CRATE).iter() { + if info.level.is_below_threshold(export_threshold) || info.used { + symbols.push(( + symbol_export::symbol_name_for_instance_in_crate(tcx, symbol, LOCAL_CRATE), + info.kind, + )); + } + } + + 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 { + // ... we add its symbol list to our export list. + for &(symbol, info) in tcx.exported_symbols(cnum).iter() { + 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 +} + /// Much simplified and explicit CLI for the NVPTX linker. The linker operates /// with bitcode and uses LLVM backend to generate a PTX assembly. pub struct PtxLinker<'a> { 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 e14ebe3ae48f9..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, SymbolExportInfo, SymbolExportLevel, + metadata_symbol_name, ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel, }; use rustc_middle::ty::query::{ExternProviders, Providers}; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; @@ -124,6 +124,7 @@ 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())), @@ -131,6 +132,17 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap< ); (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(); @@ -138,7 +150,11 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap< if let Some(id) = tcx.proc_macro_decls_static(()) { reachable_non_generics.insert( id.to_def_id(), - SymbolExportInfo { level: SymbolExportLevel::C }, + SymbolExportInfo { + level: SymbolExportLevel::C, + kind: SymbolExportKind::Data, + used: false, + }, ); } @@ -180,7 +196,11 @@ fn exported_symbols_provider_local<'tcx>( symbols.push(( exported_symbol, - SymbolExportInfo { level: SymbolExportLevel::C }, + SymbolExportInfo { + level: SymbolExportLevel::C, + kind: SymbolExportKind::Text, + used: false, + }, )); } @@ -191,7 +211,11 @@ fn exported_symbols_provider_local<'tcx>( symbols.push(( exported_symbol, - SymbolExportInfo { level: SymbolExportLevel::Rust }, + SymbolExportInfo { + level: SymbolExportLevel::Rust, + kind: SymbolExportKind::Text, + used: false, + }, )); } } @@ -207,7 +231,11 @@ fn exported_symbols_provider_local<'tcx>( let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, sym)); ( exported_symbol, - SymbolExportInfo { level: SymbolExportLevel::C }, + SymbolExportInfo { + level: SymbolExportLevel::C, + kind: SymbolExportKind::Data, + used: false, + }, ) })); } @@ -220,7 +248,11 @@ fn exported_symbols_provider_local<'tcx>( let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, sym)); ( exported_symbol, - SymbolExportInfo { level: SymbolExportLevel::C }, + SymbolExportInfo { + level: SymbolExportLevel::C, + kind: SymbolExportKind::Data, + used: false, + }, ) })); } @@ -231,7 +263,11 @@ fn exported_symbols_provider_local<'tcx>( symbols.push(( exported_symbol, - SymbolExportInfo { level: SymbolExportLevel::Rust }, + SymbolExportInfo { + level: SymbolExportLevel::Rust, + kind: SymbolExportKind::Data, + used: false, + }, )); } @@ -269,6 +305,8 @@ fn exported_symbols_provider_local<'tcx>( symbol, SymbolExportInfo { level: SymbolExportLevel::Rust, + kind: SymbolExportKind::Text, + used: false, }, )); } @@ -283,6 +321,8 @@ fn exported_symbols_provider_local<'tcx>( ExportedSymbol::DropGlue(ty), SymbolExportInfo { level: SymbolExportLevel::Rust, + kind: SymbolExportKind::Text, + used: false, }, )); } diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 010560248054e..5a1d020884278 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 6cf6be79a8628..f3d5bb4bc624a 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_session::config::{CrateType, OutputFilenames, OutputType, RUST_CGU_EXT}; use rustc_session::cstore::{self, CrateSource}; @@ -140,6 +141,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_middle/src/middle/exported_symbols.rs b/compiler/rustc_middle/src/middle/exported_symbols.rs index a605e6dfdc1d3..631fd09ec4cf6 100644 --- a/compiler/rustc_middle/src/middle/exported_symbols.rs +++ b/compiler/rustc_middle/src/middle/exported_symbols.rs @@ -21,11 +21,21 @@ 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)] From 3730fe3210c44e32fabd6ad5138fd7239a967240 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sat, 2 Apr 2022 23:53:40 +0100 Subject: [PATCH 08/16] Ignore paths in temporary dir in reproducible build test --- src/test/run-make-fulldeps/reproducible-build/linker.rs | 6 ++++++ 1 file changed, 6 insertions(+) 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))); } From 77f610e4b4a930c8552d9f642a9b8ec802dfdd59 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sat, 9 Apr 2022 18:55:23 +0100 Subject: [PATCH 09/16] Note that CI tests Windows 10 --- src/doc/rustc/src/platform-support.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) 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 From bf3ef0da0c630ab239e4f26e86602eabe585e74f Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Sat, 9 Apr 2022 15:25:46 -0400 Subject: [PATCH 10/16] Switch to the 'normal' basic block for writing asm outputs if needed. We may sometimes emit an `invoke` instead of a `call` for inline assembly during the MIR -> LLVM IR lowering. But we failed to update the IR builder's current basic block before writing the results to the outputs. This would result in invalid IR because the basic block would end in a `store` instruction, which isn't a valid terminator. --- compiler/rustc_codegen_llvm/src/asm.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 03c390b4bd427..91d132eb34350 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), .. } From 0b2f3604fd733db5ad9498eaf129655879c242b3 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Sat, 9 Apr 2022 15:16:38 -0700 Subject: [PATCH 11/16] Update asm-may_unwind test to handle use of asm with outputs. --- src/test/codegen/asm-may_unwind.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 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 +} From 460054c193e21a548cf8e0c7a86a3faf02fc96f7 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sat, 9 Apr 2022 22:36:25 +0100 Subject: [PATCH 12/16] Add a note to reachable.rs about `#[used]` --- compiler/rustc_passes/src/reachable.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 55745248c9389..b65e334261325 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -332,9 +332,12 @@ impl CollectPrivateImplItemsVisitor<'_, '_> { // which are currently akin to allocator symbols. 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) - || codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) { self.worklist.push(def_id); } From 98cd818d785f38b59ec874e13e7b83f6521553c7 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sun, 10 Apr 2022 02:16:12 +0100 Subject: [PATCH 13/16] Refactor exported_symbols and linked_symbols for code reuse --- compiler/rustc_codegen_ssa/src/back/linker.rs | 70 +++++++------------ 1 file changed, 26 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 044dd9556fed0..fce340232500f 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -12,7 +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::SymbolExportKind; +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}; @@ -1519,22 +1519,13 @@ impl<'a> L4Bender<'a> { } } -pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec { - if let Some(ref exports) = tcx.sess.target.override_export_symbols { - return exports.clone(); - } - - let mut symbols = Vec::new(); - - let export_threshold = symbol_export::crates_export_threshold(&[crate_type]); +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() { - if info.level.is_below_threshold(export_threshold) { - symbols.push(symbol_export::symbol_name_for_instance_in_crate( - tcx, - symbol, - LOCAL_CRATE, - )); - } + callback(symbol, info, LOCAL_CRATE); } let formats = tcx.dependency_formats(()); @@ -1544,16 +1535,26 @@ pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec, crate_type: CrateType) -> Vec { + if let Some(ref exports) = tcx.sess.target.override_export_symbols { + return exports.clone(); + } + + 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) { + symbols.push(symbol_export::symbol_name_for_instance_in_crate(tcx, symbol, cnum)); + } + }); symbols } @@ -1572,33 +1573,14 @@ pub(crate) fn linked_symbols( let mut symbols = Vec::new(); let export_threshold = symbol_export::crates_export_threshold(&[crate_type]); - for &(symbol, info) in tcx.exported_symbols(LOCAL_CRATE).iter() { + 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, LOCAL_CRATE), + symbol_export::symbol_name_for_instance_in_crate(tcx, symbol, cnum), info.kind, )); } - } - - 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 { - // ... we add its symbol list to our export list. - for &(symbol, info) in tcx.exported_symbols(cnum).iter() { - 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 } From 80152ed2133c2a04d6b3ef2778e147681398c74b Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sun, 10 Apr 2022 20:39:02 +0900 Subject: [PATCH 14/16] use `to_string` instead of `format!` --- compiler/rustc_parse/src/parser/item.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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)); } From 386ca6acc358fc81028680a45c8f3695c2988fef Mon Sep 17 00:00:00 2001 From: gimbles Date: Sun, 10 Apr 2022 20:51:11 +0530 Subject: [PATCH 15/16] Allow usage of sudo while not accessing root --- src/bootstrap/bootstrap.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 71b8f3c4553bc..927e686070f29 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -1161,9 +1161,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): From dfe13dbbcf6ccd503a82deb8f5a808713d0399c6 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 7 Apr 2022 01:21:35 -0700 Subject: [PATCH 16/16] only suggest removing semicolon when expr implements trait --- .../src/traits/error_reporting/suggestions.rs | 31 ++++++++----- .../rustc_typeck/src/check/fn_ctxt/checks.rs | 2 +- .../consider-removing-last-semi.stderr | 6 +-- src/test/ui/block-result/issue-11714.stderr | 2 +- src/test/ui/block-result/issue-13428.stderr | 2 +- ...-closure-expression-remove-semicolon.fixed | 2 +- ...old-closure-expression-remove-semicolon.rs | 2 +- ...closure-expression-remove-semicolon.stderr | 2 +- ...coercion-missing-tail-expected-type.stderr | 4 +- src/test/ui/issues/issue-6458-4.stderr | 2 +- .../liveness-return-last-stmt-semi.stderr | 2 +- .../impl-trait-return-trailing-semicolon.rs | 21 ++++++++- ...mpl-trait-return-trailing-semicolon.stderr | 45 ++++++++++++++++--- src/test/ui/suggestions/issue-81098.stderr | 4 +- ...t-arm-types-as-stmt-instead-of-expr.stderr | 2 +- 15 files changed, 97 insertions(+), 32 deletions(-) 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/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/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