diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_codegen_gcc/messages.ftl | 2 | ||||
| -rw-r--r-- | compiler/rustc_codegen_gcc/src/builder.rs | 15 | ||||
| -rw-r--r-- | compiler/rustc_codegen_gcc/src/errors.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/builder.rs | 25 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs | 28 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 11 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/codegen_attrs.rs | 8 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/mir/block.rs | 73 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/traits/builder.rs | 12 | ||||
| -rw-r--r-- | compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp | 26 | ||||
| -rw-r--r-- | compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs | 5 | ||||
| -rw-r--r-- | compiler/rustc_metadata/src/rmeta/mod.rs | 31 | ||||
| -rw-r--r-- | compiler/rustc_metadata/src/rmeta/parameterized.rs | 166 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/mod.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/parameterized.rs | 155 | ||||
| -rw-r--r-- | compiler/rustc_mir_transform/src/coverage/spans.rs | 38 | ||||
| -rw-r--r-- | compiler/rustc_mir_transform/src/elaborate_drop.rs | 54 |
17 files changed, 397 insertions, 258 deletions
diff --git a/compiler/rustc_codegen_gcc/messages.ftl b/compiler/rustc_codegen_gcc/messages.ftl index a70ac08f01a..b9b77b7d18c 100644 --- a/compiler/rustc_codegen_gcc/messages.ftl +++ b/compiler/rustc_codegen_gcc/messages.ftl @@ -4,3 +4,5 @@ codegen_gcc_unwinding_inline_asm = codegen_gcc_copy_bitcode = failed to copy bitcode to object file: {$err} codegen_gcc_lto_bitcode_from_rlib = failed to get bitcode from object file for LTO ({$gcc_err}) + +codegen_gcc_explicit_tail_calls_unsupported = explicit tail calls with the 'become' keyword are not implemented in the GCC backend diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index a4ec4bf8dea..4aee211e2ef 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -34,6 +34,7 @@ use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, Target, X86Abi}; use crate::common::{SignType, TypeReflection, type_is_pointer}; use crate::context::CodegenCx; +use crate::errors; use crate::intrinsic::llvm; use crate::type_of::LayoutGccExt; @@ -1742,6 +1743,20 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { call } + fn tail_call( + &mut self, + _llty: Self::Type, + _fn_attrs: Option<&CodegenFnAttrs>, + _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + _llfn: Self::Value, + _args: &[Self::Value], + _funclet: Option<&Self::Funclet>, + _instance: Option<Instance<'tcx>>, + ) { + // FIXME: implement support for explicit tail calls like rustc_codegen_llvm. + self.tcx.dcx().emit_fatal(errors::ExplicitTailCallsUnsupported); + } + fn zext(&mut self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> { // FIXME(antoyo): this does not zero-extend. self.gcc_int_cast(value, dest_typ) diff --git a/compiler/rustc_codegen_gcc/src/errors.rs b/compiler/rustc_codegen_gcc/src/errors.rs index 0aa16bd88b4..b252c39c0c0 100644 --- a/compiler/rustc_codegen_gcc/src/errors.rs +++ b/compiler/rustc_codegen_gcc/src/errors.rs @@ -19,3 +19,7 @@ pub(crate) struct CopyBitcode { pub(crate) struct LtoBitcodeFromRlib { pub gcc_err: String, } + +#[derive(Diagnostic)] +#[diag(codegen_gcc_explicit_tail_calls_unsupported)] +pub(crate) struct ExplicitTailCallsUnsupported; diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index f712b3b83fa..da2a153d819 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -15,6 +15,7 @@ use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::*; use rustc_data_structures::small_c_str::SmallCStr; use rustc_hir::def_id::DefId; +use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::ty::layout::{ FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTypingEnv, LayoutError, LayoutOfHelpers, @@ -24,7 +25,7 @@ use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_sanitizers::{cfi, kcfi}; use rustc_session::config::OptLevel; use rustc_span::Span; -use rustc_target::callconv::FnAbi; +use rustc_target::callconv::{FnAbi, PassMode}; use rustc_target::spec::{HasTargetSpec, SanitizerSet, Target}; use smallvec::SmallVec; use tracing::{debug, instrument}; @@ -1431,6 +1432,28 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { call } + fn tail_call( + &mut self, + llty: Self::Type, + fn_attrs: Option<&CodegenFnAttrs>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + llfn: Self::Value, + args: &[Self::Value], + funclet: Option<&Self::Funclet>, + instance: Option<Instance<'tcx>>, + ) { + let call = self.call(llty, fn_attrs, Some(fn_abi), llfn, args, funclet, instance); + llvm::LLVMRustSetTailCallKind(call, llvm::TailCallKind::MustTail); + + match &fn_abi.ret.mode { + PassMode::Ignore | PassMode::Indirect { .. } => self.ret_void(), + PassMode::Direct(_) | PassMode::Pair { .. } => self.ret(call), + mode @ PassMode::Cast { .. } => { + bug!("Encountered `PassMode::{mode:?}` during codegen") + } + } + } + fn zext(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { unsafe { llvm::LLVMBuildZExt(self.llbuilder, val, dest_ty, UNNAMED) } } diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs index 39a59560c9d..574463be7ff 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs @@ -39,7 +39,10 @@ impl Coords { /// or other expansions), and if it does happen then skipping a span or function is /// better than an ICE or `llvm-cov` failure that the user might have no way to avoid. pub(crate) fn make_coords(source_map: &SourceMap, file: &SourceFile, span: Span) -> Option<Coords> { - let span = ensure_non_empty_span(source_map, span)?; + if span.is_empty() { + debug_assert!(false, "can't make coords from empty span: {span:?}"); + return None; + } let lo = span.lo(); let hi = span.hi(); @@ -70,29 +73,6 @@ pub(crate) fn make_coords(source_map: &SourceMap, file: &SourceFile, span: Span) }) } -fn ensure_non_empty_span(source_map: &SourceMap, span: Span) -> Option<Span> { - if !span.is_empty() { - return Some(span); - } - - // The span is empty, so try to enlarge it to cover an adjacent '{' or '}'. - source_map - .span_to_source(span, |src, start, end| try { - // Adjusting span endpoints by `BytePos(1)` is normally a bug, - // but in this case we have specifically checked that the character - // we're skipping over is one of two specific ASCII characters, so - // adjusting by exactly 1 byte is correct. - if src.as_bytes().get(end).copied() == Some(b'{') { - Some(span.with_hi(span.hi() + BytePos(1))) - } else if start > 0 && src.as_bytes()[start - 1] == b'}' { - Some(span.with_lo(span.lo() - BytePos(1))) - } else { - None - } - }) - .ok()? -} - /// If `llvm-cov` sees a source region that is improperly ordered (end < start), /// it will immediately exit with a fatal error. To prevent that from happening, /// discard regions that are improperly ordered, or might be interpreted in a diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 0d0cb5f139e..2443194ff48 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -97,6 +97,16 @@ pub(crate) enum ModuleFlagMergeBehavior { // Consts for the LLVM CallConv type, pre-cast to usize. +#[derive(Copy, Clone, PartialEq, Debug)] +#[repr(C)] +#[allow(dead_code)] +pub(crate) enum TailCallKind { + None = 0, + Tail = 1, + MustTail = 2, + NoTail = 3, +} + /// LLVM CallingConv::ID. Should we wrap this? /// /// See <https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/IR/CallingConv.h> @@ -1186,6 +1196,7 @@ unsafe extern "C" { pub(crate) safe fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool; pub(crate) safe fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool); pub(crate) safe fn LLVMSetTailCall(CallInst: &Value, IsTailCall: Bool); + pub(crate) safe fn LLVMRustSetTailCallKind(CallInst: &Value, Kind: TailCallKind); // Operations on attributes pub(crate) fn LLVMCreateStringAttribute( diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 5c54bce6e03..78edc69b237 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -527,14 +527,14 @@ fn handle_lang_items( attrs: &[Attribute], codegen_fn_attrs: &mut CodegenFnAttrs, ) { + let lang_item = lang_items::extract(attrs).and_then(|(name, _)| LangItem::from_name(name)); + // Weak lang items have the same semantics as "std internal" symbols in the // sense that they're preserved through all our LTO passes and only // strippable by the linker. // // Additionally weak lang items have predetermined symbol names. - if let Some((name, _)) = lang_items::extract(attrs) - && let Some(lang_item) = LangItem::from_name(name) - { + if let Some(lang_item) = lang_item { if WEAK_LANG_ITEMS.contains(&lang_item) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL; } @@ -548,8 +548,6 @@ fn handle_lang_items( if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) && codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) { - let lang_item = - lang_items::extract(attrs).map_or(None, |(name, _span)| LangItem::from_name(name)); let mut err = tcx .dcx() .struct_span_err( diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index bde63fd501a..e96590441fa 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -35,6 +35,14 @@ enum MergingSucc { True, } +/// Indicates to the call terminator codegen whether a cal +/// is a normal call or an explicit tail call. +#[derive(Debug, PartialEq)] +enum CallKind { + Normal, + Tail, +} + /// Used by `FunctionCx::codegen_terminator` for emitting common patterns /// e.g., creating a basic block, calling a function, etc. struct TerminatorCodegenHelper<'tcx> { @@ -160,6 +168,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { mut unwind: mir::UnwindAction, lifetime_ends_after_call: &[(Bx::Value, Size)], instance: Option<Instance<'tcx>>, + kind: CallKind, mergeable_succ: bool, ) -> MergingSucc { let tcx = bx.tcx(); @@ -221,6 +230,11 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { } }; + if kind == CallKind::Tail { + bx.tail_call(fn_ty, fn_attrs, fn_abi, fn_ptr, llargs, self.funclet(fx), instance); + return MergingSucc::False; + } + if let Some(unwind_block) = unwind_block { let ret_llbb = if let Some((_, target)) = destination { fx.llbb(target) @@ -659,6 +673,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { unwind, &[], Some(drop_instance), + CallKind::Normal, !maybe_null && mergeable_succ, ) } @@ -747,8 +762,19 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let (fn_abi, llfn, instance) = common::build_langcall(bx, span, lang_item); // Codegen the actual panic invoke/call. - let merging_succ = - helper.do_call(self, bx, fn_abi, llfn, &args, None, unwind, &[], Some(instance), false); + let merging_succ = helper.do_call( + self, + bx, + fn_abi, + llfn, + &args, + None, + unwind, + &[], + Some(instance), + CallKind::Normal, + false, + ); assert_eq!(merging_succ, MergingSucc::False); MergingSucc::False } @@ -777,6 +803,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::UnwindAction::Unreachable, &[], Some(instance), + CallKind::Normal, false, ); assert_eq!(merging_succ, MergingSucc::False); @@ -845,6 +872,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { unwind, &[], Some(instance), + CallKind::Normal, mergeable_succ, )) } @@ -860,6 +888,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { target: Option<mir::BasicBlock>, unwind: mir::UnwindAction, fn_span: Span, + kind: CallKind, mergeable_succ: bool, ) -> MergingSucc { let source_info = mir::SourceInfo { span: fn_span, ..terminator.source_info }; @@ -1003,8 +1032,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // We still need to call `make_return_dest` even if there's no `target`, since // `fn_abi.ret` could be `PassMode::Indirect`, even if it is uninhabited, // and `make_return_dest` adds the return-place indirect pointer to `llargs`. - let return_dest = self.make_return_dest(bx, destination, &fn_abi.ret, &mut llargs); - let destination = target.map(|target| (return_dest, target)); + let destination = match kind { + CallKind::Normal => { + let return_dest = self.make_return_dest(bx, destination, &fn_abi.ret, &mut llargs); + target.map(|target| (return_dest, target)) + } + CallKind::Tail => None, + }; // Split the rust-call tupled arguments off. let (first_args, untuple) = if sig.abi() == ExternAbi::RustCall @@ -1020,6 +1054,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // to generate `lifetime_end` when the call returns. let mut lifetime_ends_after_call: Vec<(Bx::Value, Size)> = Vec::new(); 'make_args: for (i, arg) in first_args.iter().enumerate() { + if kind == CallKind::Tail && matches!(fn_abi.args[i].mode, PassMode::Indirect { .. }) { + // FIXME: https://github.com/rust-lang/rust/pull/144232#discussion_r2218543841 + span_bug!( + fn_span, + "arguments using PassMode::Indirect are currently not supported for tail calls" + ); + } + let mut op = self.codegen_operand(bx, &arg.node); if let (0, Some(ty::InstanceKind::Virtual(_, idx))) = (i, instance.map(|i| i.def)) { @@ -1147,6 +1189,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { unwind, &lifetime_ends_after_call, instance, + kind, mergeable_succ, ) } @@ -1388,15 +1431,23 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { target, unwind, fn_span, + CallKind::Normal, mergeable_succ(), ), - mir::TerminatorKind::TailCall { .. } => { - // FIXME(explicit_tail_calls): implement tail calls in ssa backend - span_bug!( - terminator.source_info.span, - "`TailCall` terminator is not yet supported by `rustc_codegen_ssa`" - ) - } + mir::TerminatorKind::TailCall { ref func, ref args, fn_span } => self + .codegen_call_terminator( + helper, + bx, + terminator, + func, + args, + mir::Place::from(mir::RETURN_PLACE), + None, + mir::UnwindAction::Unreachable, + fn_span, + CallKind::Tail, + mergeable_succ(), + ), mir::TerminatorKind::CoroutineDrop | mir::TerminatorKind::Yield { .. } => { bug!("coroutine ops in codegen") } diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 979456a6ba7..4b18146863b 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -595,6 +595,18 @@ pub trait BuilderMethods<'a, 'tcx>: funclet: Option<&Self::Funclet>, instance: Option<Instance<'tcx>>, ) -> Self::Value; + + fn tail_call( + &mut self, + llty: Self::Type, + fn_attrs: Option<&CodegenFnAttrs>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + llfn: Self::Value, + args: &[Self::Value], + funclet: Option<&Self::Funclet>, + instance: Option<Instance<'tcx>>, + ); + fn zext(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value; fn apply_attrs_to_cleanup_callsite(&mut self, llret: Self::Value); diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index c9814beedd6..588d867bbbf 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1986,3 +1986,29 @@ extern "C" void LLVMRustSetNoSanitizeHWAddress(LLVMValueRef Global) { MD.NoHWAddress = true; GV.setSanitizerMetadata(MD); } + +enum class LLVMRustTailCallKind { + None = 0, + Tail = 1, + MustTail = 2, + NoTail = 3 +}; + +extern "C" void LLVMRustSetTailCallKind(LLVMValueRef Call, + LLVMRustTailCallKind Kind) { + CallInst *CI = unwrap<CallInst>(Call); + switch (Kind) { + case LLVMRustTailCallKind::None: + CI->setTailCallKind(CallInst::TCK_None); + break; + case LLVMRustTailCallKind::Tail: + CI->setTailCallKind(CallInst::TCK_Tail); + break; + case LLVMRustTailCallKind::MustTail: + CI->setTailCallKind(CallInst::TCK_MustTail); + break; + case LLVMRustTailCallKind::NoTail: + CI->setTailCallKind(CallInst::TCK_NoTail); + break; + } +} diff --git a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs index 19369425f81..f3917b55782 100644 --- a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs +++ b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs @@ -1,6 +1,5 @@ use rustc_data_structures::owned_slice::OwnedSlice; use rustc_hir::def_path_hash_map::{Config as HashMapConfig, DefPathHashMap}; -use rustc_middle::parameterized_over_tcx; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_span::def_id::{DefIndex, DefPathHash}; @@ -11,10 +10,6 @@ pub(crate) enum DefPathHashMapRef<'tcx> { BorrowedFromTcx(&'tcx DefPathHashMap), } -parameterized_over_tcx! { - DefPathHashMapRef, -} - impl DefPathHashMapRef<'_> { #[inline] pub(crate) fn def_path_hash_to_def_index(&self, def_path_hash: &DefPathHash) -> DefIndex { diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 915c9731688..9de5e12d5bb 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -6,6 +6,7 @@ use decoder::{DecodeContext, Metadata}; use def_path_hash_map::DefPathHashMapRef; use encoder::EncodeContext; pub use encoder::{EncodedMetadata, encode_metadata, rendered_const}; +pub(crate) use parameterized::ParameterizedOverTcx; use rustc_abi::{FieldIdx, ReprOptions, VariantIdx}; use rustc_attr_data_structures::StrippedCfgItem; use rustc_data_structures::fx::FxHashMap; @@ -26,12 +27,10 @@ use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; use rustc_middle::middle::lib_features::FeatureStability; use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault; +use rustc_middle::mir; use rustc_middle::ty::fast_reject::SimplifiedType; -use rustc_middle::ty::{ - self, DeducedParamAttrs, ParameterizedOverTcx, Ty, TyCtxt, UnusedGenericParams, -}; +use rustc_middle::ty::{self, DeducedParamAttrs, Ty, TyCtxt, UnusedGenericParams}; use rustc_middle::util::Providers; -use rustc_middle::{mir, trivially_parameterized_over_tcx}; use rustc_serialize::opaque::FileEncoder; use rustc_session::config::{SymbolManglingVersion, TargetModifier}; use rustc_session::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib}; @@ -47,6 +46,7 @@ use crate::creader::CrateMetadataRef; mod decoder; mod def_path_hash_map; mod encoder; +mod parameterized; mod table; pub(crate) fn rustc_version(cfg_version: &'static str) -> String { @@ -86,10 +86,6 @@ struct LazyValue<T> { _marker: PhantomData<fn() -> T>, } -impl<T: ParameterizedOverTcx> ParameterizedOverTcx for LazyValue<T> { - type Value<'tcx> = LazyValue<T::Value<'tcx>>; -} - impl<T> LazyValue<T> { fn from_position(position: NonZero<usize>) -> LazyValue<T> { LazyValue { position, _marker: PhantomData } @@ -112,10 +108,6 @@ struct LazyArray<T> { _marker: PhantomData<fn() -> T>, } -impl<T: ParameterizedOverTcx> ParameterizedOverTcx for LazyArray<T> { - type Value<'tcx> = LazyArray<T::Value<'tcx>>; -} - impl<T> Default for LazyArray<T> { fn default() -> LazyArray<T> { LazyArray::from_position_and_num_elems(NonZero::new(1).unwrap(), 0) @@ -143,10 +135,6 @@ struct LazyTable<I, T> { _marker: PhantomData<fn(I) -> T>, } -impl<I: 'static, T: ParameterizedOverTcx> ParameterizedOverTcx for LazyTable<I, T> { - type Value<'tcx> = LazyTable<I, T::Value<'tcx>>; -} - impl<I, T> LazyTable<I, T> { fn from_position_and_encoded_size( position: NonZero<usize>, @@ -594,14 +582,3 @@ pub fn provide(providers: &mut Providers) { encoder::provide(providers); decoder::provide(providers); } - -trivially_parameterized_over_tcx! { - VariantData, - RawDefId, - TraitImpls, - IncoherentImpls, - CrateHeader, - CrateRoot, - CrateDep, - AttrFlags, -} diff --git a/compiler/rustc_metadata/src/rmeta/parameterized.rs b/compiler/rustc_metadata/src/rmeta/parameterized.rs new file mode 100644 index 00000000000..7cd399baa42 --- /dev/null +++ b/compiler/rustc_metadata/src/rmeta/parameterized.rs @@ -0,0 +1,166 @@ +use std::hash::Hash; + +use rustc_data_structures::unord::UnordMap; +use rustc_hir::def_id::DefIndex; +use rustc_index::{Idx, IndexVec}; +use rustc_middle::ty::{Binder, EarlyBinder}; +use rustc_span::Symbol; + +use crate::rmeta::{LazyArray, LazyTable, LazyValue}; + +pub(crate) trait ParameterizedOverTcx: 'static { + type Value<'tcx>; +} + +impl<T: ParameterizedOverTcx> ParameterizedOverTcx for Option<T> { + type Value<'tcx> = Option<T::Value<'tcx>>; +} + +impl<A: ParameterizedOverTcx, B: ParameterizedOverTcx> ParameterizedOverTcx for (A, B) { + type Value<'tcx> = (A::Value<'tcx>, B::Value<'tcx>); +} + +impl<T: ParameterizedOverTcx> ParameterizedOverTcx for Vec<T> { + type Value<'tcx> = Vec<T::Value<'tcx>>; +} + +impl<I: Idx + 'static, T: ParameterizedOverTcx> ParameterizedOverTcx for IndexVec<I, T> { + type Value<'tcx> = IndexVec<I, T::Value<'tcx>>; +} + +impl<I: Hash + Eq + 'static, T: ParameterizedOverTcx> ParameterizedOverTcx for UnordMap<I, T> { + type Value<'tcx> = UnordMap<I, T::Value<'tcx>>; +} + +impl<T: ParameterizedOverTcx> ParameterizedOverTcx for Binder<'static, T> { + type Value<'tcx> = Binder<'tcx, T::Value<'tcx>>; +} + +impl<T: ParameterizedOverTcx> ParameterizedOverTcx for EarlyBinder<'static, T> { + type Value<'tcx> = EarlyBinder<'tcx, T::Value<'tcx>>; +} + +impl<T: ParameterizedOverTcx> ParameterizedOverTcx for LazyValue<T> { + type Value<'tcx> = LazyValue<T::Value<'tcx>>; +} + +impl<T: ParameterizedOverTcx> ParameterizedOverTcx for LazyArray<T> { + type Value<'tcx> = LazyArray<T::Value<'tcx>>; +} + +impl<I: 'static, T: ParameterizedOverTcx> ParameterizedOverTcx for LazyTable<I, T> { + type Value<'tcx> = LazyTable<I, T::Value<'tcx>>; +} + +macro_rules! trivially_parameterized_over_tcx { + ($($ty:ty),+ $(,)?) => { + $( + impl ParameterizedOverTcx for $ty { + #[allow(unused_lifetimes)] + type Value<'tcx> = $ty; + } + )* + } +} + +trivially_parameterized_over_tcx! { + bool, + u64, + usize, + std::string::String, + // tidy-alphabetical-start + crate::rmeta::AttrFlags, + crate::rmeta::CrateDep, + crate::rmeta::CrateHeader, + crate::rmeta::CrateRoot, + crate::rmeta::IncoherentImpls, + crate::rmeta::RawDefId, + crate::rmeta::TraitImpls, + crate::rmeta::VariantData, + rustc_abi::ReprOptions, + rustc_ast::DelimArgs, + rustc_attr_data_structures::ConstStability, + rustc_attr_data_structures::DefaultBodyStability, + rustc_attr_data_structures::Deprecation, + rustc_attr_data_structures::Stability, + rustc_attr_data_structures::StrippedCfgItem<rustc_hir::def_id::DefIndex>, + rustc_hir::Attribute, + rustc_hir::Constness, + rustc_hir::CoroutineKind, + rustc_hir::Defaultness, + rustc_hir::LangItem, + rustc_hir::OpaqueTyOrigin<rustc_hir::def_id::DefId>, + rustc_hir::PreciseCapturingArgKind<Symbol, Symbol>, + rustc_hir::Safety, + rustc_hir::def::DefKind, + rustc_hir::def::DocLinkResMap, + rustc_hir::def_id::DefId, + rustc_hir::def_id::DefIndex, + rustc_hir::definitions::DefKey, + rustc_index::bit_set::DenseBitSet<u32>, + rustc_middle::metadata::ModChild, + rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs, + rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile, + rustc_middle::middle::exported_symbols::SymbolExportInfo, + rustc_middle::middle::lib_features::FeatureStability, + rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault, + rustc_middle::mir::ConstQualifs, + rustc_middle::ty::AnonConstKind, + rustc_middle::ty::AssocItemContainer, + rustc_middle::ty::AsyncDestructor, + rustc_middle::ty::Asyncness, + rustc_middle::ty::DeducedParamAttrs, + rustc_middle::ty::Destructor, + rustc_middle::ty::Generics, + rustc_middle::ty::ImplTraitInTraitData, + rustc_middle::ty::IntrinsicDef, + rustc_middle::ty::TraitDef, + rustc_middle::ty::Variance, + rustc_middle::ty::Visibility<DefIndex>, + rustc_middle::ty::adjustment::CoerceUnsizedInfo, + rustc_middle::ty::fast_reject::SimplifiedType, + rustc_session::config::TargetModifier, + rustc_session::cstore::ForeignModule, + rustc_session::cstore::LinkagePreference, + rustc_session::cstore::NativeLib, + rustc_span::ExpnData, + rustc_span::ExpnHash, + rustc_span::ExpnId, + rustc_span::Ident, + rustc_span::SourceFile, + rustc_span::Span, + rustc_span::Symbol, + rustc_span::hygiene::SyntaxContextKey, + // tidy-alphabetical-end +} + +// HACK(compiler-errors): This macro rule can only take a fake path, +// not a real, due to parsing ambiguity reasons. +macro_rules! parameterized_over_tcx { + ($($( $fake_path:ident )::+ ),+ $(,)?) => { + $( + impl ParameterizedOverTcx for $( $fake_path )::+ <'static> { + type Value<'tcx> = $( $fake_path )::+ <'tcx>; + } + )* + } +} + +parameterized_over_tcx! { + // tidy-alphabetical-start + crate::rmeta::DefPathHashMapRef, + rustc_middle::middle::exported_symbols::ExportedSymbol, + rustc_middle::mir::Body, + rustc_middle::mir::CoroutineLayout, + rustc_middle::mir::interpret::ConstAllocation, + rustc_middle::ty::Clause, + rustc_middle::ty::ClauseKind, + rustc_middle::ty::Const, + rustc_middle::ty::ConstConditions, + rustc_middle::ty::FnSig, + rustc_middle::ty::GenericPredicates, + rustc_middle::ty::ImplTraitHeader, + rustc_middle::ty::TraitRef, + rustc_middle::ty::Ty, + // tidy-alphabetical-end +} diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index bb70c61cd14..5b7f34e0e77 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -85,7 +85,6 @@ pub use self::fold::*; pub use self::instance::{Instance, InstanceKind, ReifyReason, ShortInstance, UnusedGenericParams}; pub use self::list::{List, ListWithCachedTypeInfo}; pub use self::opaque_types::OpaqueTypeKey; -pub use self::parameterized::ParameterizedOverTcx; pub use self::pattern::{Pattern, PatternKind}; pub use self::predicate::{ AliasTerm, ArgOutlivesPredicate, Clause, ClauseKind, CoercePredicate, ExistentialPredicate, @@ -158,7 +157,6 @@ mod instance; mod intrinsic; mod list; mod opaque_types; -mod parameterized; mod predicate; mod region; mod rvalue_scopes; diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs deleted file mode 100644 index dbacbe21edb..00000000000 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ /dev/null @@ -1,155 +0,0 @@ -use std::hash::Hash; - -use rustc_data_structures::unord::UnordMap; -use rustc_hir::def_id::DefIndex; -use rustc_index::{Idx, IndexVec}; -use rustc_span::Symbol; - -use crate::ty; - -pub trait ParameterizedOverTcx: 'static { - type Value<'tcx>; -} - -impl<T: ParameterizedOverTcx> ParameterizedOverTcx for &'static [T] { - type Value<'tcx> = &'tcx [T::Value<'tcx>]; -} - -impl<T: ParameterizedOverTcx> ParameterizedOverTcx for Option<T> { - type Value<'tcx> = Option<T::Value<'tcx>>; -} - -impl<A: ParameterizedOverTcx, B: ParameterizedOverTcx> ParameterizedOverTcx for (A, B) { - type Value<'tcx> = (A::Value<'tcx>, B::Value<'tcx>); -} - -impl<T: ParameterizedOverTcx> ParameterizedOverTcx for Vec<T> { - type Value<'tcx> = Vec<T::Value<'tcx>>; -} - -impl<I: Idx + 'static, T: ParameterizedOverTcx> ParameterizedOverTcx for IndexVec<I, T> { - type Value<'tcx> = IndexVec<I, T::Value<'tcx>>; -} - -impl<I: Hash + Eq + 'static, T: ParameterizedOverTcx> ParameterizedOverTcx for UnordMap<I, T> { - type Value<'tcx> = UnordMap<I, T::Value<'tcx>>; -} - -impl<T: ParameterizedOverTcx> ParameterizedOverTcx for ty::Binder<'static, T> { - type Value<'tcx> = ty::Binder<'tcx, T::Value<'tcx>>; -} - -impl<T: ParameterizedOverTcx> ParameterizedOverTcx for ty::EarlyBinder<'static, T> { - type Value<'tcx> = ty::EarlyBinder<'tcx, T::Value<'tcx>>; -} - -#[macro_export] -macro_rules! trivially_parameterized_over_tcx { - ($($ty:ty),+ $(,)?) => { - $( - impl $crate::ty::ParameterizedOverTcx for $ty { - #[allow(unused_lifetimes)] - type Value<'tcx> = $ty; - } - )* - } -} - -trivially_parameterized_over_tcx! { - usize, - (), - u32, - u64, - bool, - std::string::String, - crate::metadata::ModChild, - crate::middle::codegen_fn_attrs::CodegenFnAttrs, - crate::middle::debugger_visualizer::DebuggerVisualizerFile, - crate::middle::exported_symbols::SymbolExportInfo, - crate::middle::lib_features::FeatureStability, - crate::middle::resolve_bound_vars::ObjectLifetimeDefault, - crate::mir::ConstQualifs, - ty::AsyncDestructor, - ty::AssocItemContainer, - ty::Asyncness, - ty::AnonConstKind, - ty::DeducedParamAttrs, - ty::Destructor, - ty::Generics, - ty::ImplPolarity, - ty::ImplTraitInTraitData, - ty::ReprOptions, - ty::TraitDef, - ty::UnusedGenericParams, - ty::Visibility<DefIndex>, - ty::adjustment::CoerceUnsizedInfo, - ty::fast_reject::SimplifiedType, - ty::IntrinsicDef, - rustc_ast::Attribute, - rustc_ast::DelimArgs, - rustc_attr_data_structures::StrippedCfgItem<rustc_hir::def_id::DefIndex>, - rustc_attr_data_structures::ConstStability, - rustc_attr_data_structures::DefaultBodyStability, - rustc_attr_data_structures::Deprecation, - rustc_attr_data_structures::Stability, - rustc_hir::Constness, - rustc_hir::Defaultness, - rustc_hir::Safety, - rustc_hir::CoroutineKind, - rustc_hir::IsAsync, - rustc_hir::LangItem, - rustc_hir::def::DefKind, - rustc_hir::def::DocLinkResMap, - rustc_hir::def_id::DefId, - rustc_hir::def_id::DefIndex, - rustc_hir::definitions::DefKey, - rustc_hir::OpaqueTyOrigin<rustc_hir::def_id::DefId>, - rustc_hir::PreciseCapturingArgKind<Symbol, Symbol>, - rustc_index::bit_set::DenseBitSet<u32>, - rustc_index::bit_set::FiniteBitSet<u32>, - rustc_session::cstore::ForeignModule, - rustc_session::cstore::LinkagePreference, - rustc_session::cstore::NativeLib, - rustc_session::config::TargetModifier, - rustc_span::ExpnData, - rustc_span::ExpnHash, - rustc_span::ExpnId, - rustc_span::SourceFile, - rustc_span::Span, - rustc_span::Symbol, - rustc_span::def_id::DefPathHash, - rustc_span::hygiene::SyntaxContextKey, - rustc_span::Ident, - rustc_type_ir::Variance, - rustc_hir::Attribute, -} - -// HACK(compiler-errors): This macro rule can only take a fake path, -// not a real, due to parsing ambiguity reasons. -#[macro_export] -macro_rules! parameterized_over_tcx { - ($($($fake_path:ident)::+),+ $(,)?) => { - $( - impl $crate::ty::ParameterizedOverTcx for $($fake_path)::+<'static> { - type Value<'tcx> = $($fake_path)::+<'tcx>; - } - )* - } -} - -parameterized_over_tcx! { - crate::middle::exported_symbols::ExportedSymbol, - crate::mir::Body, - crate::mir::CoroutineLayout, - crate::mir::interpret::ConstAllocation, - ty::Ty, - ty::FnSig, - ty::GenericPredicates, - ty::ConstConditions, - ty::TraitRef, - ty::Const, - ty::Predicate, - ty::Clause, - ty::ClauseKind, - ty::ImplTraitHeader, -} diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index ec76076020e..ddeae093df5 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -1,7 +1,8 @@ use rustc_data_structures::fx::FxHashSet; use rustc_middle::mir; use rustc_middle::ty::TyCtxt; -use rustc_span::{DesugaringKind, ExpnKind, MacroKind, Span}; +use rustc_span::source_map::SourceMap; +use rustc_span::{BytePos, DesugaringKind, ExpnKind, MacroKind, Span}; use tracing::instrument; use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph}; @@ -83,8 +84,18 @@ pub(super) fn extract_refined_covspans<'tcx>( // Discard any span that overlaps with a hole. discard_spans_overlapping_holes(&mut covspans, &holes); - // Perform more refinement steps after holes have been dealt with. + // Discard spans that overlap in unwanted ways. let mut covspans = remove_unwanted_overlapping_spans(covspans); + + // For all empty spans, either enlarge them to be non-empty, or discard them. + let source_map = tcx.sess.source_map(); + covspans.retain_mut(|covspan| { + let Some(span) = ensure_non_empty_span(source_map, covspan.span) else { return false }; + covspan.span = span; + true + }); + + // Merge covspans that can be merged. covspans.dedup_by(|b, a| a.merge_if_eligible(b)); code_mappings.extend(covspans.into_iter().map(|Covspan { span, bcb }| { @@ -230,3 +241,26 @@ fn compare_spans(a: Span, b: Span) -> std::cmp::Ordering { // - Both have the same start and span A extends further right .then_with(|| Ord::cmp(&a.hi(), &b.hi()).reverse()) } + +fn ensure_non_empty_span(source_map: &SourceMap, span: Span) -> Option<Span> { + if !span.is_empty() { + return Some(span); + } + + // The span is empty, so try to enlarge it to cover an adjacent '{' or '}'. + source_map + .span_to_source(span, |src, start, end| try { + // Adjusting span endpoints by `BytePos(1)` is normally a bug, + // but in this case we have specifically checked that the character + // we're skipping over is one of two specific ASCII characters, so + // adjusting by exactly 1 byte is correct. + if src.as_bytes().get(end).copied() == Some(b'{') { + Some(span.with_hi(span.hi() + BytePos(1))) + } else if start > 0 && src.as_bytes()[start - 1] == b'}' { + Some(span.with_lo(span.lo() - BytePos(1))) + } else { + None + } + }) + .ok()? +} diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs index de96b1f255a..df4853c1dcb 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drop.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs @@ -761,24 +761,37 @@ where let skip_contents = adt.is_union() || adt.is_manually_drop(); let contents_drop = if skip_contents { + if adt.has_dtor(self.tcx()) && self.elaborator.get_drop_flag(self.path).is_some() { + // the top-level drop flag is usually cleared by open_drop_for_adt_contents + // types with destructors would still need an empty drop ladder to clear it + + // however, these types are only open dropped in `DropShimElaborator` + // which does not have drop flags + // a future box-like "DerefMove" trait would allow for this case to happen + span_bug!(self.source_info.span, "open dropping partially moved union"); + } + (self.succ, self.unwind, self.dropline) } else { self.open_drop_for_adt_contents(adt, args) }; - if adt.is_box() { - // we need to drop the inside of the box before running the destructor - let succ = self.destructor_call_block_sync((contents_drop.0, contents_drop.1)); - let unwind = contents_drop - .1 - .map(|unwind| self.destructor_call_block_sync((unwind, Unwind::InCleanup))); - let dropline = contents_drop - .2 - .map(|dropline| self.destructor_call_block_sync((dropline, contents_drop.1))); - - self.open_drop_for_box_contents(adt, args, succ, unwind, dropline) - } else if adt.has_dtor(self.tcx()) { - self.destructor_call_block(contents_drop) + if adt.has_dtor(self.tcx()) { + let destructor_block = if adt.is_box() { + // we need to drop the inside of the box before running the destructor + let succ = self.destructor_call_block_sync((contents_drop.0, contents_drop.1)); + let unwind = contents_drop + .1 + .map(|unwind| self.destructor_call_block_sync((unwind, Unwind::InCleanup))); + let dropline = contents_drop + .2 + .map(|dropline| self.destructor_call_block_sync((dropline, contents_drop.1))); + self.open_drop_for_box_contents(adt, args, succ, unwind, dropline) + } else { + self.destructor_call_block(contents_drop) + }; + + self.drop_flag_test_block(destructor_block, contents_drop.0, contents_drop.1) } else { contents_drop.0 } @@ -982,12 +995,7 @@ where unwind.is_cleanup(), ); - let destructor_block = self.elaborator.patch().new_block(result); - - let block_start = Location { block: destructor_block, statement_index: 0 }; - self.elaborator.clear_drop_flag(block_start, self.path, DropFlagMode::Shallow); - - self.drop_flag_test_block(destructor_block, succ, unwind) + self.elaborator.patch().new_block(result) } fn destructor_call_block( @@ -1002,13 +1010,7 @@ where && !unwind.is_cleanup() && ty.is_async_drop(self.tcx(), self.elaborator.typing_env()) { - let destructor_block = - self.build_async_drop(self.place, ty, None, succ, unwind, dropline, true); - - let block_start = Location { block: destructor_block, statement_index: 0 }; - self.elaborator.clear_drop_flag(block_start, self.path, DropFlagMode::Shallow); - - self.drop_flag_test_block(destructor_block, succ, unwind) + self.build_async_drop(self.place, ty, None, succ, unwind, dropline, true) } else { self.destructor_call_block_sync((succ, unwind)) } |
