diff --git a/Cargo.lock b/Cargo.lock index 833356011964..01300d56cff9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3356,9 +3356,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" +checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" [[package]] name = "rustc-hash" @@ -3865,7 +3865,6 @@ dependencies = [ "rustc_fluent_macro", "rustc_hashes", "rustc_index", - "rustc_lexer", "rustc_lint_defs", "rustc_macros", "rustc_serialize", diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index cbdc89f9deed..0e3ab0a4a4c3 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -5,7 +5,6 @@ //! This API is completely unstable and subject to change. // tidy-alphabetical-start -#![cfg_attr(bootstrap, feature(array_windows))] #![doc(test(attr(deny(warnings), allow(internal_features))))] #![feature(associated_type_defaults)] #![feature(box_patterns)] diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs index ab99186777f9..a367e699fcb9 100644 --- a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs +++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs @@ -1,4 +1,8 @@ -use rustc_hir::attrs::WindowsSubsystemKind; +use rustc_hir::attrs::{CrateType, WindowsSubsystemKind}; +use rustc_hir::lints::AttributeLintKind; +use rustc_session::lint::builtin::UNKNOWN_CRATE_TYPES; +use rustc_span::Symbol; +use rustc_span::edit_distance::find_best_match_for_name; use super::prelude::*; @@ -26,6 +30,56 @@ impl SingleAttributeParser for CrateNameParser { } } +pub(crate) struct CrateTypeParser; + +impl CombineAttributeParser for CrateTypeParser { + const PATH: &[Symbol] = &[sym::crate_type]; + type Item = CrateType; + const CONVERT: ConvertFn = |items, _| AttributeKind::CrateType(items); + + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); + + const TEMPLATE: AttributeTemplate = + template!(NameValueStr: "crate type", "https://doc.rust-lang.org/reference/linkage.html"); + + fn extend( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, + ) -> impl IntoIterator { + let ArgParser::NameValue(n) = args else { + cx.expected_name_value(cx.attr_span, None); + return None; + }; + + let Some(crate_type) = n.value_as_str() else { + cx.expected_string_literal(n.value_span, Some(n.value_as_lit())); + return None; + }; + + let Ok(crate_type) = crate_type.try_into() else { + // We don't error on invalid `#![crate_type]` when not applied to a crate + if cx.shared.target == Target::Crate { + let candidate = find_best_match_for_name( + &CrateType::all_stable().iter().map(|(name, _)| *name).collect::>(), + crate_type, + None, + ); + cx.emit_lint( + UNKNOWN_CRATE_TYPES, + AttributeLintKind::CrateTypeUnknown { + span: n.value_span, + suggested: candidate, + }, + n.value_span, + ); + } + return None; + }; + + Some(crate_type) + } +} + pub(crate) struct RecursionLimitParser; impl SingleAttributeParser for RecursionLimitParser { @@ -184,3 +238,39 @@ impl SingleAttributeParser for WindowsSubsystemParser { Some(AttributeKind::WindowsSubsystem(kind, cx.attr_span)) } } + +pub(crate) struct PanicRuntimeParser; + +impl NoArgsAttributeParser for PanicRuntimeParser { + const PATH: &[Symbol] = &[sym::panic_runtime]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::PanicRuntime; +} + +pub(crate) struct NeedsPanicRuntimeParser; + +impl NoArgsAttributeParser for NeedsPanicRuntimeParser { + const PATH: &[Symbol] = &[sym::needs_panic_runtime]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NeedsPanicRuntime; +} + +pub(crate) struct ProfilerRuntimeParser; + +impl NoArgsAttributeParser for ProfilerRuntimeParser { + const PATH: &[Symbol] = &[sym::profiler_runtime]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ProfilerRuntime; +} + +pub(crate) struct NoBuiltinsParser; + +impl NoArgsAttributeParser for NoBuiltinsParser { + const PATH: &[Symbol] = &[sym::no_builtins]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NoBuiltins; +} diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index ce3d116dce3b..a636b449ca56 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -665,3 +665,12 @@ impl NoArgsAttributeParser for NeedsAllocatorParser { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NeedsAllocator; } + +pub(crate) struct CompilerBuiltinsParser; + +impl NoArgsAttributeParser for CompilerBuiltinsParser { + const PATH: &[Symbol] = &[sym::compiler_builtins]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::CompilerBuiltins; +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 614619bca3ec..e500be68e241 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -28,9 +28,10 @@ use crate::attributes::codegen_attrs::{ }; use crate::attributes::confusables::ConfusablesParser; use crate::attributes::crate_level::{ - CrateNameParser, MoveSizeLimitParser, NoCoreParser, NoMainParser, NoStdParser, - PatternComplexityLimitParser, RecursionLimitParser, RustcCoherenceIsCoreParser, - TypeLengthLimitParser, WindowsSubsystemParser, + CrateNameParser, CrateTypeParser, MoveSizeLimitParser, NeedsPanicRuntimeParser, + NoBuiltinsParser, NoCoreParser, NoMainParser, NoStdParser, PanicRuntimeParser, + PatternComplexityLimitParser, ProfilerRuntimeParser, RecursionLimitParser, + RustcCoherenceIsCoreParser, TypeLengthLimitParser, WindowsSubsystemParser, }; use crate::attributes::debugger::DebuggerViualizerParser; use crate::attributes::deprecation::DeprecationParser; @@ -40,8 +41,9 @@ use crate::attributes::dummy::DummyParser; use crate::attributes::inline::{InlineParser, RustcForceInlineParser}; use crate::attributes::instruction_set::InstructionSetParser; use crate::attributes::link_attrs::{ - ExportStableParser, FfiConstParser, FfiPureParser, LinkNameParser, LinkOrdinalParser, - LinkParser, LinkSectionParser, LinkageParser, NeedsAllocatorParser, StdInternalSymbolParser, + CompilerBuiltinsParser, ExportStableParser, FfiConstParser, FfiPureParser, LinkNameParser, + LinkOrdinalParser, LinkParser, LinkSectionParser, LinkageParser, NeedsAllocatorParser, + StdInternalSymbolParser, }; use crate::attributes::lint_helpers::{ AsPtrParser, AutomaticallyDerivedParser, PassByValueParser, PubTransparentParser, @@ -191,6 +193,7 @@ attribute_parsers!( // tidy-alphabetical-start Combine, Combine, + Combine, Combine, Combine, Combine, @@ -251,6 +254,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, @@ -266,6 +270,8 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, + Single>, Single>, Single>, Single>, @@ -273,12 +279,14 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 7c84530abbee..c2260a459097 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -986,16 +986,6 @@ impl<'a> MethodDef<'a> { f(cx, span, &substructure) } - fn get_ret_ty( - &self, - cx: &ExtCtxt<'_>, - trait_: &TraitDef<'_>, - generics: &Generics, - type_ident: Ident, - ) -> Box { - self.ret_ty.to_ty(cx, trait_.span, type_ident, generics) - } - fn is_static(&self) -> bool { !self.explicit_self } @@ -1068,10 +1058,14 @@ impl<'a> MethodDef<'a> { self_arg.into_iter().chain(nonself_args).collect() }; - let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident); + let ret_type = if let Ty::Unit = &self.ret_ty { + ast::FnRetTy::Default(span) + } else { + ast::FnRetTy::Ty(self.ret_ty.to_ty(cx, span, type_ident, generics)) + }; let method_ident = Ident::new(self.name, span); - let fn_decl = cx.fn_decl(args, ast::FnRetTy::Ty(ret_type)); + let fn_decl = cx.fn_decl(args, ret_type); let body_block = body.into_block(cx, span); let trait_lo_sp = span.shrink_to_lo(); diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs index 0cd510037293..756f86a7d011 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs @@ -242,7 +242,7 @@ impl DebugContext { let generics = tcx.generics_of(enclosing_fn_def_id); let args = instance.args.truncate_to(tcx, generics); - type_names::push_generic_params( + type_names::push_generic_args( tcx, tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), args), &mut name, diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 9379faf1156f..ca4805a93e01 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1397,12 +1397,12 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { fn call( &mut self, llty: &'ll Type, - fn_call_attrs: Option<&CodegenFnAttrs>, + caller_attrs: Option<&CodegenFnAttrs>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, llfn: &'ll Value, args: &[&'ll Value], funclet: Option<&Funclet<'ll>>, - instance: Option>, + callee_instance: Option>, ) -> &'ll Value { debug!("call {:?} with args ({:?})", llfn, args); @@ -1414,10 +1414,10 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } // Emit CFI pointer type membership test - self.cfi_type_test(fn_call_attrs, fn_abi, instance, llfn); + self.cfi_type_test(caller_attrs, fn_abi, callee_instance, llfn); // Emit KCFI operand bundle - let kcfi_bundle = self.kcfi_operand_bundle(fn_call_attrs, fn_abi, instance, llfn); + let kcfi_bundle = self.kcfi_operand_bundle(caller_attrs, fn_abi, callee_instance, llfn); if let Some(kcfi_bundle) = kcfi_bundle.as_ref().map(|b| b.as_ref()) { bundles.push(kcfi_bundle); } @@ -1435,17 +1435,17 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { ) }; - if let Some(instance) = instance { + if let Some(callee_instance) = callee_instance { // Attributes on the function definition being called - let fn_defn_attrs = self.cx.tcx.codegen_fn_attrs(instance.def_id()); - if let Some(fn_call_attrs) = fn_call_attrs + let callee_attrs = self.cx.tcx.codegen_fn_attrs(callee_instance.def_id()); + if let Some(caller_attrs) = caller_attrs // If there is an inline attribute and a target feature that matches // we will add the attribute to the callsite otherwise we'll omit // this and not add the attribute to prevent soundness issues. - && let Some(inlining_rule) = attributes::inline_attr(&self.cx, self.cx.tcx, instance) + && let Some(inlining_rule) = attributes::inline_attr(&self.cx, self.cx.tcx, callee_instance) && self.cx.tcx.is_target_feature_call_safe( - &fn_defn_attrs.target_features, - &fn_call_attrs.target_features.iter().cloned().chain( + &callee_attrs.target_features, + &caller_attrs.target_features.iter().cloned().chain( self.cx.tcx.sess.target_features.iter().map(|feat| TargetFeature { name: *feat, kind: TargetFeatureKind::Implied, @@ -1470,14 +1470,15 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { fn tail_call( &mut self, llty: Self::Type, - fn_attrs: Option<&CodegenFnAttrs>, + caller_attrs: Option<&CodegenFnAttrs>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, llfn: Self::Value, args: &[Self::Value], funclet: Option<&Self::Funclet>, - instance: Option>, + callee_instance: Option>, ) { - let call = self.call(llty, fn_attrs, Some(fn_abi), llfn, args, funclet, instance); + let call = + self.call(llty, caller_attrs, Some(fn_abi), llfn, args, funclet, callee_instance); llvm::LLVMSetTailCallKind(call, llvm::TailCallKind::MustTail); match &fn_abi.ret.mode { diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs index 3a750b6b53eb..f88f0c2fb099 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs @@ -92,7 +92,7 @@ pub(crate) fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool { CrateType::Executable | CrateType::Dylib | CrateType::Cdylib - | CrateType::Staticlib + | CrateType::StaticLib | CrateType::Sdylib => { // These are crate types for which we will embed pretty printers since they // are treated as leaf crates. diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 1c63bbcd1710..c3fa86f8a2ad 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -456,7 +456,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { let generics = tcx.generics_of(enclosing_fn_def_id); let args = instance.args.truncate_to(tcx, generics); - type_names::push_generic_params( + type_names::push_generic_args( tcx, tcx.normalize_erasing_regions(self.typing_env(), args), &mut name, diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index e4e954d22611..c8109db86e2f 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -136,7 +136,7 @@ pub fn link_binary( ) .build(&out_filename); } - CrateType::Staticlib => { + CrateType::StaticLib => { link_staticlib( sess, archive_builder_builder, @@ -474,7 +474,7 @@ fn link_staticlib( let res = each_linked_rlib( &codegen_results.crate_info, - Some(CrateType::Staticlib), + Some(CrateType::StaticLib), &mut |cnum, path| { let lto = are_upstream_rust_objects_already_included(sess) && !ignored_for_lto(sess, &codegen_results.crate_info, cnum); @@ -532,7 +532,7 @@ fn link_staticlib( let fmts = codegen_results .crate_info .dependency_formats - .get(&CrateType::Staticlib) + .get(&CrateType::StaticLib) .expect("no dependency formats for staticlib"); let mut all_rust_dylibs = vec![]; @@ -1210,7 +1210,7 @@ fn add_sanitizer_libraries( return; } - if matches!(crate_type, CrateType::Rlib | CrateType::Staticlib) { + if matches!(crate_type, CrateType::Rlib | CrateType::StaticLib) { return; } diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 637d54dd06c6..241c8d6bfd18 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -1857,7 +1857,7 @@ pub(crate) fn linked_symbols( | CrateType::Cdylib | CrateType::Dylib | CrateType::Sdylib => (), - CrateType::Staticlib | CrateType::Rlib => { + CrateType::StaticLib | CrateType::Rlib => { // These are not linked, so no need to generate symbols.o for them. return Vec::new(); } diff --git a/compiler/rustc_codegen_ssa/src/back/lto.rs b/compiler/rustc_codegen_ssa/src/back/lto.rs index ef4c193c4c2a..677268e367c2 100644 --- a/compiler/rustc_codegen_ssa/src/back/lto.rs +++ b/compiler/rustc_codegen_ssa/src/back/lto.rs @@ -67,7 +67,7 @@ fn crate_type_allows_lto(crate_type: CrateType) -> bool { match crate_type { CrateType::Executable | CrateType::Dylib - | CrateType::Staticlib + | CrateType::StaticLib | CrateType::Cdylib | CrateType::ProcMacro | CrateType::Sdylib => true, diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 59d0f5ee9d54..9b26a653fbd7 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -28,7 +28,7 @@ fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel { fn crate_export_threshold(crate_type: CrateType) -> SymbolExportLevel { match crate_type { - CrateType::Executable | CrateType::Staticlib | CrateType::ProcMacro | CrateType::Cdylib => { + CrateType::Executable | CrateType::StaticLib | CrateType::ProcMacro | CrateType::Cdylib => { SymbolExportLevel::C } CrateType::Rlib | CrateType::Dylib | CrateType::Sdylib => SymbolExportLevel::Rust, diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index af9c61e17768..8321f7fde503 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -6,7 +6,6 @@ use std::sync::mpsc::{Receiver, Sender, channel}; use std::{fs, io, mem, str, thread}; use rustc_abi::Size; -use rustc_ast::attr; use rustc_data_structures::assert_matches; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::jobserver::{self, Acquired}; @@ -19,6 +18,8 @@ use rustc_errors::{ Level, MultiSpan, Style, Suggestions, catch_fatal_errors, }; use rustc_fs_util::link_or_copy; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::find_attr; use rustc_incremental::{ copy_cgu_workproduct_to_incr_comp_cache_dir, in_incr_comp_dir, in_incr_comp_dir_sess, }; @@ -31,7 +32,7 @@ use rustc_session::config::{ self, CrateType, Lto, OutFileName, OutputFilenames, OutputType, Passes, SwitchWithOptPath, }; use rustc_span::source_map::SourceMap; -use rustc_span::{FileName, InnerSpan, Span, SpanData, sym}; +use rustc_span::{FileName, InnerSpan, Span, SpanData}; use rustc_target::spec::{MergeFunctions, SanitizerSet}; use tracing::debug; @@ -453,7 +454,7 @@ pub(crate) fn start_async_codegen( let (coordinator_send, coordinator_receive) = channel(); let crate_attrs = tcx.hir_attrs(rustc_hir::CRATE_HIR_ID); - let no_builtins = attr::contains_name(crate_attrs, sym::no_builtins); + let no_builtins = find_attr!(crate_attrs, AttributeKind::NoBuiltins); let crate_info = CrateInfo::new(tcx, target_cpu); diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 982a814c1c86..43767dff92bf 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -1009,7 +1009,7 @@ impl CrateInfo { info.linked_symbols .iter_mut() .filter(|(crate_type, _)| { - !matches!(crate_type, CrateType::Rlib | CrateType::Staticlib) + !matches!(crate_type, CrateType::Rlib | CrateType::StaticLib) }) .for_each(|(_, linked_symbols)| { let mut symbols = missing_weak_lang_items @@ -1041,7 +1041,7 @@ impl CrateInfo { // this is a rare use case and we don't want to slow down the common case. false } - CrateType::Staticlib | CrateType::Rlib => { + CrateType::StaticLib | CrateType::Rlib => { // We don't invoke the linker for these, so we don't need to collect the NatVis for // them. false diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index d55e134109d6..4cb390e7d569 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -2,7 +2,7 @@ use std::str::FromStr; use rustc_abi::{Align, ExternAbi}; use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode}; -use rustc_ast::{LitKind, MetaItem, MetaItemInner, attr}; +use rustc_ast::{LitKind, MetaItem, MetaItemInner}; use rustc_hir::attrs::{ AttributeKind, EiiImplResolution, InlineAttr, Linkage, RtsanSetting, UsedBy, }; @@ -353,7 +353,7 @@ fn apply_overrides(tcx: TyCtxt<'_>, did: LocalDefId, codegen_fn_attrs: &mut Code // When `no_builtins` is applied at the crate level, we should add the // `no-builtins` attribute to each function to ensure it takes effect in LTO. let crate_attrs = tcx.hir_attrs(rustc_hir::CRATE_HIR_ID); - let no_builtins = attr::contains_name(crate_attrs, sym::no_builtins); + let no_builtins = find_attr!(crate_attrs, AttributeKind::NoBuiltins); if no_builtins { codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_BUILTINS; } diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 02476a332252..1c88a8da5ea9 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -109,14 +109,14 @@ fn push_debuginfo_type_name<'tcx>( ty_and_layout, &|output, visited| { push_item_name(tcx, def.did(), true, output); - push_generic_params_internal(tcx, args, output, visited); + push_generic_args_internal(tcx, args, output, visited); }, output, visited, ); } else { push_item_name(tcx, def.did(), qualified, output); - push_generic_params_internal(tcx, args, output, visited); + push_generic_args_internal(tcx, args, output, visited); } } ty::Tuple(component_types) => { @@ -253,19 +253,18 @@ fn push_debuginfo_type_name<'tcx>( ); push_item_name(tcx, principal.def_id, qualified, output); let principal_has_generic_params = - push_generic_params_internal(tcx, principal.args, output, visited); + push_generic_args_internal(tcx, principal.args, output, visited); let projection_bounds: SmallVec<[_; 4]> = trait_data .projection_bounds() .map(|bound| { let ExistentialProjection { def_id: item_def_id, term, .. } = tcx.instantiate_bound_regions_with_erased(bound); - // FIXME(mgca): allow for consts here - (item_def_id, term.expect_type()) + (item_def_id, term) }) .collect(); - if projection_bounds.len() != 0 { + if !projection_bounds.is_empty() { if principal_has_generic_params { // push_generic_params_internal() above added a `>` but we actually // want to add more items to that list, so remove that again... @@ -279,17 +278,17 @@ fn push_debuginfo_type_name<'tcx>( output.push('<'); } - for (item_def_id, ty) in projection_bounds { + for (item_def_id, term) in projection_bounds { if cpp_like_debuginfo { output.push_str("assoc$<"); push_item_name(tcx, item_def_id, false, output); push_arg_separator(cpp_like_debuginfo, output); - push_debuginfo_type_name(tcx, ty, true, output, visited); + push_debuginfo_term_name(tcx, term, true, output, visited); push_close_angle_bracket(cpp_like_debuginfo, output); } else { push_item_name(tcx, item_def_id, false, output); output.push('='); - push_debuginfo_type_name(tcx, ty, true, output, visited); + push_debuginfo_term_name(tcx, term, true, output, visited); } push_arg_separator(cpp_like_debuginfo, output); } @@ -533,7 +532,7 @@ pub fn compute_debuginfo_vtable_name<'tcx>( tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), trait_ref); push_item_name(tcx, trait_ref.def_id, true, &mut vtable_name); visited.clear(); - push_generic_params_internal(tcx, trait_ref.args, &mut vtable_name, &mut visited); + push_generic_args_internal(tcx, trait_ref.args, &mut vtable_name, &mut visited); } else { vtable_name.push('_'); } @@ -631,7 +630,13 @@ fn push_unqualified_item_name( }; } -fn push_generic_params_internal<'tcx>( +pub fn push_generic_args<'tcx>(tcx: TyCtxt<'tcx>, args: GenericArgsRef<'tcx>, output: &mut String) { + let _prof = tcx.prof.generic_activity("compute_debuginfo_type_name"); + let mut visited = FxHashSet::default(); + push_generic_args_internal(tcx, args, output, &mut visited); +} + +fn push_generic_args_internal<'tcx>( tcx: TyCtxt<'tcx>, args: GenericArgsRef<'tcx>, output: &mut String, @@ -646,14 +651,10 @@ fn push_generic_params_internal<'tcx>( output.push('<'); - for type_parameter in args { - match type_parameter { - GenericArgKind::Type(type_parameter) => { - push_debuginfo_type_name(tcx, type_parameter, true, output, visited); - } - GenericArgKind::Const(ct) => { - push_const_param(tcx, ct, output); - } + for arg in args { + match arg { + GenericArgKind::Type(ty) => push_debuginfo_type_name(tcx, ty, true, output, visited), + GenericArgKind::Const(ct) => push_debuginfo_const_name(tcx, ct, output), other => bug!("Unexpected non-erasable generic: {:?}", other), } @@ -665,7 +666,20 @@ fn push_generic_params_internal<'tcx>( true } -fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut String) { +fn push_debuginfo_term_name<'tcx>( + tcx: TyCtxt<'tcx>, + term: ty::Term<'tcx>, + qualified: bool, + output: &mut String, + visited: &mut FxHashSet>, +) { + match term.kind() { + ty::TermKind::Ty(ty) => push_debuginfo_type_name(tcx, ty, qualified, output, visited), + ty::TermKind::Const(ct) => push_debuginfo_const_name(tcx, ct, output), + } +} + +fn push_debuginfo_const_name<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut String) { match ct.kind() { ty::ConstKind::Param(param) => { write!(output, "{}", param.name) @@ -715,16 +729,6 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S .unwrap(); } -pub fn push_generic_params<'tcx>( - tcx: TyCtxt<'tcx>, - args: GenericArgsRef<'tcx>, - output: &mut String, -) { - let _prof = tcx.prof.generic_activity("compute_debuginfo_type_name"); - let mut visited = FxHashSet::default(); - push_generic_params_internal(tcx, args, output, &mut visited); -} - fn push_closure_or_coroutine_name<'tcx>( tcx: TyCtxt<'tcx>, def_id: DefId, @@ -767,7 +771,7 @@ fn push_closure_or_coroutine_name<'tcx>( // FIXME(async_closures): This is probably not going to be correct w.r.t. // multiple coroutine flavors. Maybe truncate to (parent + 1)? let args = args.truncate_to(tcx, generics); - push_generic_params_internal(tcx, args, output, visited); + push_generic_args_internal(tcx, args, output, visited); } fn push_close_angle_bracket(cpp_like_debuginfo: bool, output: &mut String) { diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index d22546dee565..35de8b5e1486 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -199,12 +199,12 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { // do an invoke, otherwise do a call. let fn_ty = bx.fn_decl_backend_type(fn_abi); - let fn_attrs = if bx.tcx().def_kind(fx.instance.def_id()).has_codegen_attrs() { + let caller_attrs = if bx.tcx().def_kind(fx.instance.def_id()).has_codegen_attrs() { Some(bx.tcx().codegen_instance_attrs(fx.instance.def)) } else { None }; - let fn_attrs = fn_attrs.as_deref(); + let caller_attrs = caller_attrs.as_deref(); if !fn_abi.can_unwind { unwind = mir::UnwindAction::Unreachable; @@ -233,7 +233,7 @@ 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); + bx.tail_call(fn_ty, caller_attrs, fn_abi, fn_ptr, llargs, self.funclet(fx), instance); return MergingSucc::False; } @@ -245,7 +245,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { }; let invokeret = bx.invoke( fn_ty, - fn_attrs, + caller_attrs, Some(fn_abi), fn_ptr, llargs, @@ -268,8 +268,15 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { } MergingSucc::False } else { - let llret = - bx.call(fn_ty, fn_attrs, Some(fn_abi), fn_ptr, llargs, self.funclet(fx), instance); + let llret = bx.call( + fn_ty, + caller_attrs, + Some(fn_abi), + fn_ptr, + llargs, + self.funclet(fx), + instance, + ); if fx.mir[self.bb].is_cleanup { bx.apply_attrs_to_cleanup_callsite(llret); } diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index cb74e2e46d65..625551d17d9d 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -67,7 +67,7 @@ pub trait CodegenBackend { CrateType::Executable, CrateType::Dylib, CrateType::Rlib, - CrateType::Staticlib, + CrateType::StaticLib, CrateType::Cdylib, CrateType::ProcMacro, CrateType::Sdylib, diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index ba36188f05d1..3486bd140ece 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -600,10 +600,13 @@ pub trait BuilderMethods<'a, 'tcx>: /// /// ## Arguments /// - /// The `fn_attrs`, `fn_abi`, and `instance` arguments are Options because they are advisory. - /// They relate to optional codegen enhancements like LLVM CFI, and do not affect ABI per se. - /// Any ABI-related transformations should be handled by different, earlier stages of codegen. - /// For instance, in the caller of `BuilderMethods::call`. + /// `caller_attrs` are the attributes of the surrounding caller; they have nothing to do with + /// the callee. + /// + /// The `caller_attrs`, `fn_abi`, and `callee_instance` arguments are Options because they are + /// advisory. They relate to optional codegen enhancements like LLVM CFI, and do not affect ABI + /// per se. Any ABI-related transformations should be handled by different, earlier stages of + /// codegen. For instance, in the caller of `BuilderMethods::call`. /// /// This means that a codegen backend which disregards `fn_attrs`, `fn_abi`, and `instance` /// should still do correct codegen, and code should not be miscompiled if they are omitted. @@ -620,23 +623,23 @@ pub trait BuilderMethods<'a, 'tcx>: fn call( &mut self, llty: Self::Type, - fn_attrs: Option<&CodegenFnAttrs>, + caller_attrs: Option<&CodegenFnAttrs>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, fn_val: Self::Value, args: &[Self::Value], funclet: Option<&Self::Funclet>, - instance: Option>, + callee_instance: Option>, ) -> Self::Value; fn tail_call( &mut self, llty: Self::Type, - fn_attrs: Option<&CodegenFnAttrs>, + caller_attrs: Option<&CodegenFnAttrs>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, llfn: Self::Value, args: &[Self::Value], funclet: Option<&Self::Funclet>, - instance: Option>, + callee_instance: Option>, ); fn zext(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value; diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs index 02615e3bbc18..fe3891d0dd7e 100644 --- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs @@ -343,17 +343,18 @@ where // Check the qualifs of the value of `const` items. let uneval = match constant.const_ { - Const::Ty(_, ct) - if matches!( - ct.kind(), - ty::ConstKind::Param(_) | ty::ConstKind::Error(_) | ty::ConstKind::Value(_) - ) => - { - None - } - Const::Ty(_, c) => { - bug!("expected ConstKind::Param or ConstKind::Value here, found {:?}", c) - } + Const::Ty(_, ct) => match ct.kind() { + ty::ConstKind::Param(_) | ty::ConstKind::Error(_) => None, + // Unevaluated consts in MIR bodies don't have associated MIR (e.g. `#[type_const]`). + ty::ConstKind::Unevaluated(_) => None, + // FIXME(mgca): Investigate whether using `None` for `ConstKind::Value` is overly + // strict, and if instead we should be doing some kind of value-based analysis. + ty::ConstKind::Value(_) => None, + _ => bug!( + "expected ConstKind::Param, ConstKind::Value, ConstKind::Unevaluated, or ConstKind::Error here, found {:?}", + ct + ), + }, Const::Unevaluated(uv, _) => Some(uv), Const::Val(..) => None, }; @@ -364,10 +365,8 @@ where // check performed after the promotion. Verify that with an assertion. assert!(promoted.is_none() || Q::ALLOW_PROMOTED); - // Don't peak inside trait associated constants, also `#[type_const] const` items - // don't have bodies so there's nothing to look at - if promoted.is_none() && cx.tcx.trait_of_assoc(def).is_none() && !cx.tcx.is_type_const(def) - { + // Don't peak inside trait associated constants. + if promoted.is_none() && cx.tcx.trait_of_assoc(def).is_none() { let qualifs = cx.tcx.at(constant.span).mir_const_qualif(def); if !Q::in_qualifs(&qualifs) { diff --git a/compiler/rustc_const_eval/src/const_eval/type_info.rs b/compiler/rustc_const_eval/src/const_eval/type_info.rs index e6092fc3787c..3fcf6f94b5bf 100644 --- a/compiler/rustc_const_eval/src/const_eval/type_info.rs +++ b/compiler/rustc_const_eval/src/const_eval/type_info.rs @@ -66,6 +66,14 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { variant } + ty::Slice(ty) => { + let (variant, variant_place) = downcast(sym::Slice)?; + let slice_place = self.project_field(&variant_place, FieldIdx::ZERO)?; + + self.write_slice_type_info(slice_place, *ty)?; + + variant + } ty::Bool => { let (variant, _variant_place) = downcast(sym::Bool)?; variant @@ -124,7 +132,6 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { ty::Adt(_, _) | ty::Foreign(_) | ty::Pat(_, _) - | ty::Slice(_) | ty::FnDef(..) | ty::FnPtr(..) | ty::UnsafeBinder(..) @@ -254,6 +261,27 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { interp_ok(()) } + pub(crate) fn write_slice_type_info( + &mut self, + place: impl Writeable<'tcx, CtfeProvenance>, + ty: Ty<'tcx>, + ) -> InterpResult<'tcx> { + // Iterate over all fields of `type_info::Slice`. + for (field_idx, field) in + place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated() + { + let field_place = self.project_field(&place, field_idx)?; + + match field.name { + // Write the `TypeId` of the slice's elements to the `element_ty` field. + sym::element_ty => self.write_type_id(ty, &field_place)?, + other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"), + } + } + + interp_ok(()) + } + fn write_int_type_info( &mut self, place: impl Writeable<'tcx, CtfeProvenance>, diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs index d7fe7801fb08..f61baa006b63 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs @@ -30,7 +30,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let dest = dest.force_mplace(self)?; match intrinsic_name { - sym::simd_insert => { + sym::simd_insert | sym::simd_insert_dyn => { let index = u64::from(self.read_scalar(&args[1])?.to_u32()?); let elem = &args[2]; let (input, input_len) = self.project_to_simd(&args[0])?; @@ -39,7 +39,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Bounds are not checked by typeck so we have to do it ourselves. if index >= input_len { throw_ub_format!( - "`simd_insert` index {index} is out-of-bounds of vector with length {input_len}" + "`{intrinsic_name}` index {index} is out-of-bounds of vector with length {input_len}" ); } @@ -50,13 +50,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.copy_op(&value, &place)?; } } - sym::simd_extract => { + sym::simd_extract | sym::simd_extract_dyn => { let index = u64::from(self.read_scalar(&args[1])?.to_u32()?); let (input, input_len) = self.project_to_simd(&args[0])?; // Bounds are not checked by typeck so we have to do it ourselves. if index >= input_len { throw_ub_format!( - "`simd_extract` index {index} is out-of-bounds of vector with length {input_len}" + "`{intrinsic_name}` index {index} is out-of-bounds of vector with length {input_len}" ); } self.copy_op(&self.project_index(&input, index)?, &dest)?; diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 8377213850b8..85877d73519a 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -10,7 +10,6 @@ #![allow(internal_features)] #![allow(rustc::default_hash_types)] #![allow(rustc::potential_query_instability)] -#![cfg_attr(bootstrap, feature(array_windows))] #![deny(unsafe_op_in_unsafe_fn)] #![feature(allocator_api)] #![feature(ascii_char)] @@ -42,8 +41,11 @@ // have to worry about it being moved to a different module in std during stabilization. // FIXME(#151359): Remove this when `feature(assert_matches)` is stable in stage0. // (This doesn't necessarily need to be fixed during the beta bump itself.) +#[cfg(bootstrap)] pub use std::assert_matches::{assert_matches, debug_assert_matches}; use std::fmt; +#[cfg(not(bootstrap))] +pub use std::{assert_matches, debug_assert_matches}; pub use atomic_ref::AtomicRef; pub use ena::{snapshot_vec, undo_log, unify}; diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 5dee64b42f73..38ee87601614 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -42,6 +42,7 @@ use rustc_feature::find_gated_cfg; // `rust_index` isn't used in this crate's code, but it must be named in the // `Cargo.toml` for the `rustc_randomized_layouts` feature. use rustc_index as _; +use rustc_interface::passes::collect_crate_types; use rustc_interface::util::{self, get_codegen_backend}; use rustc_interface::{Linker, create_and_enter_global_ctxt, interface, passes}; use rustc_lint::unerased_lint_store; @@ -56,10 +57,10 @@ use rustc_session::config::{ }; use rustc_session::getopts::{self, Matches}; use rustc_session::lint::{Lint, LintId}; -use rustc_session::output::{CRATE_TYPES, collect_crate_types, invalid_output_for_target}; +use rustc_session::output::invalid_output_for_target; use rustc_session::{EarlyDiagCtxt, Session, config}; -use rustc_span::FileName; use rustc_span::def_id::LOCAL_CRATE; +use rustc_span::{DUMMY_SP, FileName}; use rustc_target::json::ToJson; use rustc_target::spec::{Target, TargetTuple}; use tracing::trace; @@ -698,6 +699,7 @@ fn print_crate_info( &codegen_backend.supported_crate_types(sess), codegen_backend.name(), attrs, + DUMMY_SP, ); for &style in &crate_types { let fname = rustc_session::output::filename_for_input( @@ -849,7 +851,7 @@ fn print_crate_info( } } SupportedCrateTypes => { - let supported_crate_types = CRATE_TYPES + let supported_crate_types = CrateType::all() .iter() .filter(|(_, crate_type)| !invalid_output_for_target(sess, *crate_type)) .filter(|(_, crate_type)| *crate_type != CrateType::Sdylib) @@ -1534,10 +1536,11 @@ fn report_ice( using_internal_features: &AtomicBool, ) { let translator = default_translator(); - let emitter = Box::new(rustc_errors::emitter::HumanEmitter::new( - stderr_destination(rustc_errors::ColorConfig::Auto), - translator, - )); + let emitter = + Box::new(rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitter::new( + stderr_destination(rustc_errors::ColorConfig::Auto), + translator, + )); let dcx = rustc_errors::DiagCtxt::new(emitter); let dcx = dcx.handle(); diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index 6c5a1740a9a6..81eecca3199f 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -17,7 +17,6 @@ rustc_error_messages = { path = "../rustc_error_messages" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_hashes = { path = "../rustc_hashes" } rustc_index = { path = "../rustc_index" } -rustc_lexer = { path = "../rustc_lexer" } rustc_lint_defs = { path = "../rustc_lint_defs" } rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 4365ceaff22d..a9e81354fc6a 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -15,10 +15,9 @@ use rustc_span::source_map::Spanned; use rustc_span::{DUMMY_SP, Span, Symbol}; use tracing::debug; -use crate::snippet::Style; use crate::{ CodeSuggestion, DiagCtxtHandle, DiagMessage, ErrCode, ErrorGuaranteed, ExplicitBug, Level, - MultiSpan, StashKey, SubdiagMessage, Substitution, SubstitutionPart, SuggestionStyle, + MultiSpan, StashKey, Style, SubdiagMessage, Substitution, SubstitutionPart, SuggestionStyle, Suggestions, }; diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 2e41f74ee25d..3433db1e0704 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -8,42 +8,29 @@ //! The output types are defined in `rustc_session::config::ErrorOutputType`. use std::borrow::Cow; -use std::cmp::{Reverse, max, min}; use std::error::Report; use std::io::prelude::*; use std::io::{self, IsTerminal}; use std::iter; use std::path::Path; -use std::sync::Arc; use anstream::{AutoStream, ColorChoice}; use anstyle::{AnsiColor, Effects}; -use derive_setters::Setters; -use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; -use rustc_data_structures::sync::{DynSend, IntoDynSyncSend}; -use rustc_error_messages::{FluentArgs, SpanLabel}; -use rustc_lexer; -use rustc_lint_defs::pluralize; +use rustc_data_structures::fx::FxIndexSet; +use rustc_data_structures::sync::DynSend; +use rustc_error_messages::FluentArgs; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::SourceMap; -use rustc_span::{FileLines, FileName, SourceFile, Span, char_width, str_width}; -use tracing::{debug, instrument, trace, warn}; +use rustc_span::{FileName, SourceFile, Span}; +use tracing::{debug, warn}; use crate::registry::Registry; -use crate::snippet::{ - Annotation, AnnotationColumn, AnnotationType, Line, MultilineAnnotation, Style, StyledString, -}; -use crate::styled_buffer::StyledBuffer; use crate::timings::TimingRecord; -use crate::translation::{Translator, to_fluent_args}; +use crate::translation::Translator; use crate::{ - CodeSuggestion, DiagInner, DiagMessage, ErrCode, Level, MultiSpan, Subdiag, - SubstitutionHighlight, SuggestionStyle, TerminalUrl, + CodeSuggestion, DiagInner, DiagMessage, Level, MultiSpan, Style, Subdiag, SuggestionStyle, }; -/// Default column width, used in tests and when terminal dimensions cannot be determined. -const DEFAULT_COLUMN_WIDTH: usize = 140; - /// Describes the way the content of the `rendered` field of the json output is generated #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct HumanReadableErrorType { @@ -57,119 +44,11 @@ impl HumanReadableErrorType { } } -#[derive(Clone, Copy, Debug)] -struct Margin { - /// The available whitespace in the left that can be consumed when centering. - pub whitespace_left: usize, - /// The column of the beginning of leftmost span. - pub span_left: usize, - /// The column of the end of rightmost span. - pub span_right: usize, - /// The beginning of the line to be displayed. - pub computed_left: usize, - /// The end of the line to be displayed. - pub computed_right: usize, - /// The current width of the terminal. Uses value of `DEFAULT_COLUMN_WIDTH` constant by default - /// and in tests. - pub column_width: usize, - /// The end column of a span label, including the span. Doesn't account for labels not in the - /// same line as the span. - pub label_right: usize, -} - -impl Margin { - fn new( - whitespace_left: usize, - span_left: usize, - span_right: usize, - label_right: usize, - column_width: usize, - max_line_len: usize, - ) -> Self { - // The 6 is padding to give a bit of room for `...` when displaying: - // ``` - // error: message - // --> file.rs:16:58 - // | - // 16 | ... fn foo(self) -> Self::Bar { - // | ^^^^^^^^^ - // ``` - - let mut m = Margin { - whitespace_left: whitespace_left.saturating_sub(6), - span_left: span_left.saturating_sub(6), - span_right: span_right + 6, - computed_left: 0, - computed_right: 0, - column_width, - label_right: label_right + 6, - }; - m.compute(max_line_len); - m - } - - fn was_cut_left(&self) -> bool { - self.computed_left > 0 - } - - fn compute(&mut self, max_line_len: usize) { - // When there's a lot of whitespace (>20), we want to trim it as it is useless. - // FIXME: this doesn't account for '\t', but to do so correctly we need to perform that - // calculation later, right before printing in order to be accurate with both unicode - // handling and trimming of long lines. - self.computed_left = if self.whitespace_left > 20 { - self.whitespace_left - 16 // We want some padding. - } else { - 0 - }; - // We want to show as much as possible, max_line_len is the rightmost boundary for the - // relevant code. - self.computed_right = max(max_line_len, self.computed_left); - - if self.computed_right - self.computed_left > self.column_width { - // Trimming only whitespace isn't enough, let's get craftier. - if self.label_right - self.whitespace_left <= self.column_width { - // Attempt to fit the code window only trimming whitespace. - self.computed_left = self.whitespace_left; - self.computed_right = self.computed_left + self.column_width; - } else if self.label_right - self.span_left <= self.column_width { - // Attempt to fit the code window considering only the spans and labels. - let padding_left = (self.column_width - (self.label_right - self.span_left)) / 2; - self.computed_left = self.span_left.saturating_sub(padding_left); - self.computed_right = self.computed_left + self.column_width; - } else if self.span_right - self.span_left <= self.column_width { - // Attempt to fit the code window considering the spans and labels plus padding. - let padding_left = (self.column_width - (self.span_right - self.span_left)) / 5 * 2; - self.computed_left = self.span_left.saturating_sub(padding_left); - self.computed_right = self.computed_left + self.column_width; - } else { - // Mostly give up but still don't show the full line. - self.computed_left = self.span_left; - self.computed_right = self.span_right; - } - } - } - - fn left(&self, line_len: usize) -> usize { - min(self.computed_left, line_len) - } - - fn right(&self, line_len: usize) -> usize { - if line_len.saturating_sub(self.computed_left) <= self.column_width { - line_len - } else { - min(line_len, self.computed_right) - } - } -} - pub enum TimingEvent { Start, End, } -const ANONYMIZED_LINE_NUM: &str = "LL"; - pub type DynEmitter = dyn Emitter + DynSend; /// Emitter trait for emitting errors and other structured information. @@ -490,48 +369,6 @@ pub trait Emitter { } } -impl Emitter for HumanEmitter { - fn source_map(&self) -> Option<&SourceMap> { - self.sm.as_deref() - } - - fn emit_diagnostic(&mut self, mut diag: DiagInner, _registry: &Registry) { - let fluent_args = to_fluent_args(diag.args.iter()); - - if self.track_diagnostics && diag.span.has_primary_spans() && !diag.span.is_dummy() { - diag.children.insert(0, diag.emitted_at_sub_diag()); - } - - let mut suggestions = diag.suggestions.unwrap_tag(); - self.primary_span_formatted(&mut diag.span, &mut suggestions, &fluent_args); - - self.fix_multispans_in_extern_macros_and_render_macro_backtrace( - &mut diag.span, - &mut diag.children, - &diag.level, - self.macro_backtrace, - ); - - self.emit_messages_default( - &diag.level, - &diag.messages, - &fluent_args, - &diag.code, - &diag.span, - &diag.children, - &suggestions, - ); - } - - fn should_show_explain(&self) -> bool { - !self.short_message - } - - fn translator(&self) -> &Translator { - &self.translator - } -} - /// An emitter that adds a note to each diagnostic. pub struct EmitterWithNote { pub emitter: Box, @@ -604,2703 +441,6 @@ pub enum OutputTheme { Unicode, } -/// Handles the writing of `HumanReadableErrorType` -#[derive(Setters)] -pub struct HumanEmitter { - #[setters(skip)] - dst: IntoDynSyncSend, - sm: Option>, - #[setters(skip)] - translator: Translator, - short_message: bool, - ui_testing: bool, - ignored_directories_in_source_blocks: Vec, - diagnostic_width: Option, - - macro_backtrace: bool, - track_diagnostics: bool, - terminal_url: TerminalUrl, - theme: OutputTheme, -} - -#[derive(Debug)] -pub(crate) struct FileWithAnnotatedLines { - pub(crate) file: Arc, - pub(crate) lines: Vec, - multiline_depth: usize, -} - -impl HumanEmitter { - pub fn new(dst: Destination, translator: Translator) -> HumanEmitter { - HumanEmitter { - dst: IntoDynSyncSend(dst), - sm: None, - translator, - short_message: false, - ui_testing: false, - ignored_directories_in_source_blocks: Vec::new(), - diagnostic_width: None, - macro_backtrace: false, - track_diagnostics: false, - terminal_url: TerminalUrl::No, - theme: OutputTheme::Ascii, - } - } - - fn maybe_anonymized(&self, line_num: usize) -> Cow<'static, str> { - if self.ui_testing { - Cow::Borrowed(ANONYMIZED_LINE_NUM) - } else { - Cow::Owned(line_num.to_string()) - } - } - - fn draw_line( - &self, - buffer: &mut StyledBuffer, - source_string: &str, - line_index: usize, - line_offset: usize, - width_offset: usize, - code_offset: usize, - margin: Margin, - ) -> usize { - let line_len = source_string.len(); - // Create the source line we will highlight. - let left = margin.left(line_len); - let right = margin.right(line_len); - // FIXME: The following code looks fishy. See #132860. - // On long lines, we strip the source line, accounting for unicode. - let code: String = source_string - .chars() - .enumerate() - .skip_while(|(i, _)| *i < left) - .take_while(|(i, _)| *i < right) - .map(|(_, c)| c) - .collect(); - let code = normalize_whitespace(&code); - let was_cut_right = - source_string.chars().enumerate().skip_while(|(i, _)| *i < right).next().is_some(); - buffer.puts(line_offset, code_offset, &code, Style::Quotation); - let placeholder = self.margin(); - if margin.was_cut_left() { - // We have stripped some code/whitespace from the beginning, make it clear. - buffer.puts(line_offset, code_offset, placeholder, Style::LineNumber); - } - if was_cut_right { - let padding = str_width(placeholder); - // We have stripped some code after the rightmost span end, make it clear we did so. - buffer.puts( - line_offset, - code_offset + str_width(&code) - padding, - placeholder, - Style::LineNumber, - ); - } - self.draw_line_num(buffer, line_index, line_offset, width_offset - 3); - self.draw_col_separator_no_space(buffer, line_offset, width_offset - 2); - left - } - - #[instrument(level = "trace", skip(self), ret)] - fn render_source_line( - &self, - buffer: &mut StyledBuffer, - file: Arc, - line: &Line, - width_offset: usize, - code_offset: usize, - margin: Margin, - close_window: bool, - ) -> Vec<(usize, Style)> { - // Draw: - // - // LL | ... code ... - // | ^^-^ span label - // | | - // | secondary span label - // - // ^^ ^ ^^^ ^^^^ ^^^ we don't care about code too far to the right of a span, we trim it - // | | | | - // | | | actual code found in your source code and the spans we use to mark it - // | | when there's too much wasted space to the left, trim it - // | vertical divider between the column number and the code - // column number - - if line.line_index == 0 { - return Vec::new(); - } - - let Some(source_string) = file.get_line(line.line_index - 1) else { - return Vec::new(); - }; - trace!(?source_string); - - let line_offset = buffer.num_lines(); - - // Left trim. - // FIXME: This looks fishy. See #132860. - let left = self.draw_line( - buffer, - &source_string, - line.line_index, - line_offset, - width_offset, - code_offset, - margin, - ); - - // Special case when there's only one annotation involved, it is the start of a multiline - // span and there's no text at the beginning of the code line. Instead of doing the whole - // graph: - // - // 2 | fn foo() { - // | _^ - // 3 | | - // 4 | | } - // | |_^ test - // - // we simplify the output to: - // - // 2 | / fn foo() { - // 3 | | - // 4 | | } - // | |_^ test - let mut buffer_ops = vec![]; - let mut annotations = vec![]; - let mut short_start = true; - for ann in &line.annotations { - if let AnnotationType::MultilineStart(depth) = ann.annotation_type { - if source_string.chars().take(ann.start_col.file).all(|c| c.is_whitespace()) { - let uline = self.underline(ann.is_primary); - let chr = uline.multiline_whole_line; - annotations.push((depth, uline.style)); - buffer_ops.push((line_offset, width_offset + depth - 1, chr, uline.style)); - } else { - short_start = false; - break; - } - } else if let AnnotationType::MultilineLine(_) = ann.annotation_type { - } else { - short_start = false; - break; - } - } - if short_start { - for (y, x, c, s) in buffer_ops { - buffer.putc(y, x, c, s); - } - return annotations; - } - - // We want to display like this: - // - // vec.push(vec.pop().unwrap()); - // --- ^^^ - previous borrow ends here - // | | - // | error occurs here - // previous borrow of `vec` occurs here - // - // But there are some weird edge cases to be aware of: - // - // vec.push(vec.pop().unwrap()); - // -------- - previous borrow ends here - // || - // |this makes no sense - // previous borrow of `vec` occurs here - // - // For this reason, we group the lines into "highlight lines" - // and "annotations lines", where the highlight lines have the `^`. - - // Sort the annotations by (start, end col) - // The labels are reversed, sort and then reversed again. - // Consider a list of annotations (A1, A2, C1, C2, B1, B2) where - // the letter signifies the span. Here we are only sorting by the - // span and hence, the order of the elements with the same span will - // not change. On reversing the ordering (|a, b| but b.cmp(a)), you get - // (C1, C2, B1, B2, A1, A2). All the elements with the same span are - // still ordered first to last, but all the elements with different - // spans are ordered by their spans in last to first order. Last to - // first order is important, because the jiggly lines and | are on - // the left, so the rightmost span needs to be rendered first, - // otherwise the lines would end up needing to go over a message. - - let mut annotations = line.annotations.clone(); - annotations.sort_by_key(|a| Reverse(a.start_col)); - - // First, figure out where each label will be positioned. - // - // In the case where you have the following annotations: - // - // vec.push(vec.pop().unwrap()); - // -------- - previous borrow ends here [C] - // || - // |this makes no sense [B] - // previous borrow of `vec` occurs here [A] - // - // `annotations_position` will hold [(2, A), (1, B), (0, C)]. - // - // We try, when possible, to stick the rightmost annotation at the end - // of the highlight line: - // - // vec.push(vec.pop().unwrap()); - // --- --- - previous borrow ends here - // - // But sometimes that's not possible because one of the other - // annotations overlaps it. For example, from the test - // `span_overlap_label`, we have the following annotations - // (written on distinct lines for clarity): - // - // fn foo(x: u32) { - // -------------- - // - - // - // In this case, we can't stick the rightmost-most label on - // the highlight line, or we would get: - // - // fn foo(x: u32) { - // -------- x_span - // | - // fn_span - // - // which is totally weird. Instead we want: - // - // fn foo(x: u32) { - // -------------- - // | | - // | x_span - // fn_span - // - // which is...less weird, at least. In fact, in general, if - // the rightmost span overlaps with any other span, we should - // use the "hang below" version, so we can at least make it - // clear where the span *starts*. There's an exception for this - // logic, when the labels do not have a message: - // - // fn foo(x: u32) { - // -------------- - // | - // x_span - // - // instead of: - // - // fn foo(x: u32) { - // -------------- - // | | - // | x_span - // - // - let mut overlap = vec![false; annotations.len()]; - let mut annotations_position = vec![]; - let mut line_len: usize = 0; - let mut p = 0; - for (i, annotation) in annotations.iter().enumerate() { - for (j, next) in annotations.iter().enumerate() { - if overlaps(next, annotation, 0) && j > i { - overlap[i] = true; - overlap[j] = true; - } - if overlaps(next, annotation, 0) // This label overlaps with another one and both - && annotation.has_label() // take space (they have text and are not - && j > i // multiline lines). - && p == 0 - // We're currently on the first line, move the label one line down - { - // If we're overlapping with an un-labelled annotation with the same span - // we can just merge them in the output - if next.start_col == annotation.start_col - && next.end_col == annotation.end_col - && !next.has_label() - { - continue; - } - - // This annotation needs a new line in the output. - p += 1; - break; - } - } - annotations_position.push((p, annotation)); - for (j, next) in annotations.iter().enumerate() { - if j > i { - let l = next.label.as_ref().map_or(0, |label| label.len() + 2); - if (overlaps(next, annotation, l) // Do not allow two labels to be in the same - // line if they overlap including padding, to - // avoid situations like: - // - // fn foo(x: u32) { - // -------^------ - // | | - // fn_spanx_span - // - && annotation.has_label() // Both labels must have some text, otherwise - && next.has_label()) // they are not overlapping. - // Do not add a new line if this annotation - // or the next are vertical line placeholders. - || (annotation.takes_space() // If either this or the next annotation is - && next.has_label()) // multiline start/end, move it to a new line - || (annotation.has_label() // so as not to overlap the horizontal lines. - && next.takes_space()) - || (annotation.takes_space() && next.takes_space()) - || (overlaps(next, annotation, l) - && next.end_col <= annotation.end_col - && next.has_label() - && p == 0) - // Avoid #42595. - { - // This annotation needs a new line in the output. - p += 1; - break; - } - } - } - line_len = max(line_len, p); - } - - if line_len != 0 { - line_len += 1; - } - - // If there are no annotations or the only annotations on this line are - // MultilineLine, then there's only code being shown, stop processing. - if line.annotations.iter().all(|a| a.is_line()) { - return vec![]; - } - - if annotations_position - .iter() - .all(|(_, ann)| matches!(ann.annotation_type, AnnotationType::MultilineStart(_))) - && let Some(max_pos) = annotations_position.iter().map(|(pos, _)| *pos).max() - { - // Special case the following, so that we minimize overlapping multiline spans. - // - // 3 │ X0 Y0 Z0 - // │ ┏━━━━━┛ │ │ < We are writing these lines - // │ ┃┌───────┘ │ < by reverting the "depth" of - // │ ┃│┌─────────┘ < their multiline spans. - // 4 │ ┃││ X1 Y1 Z1 - // 5 │ ┃││ X2 Y2 Z2 - // │ ┃│└────╿──│──┘ `Z` label - // │ ┃└─────│──┤ - // │ ┗━━━━━━┥ `Y` is a good letter too - // ╰╴ `X` is a good letter - for (pos, _) in &mut annotations_position { - *pos = max_pos - *pos; - } - // We know then that we don't need an additional line for the span label, saving us - // one line of vertical space. - line_len = line_len.saturating_sub(1); - } - - // Write the column separator. - // - // After this we will have: - // - // 2 | fn foo() { - // | - // | - // | - // 3 | - // 4 | } - // | - for pos in 0..=line_len { - self.draw_col_separator_no_space(buffer, line_offset + pos + 1, width_offset - 2); - } - if close_window { - self.draw_col_separator_end(buffer, line_offset + line_len + 1, width_offset - 2); - } - - // Write the horizontal lines for multiline annotations - // (only the first and last lines need this). - // - // After this we will have: - // - // 2 | fn foo() { - // | __________ - // | - // | - // 3 | - // 4 | } - // | _ - for &(pos, annotation) in &annotations_position { - let underline = self.underline(annotation.is_primary); - let pos = pos + 1; - match annotation.annotation_type { - AnnotationType::MultilineStart(depth) | AnnotationType::MultilineEnd(depth) => { - let pre: usize = source_string - .chars() - .take(annotation.start_col.file) - .skip(left) - .map(|c| char_width(c)) - .sum(); - self.draw_range( - buffer, - underline.multiline_horizontal, - line_offset + pos, - width_offset + depth, - code_offset + pre, - underline.style, - ); - } - _ => {} - } - } - - // Write the vertical lines for labels that are on a different line as the underline. - // - // After this we will have: - // - // 2 | fn foo() { - // | __________ - // | | | - // | | - // 3 | | - // 4 | | } - // | |_ - for &(pos, annotation) in &annotations_position { - let underline = self.underline(annotation.is_primary); - let pos = pos + 1; - - let code_offset = code_offset - + source_string - .chars() - .take(annotation.start_col.file) - .skip(left) - .map(|c| char_width(c)) - .sum::(); - if pos > 1 && (annotation.has_label() || annotation.takes_space()) { - for p in line_offset + 1..=line_offset + pos { - buffer.putc( - p, - code_offset, - match annotation.annotation_type { - AnnotationType::MultilineLine(_) => underline.multiline_vertical, - _ => underline.vertical_text_line, - }, - underline.style, - ); - } - if let AnnotationType::MultilineStart(_) = annotation.annotation_type { - buffer.putc( - line_offset + pos, - code_offset, - underline.bottom_right, - underline.style, - ); - } - if let AnnotationType::MultilineEnd(_) = annotation.annotation_type - && annotation.has_label() - { - buffer.putc( - line_offset + pos, - code_offset, - underline.multiline_bottom_right_with_text, - underline.style, - ); - } - } - match annotation.annotation_type { - AnnotationType::MultilineStart(depth) => { - buffer.putc( - line_offset + pos, - width_offset + depth - 1, - underline.top_left, - underline.style, - ); - for p in line_offset + pos + 1..line_offset + line_len + 2 { - buffer.putc( - p, - width_offset + depth - 1, - underline.multiline_vertical, - underline.style, - ); - } - } - AnnotationType::MultilineEnd(depth) => { - for p in line_offset..line_offset + pos { - buffer.putc( - p, - width_offset + depth - 1, - underline.multiline_vertical, - underline.style, - ); - } - buffer.putc( - line_offset + pos, - width_offset + depth - 1, - underline.bottom_left, - underline.style, - ); - } - _ => (), - } - } - - // Write the labels on the annotations that actually have a label. - // - // After this we will have: - // - // 2 | fn foo() { - // | __________ - // | | - // | something about `foo` - // 3 | - // 4 | } - // | _ test - for &(pos, annotation) in &annotations_position { - let style = - if annotation.is_primary { Style::LabelPrimary } else { Style::LabelSecondary }; - let (pos, col) = if pos == 0 { - let pre: usize = source_string - .chars() - .take(annotation.end_col.file) - .skip(left) - .map(|c| char_width(c)) - .sum(); - if annotation.end_col.file == 0 { - (pos + 1, (pre + 2)) - } else { - let pad = if annotation.end_col.file - annotation.start_col.file == 0 { - 2 - } else { - 1 - }; - (pos + 1, (pre + pad)) - } - } else { - let pre: usize = source_string - .chars() - .take(annotation.start_col.file) - .skip(left) - .map(|c| char_width(c)) - .sum(); - (pos + 2, pre) - }; - if let Some(ref label) = annotation.label { - buffer.puts(line_offset + pos, code_offset + col, label, style); - } - } - - // Sort from biggest span to smallest span so that smaller spans are - // represented in the output: - // - // x | fn foo() - // | ^^^---^^ - // | | | - // | | something about `foo` - // | something about `fn foo()` - annotations_position.sort_by_key(|(_, ann)| { - // Decreasing order. When annotations share the same length, prefer `Primary`. - (Reverse(ann.len()), ann.is_primary) - }); - - // Write the underlines. - // - // After this we will have: - // - // 2 | fn foo() { - // | ____-_____^ - // | | - // | something about `foo` - // 3 | - // 4 | } - // | _^ test - for &(pos, annotation) in &annotations_position { - let uline = self.underline(annotation.is_primary); - let width = annotation.end_col.file - annotation.start_col.file; - let previous: String = - source_string.chars().take(annotation.start_col.file).skip(left).collect(); - let underlined: String = - source_string.chars().skip(annotation.start_col.file).take(width).collect(); - debug!(?previous, ?underlined); - let code_offset = code_offset - + source_string - .chars() - .take(annotation.start_col.file) - .skip(left) - .map(|c| char_width(c)) - .sum::(); - let ann_width: usize = source_string - .chars() - .skip(annotation.start_col.file) - .take(width) - .map(|c| char_width(c)) - .sum(); - let ann_width = if ann_width == 0 - && matches!(annotation.annotation_type, AnnotationType::Singleline) - { - 1 - } else { - ann_width - }; - for p in 0..ann_width { - // The default span label underline. - buffer.putc(line_offset + 1, code_offset + p, uline.underline, uline.style); - } - - if pos == 0 - && matches!( - annotation.annotation_type, - AnnotationType::MultilineStart(_) | AnnotationType::MultilineEnd(_) - ) - { - // The beginning of a multiline span with its leftward moving line on the same line. - buffer.putc( - line_offset + 1, - code_offset, - match annotation.annotation_type { - AnnotationType::MultilineStart(_) => uline.top_right_flat, - AnnotationType::MultilineEnd(_) => uline.multiline_end_same_line, - _ => panic!("unexpected annotation type: {annotation:?}"), - }, - uline.style, - ); - } else if pos != 0 - && matches!( - annotation.annotation_type, - AnnotationType::MultilineStart(_) | AnnotationType::MultilineEnd(_) - ) - { - // The beginning of a multiline span with its leftward moving line on another line, - // so we start going down first. - buffer.putc( - line_offset + 1, - code_offset, - match annotation.annotation_type { - AnnotationType::MultilineStart(_) => uline.multiline_start_down, - AnnotationType::MultilineEnd(_) => uline.multiline_end_up, - _ => panic!("unexpected annotation type: {annotation:?}"), - }, - uline.style, - ); - } else if pos != 0 && annotation.has_label() { - // The beginning of a span label with an actual label, we'll point down. - buffer.putc(line_offset + 1, code_offset, uline.label_start, uline.style); - } - } - - // We look for individual *long* spans, and we trim the *middle*, so that we render - // LL | ...= [0, 0, 0, ..., 0, 0]; - // | ^^^^^^^^^^...^^^^^^^ expected `&[u8]`, found `[{integer}; 1680]` - for (i, (_pos, annotation)) in annotations_position.iter().enumerate() { - // Skip cases where multiple spans overlap each other. - if overlap[i] { - continue; - }; - let AnnotationType::Singleline = annotation.annotation_type else { continue }; - let width = annotation.end_col.display - annotation.start_col.display; - if width > margin.column_width * 2 && width > 10 { - // If the terminal is *too* small, we keep at least a tiny bit of the span for - // display. - let pad = max(margin.column_width / 3, 5); - // Code line - buffer.replace( - line_offset, - annotation.start_col.file + pad, - annotation.end_col.file - pad, - self.margin(), - ); - // Underline line - buffer.replace( - line_offset + 1, - annotation.start_col.file + pad, - annotation.end_col.file - pad, - self.margin(), - ); - } - } - annotations_position - .iter() - .filter_map(|&(_, annotation)| match annotation.annotation_type { - AnnotationType::MultilineStart(p) | AnnotationType::MultilineEnd(p) => { - let style = if annotation.is_primary { - Style::LabelPrimary - } else { - Style::LabelSecondary - }; - Some((p, style)) - } - _ => None, - }) - .collect::>() - } - - fn get_multispan_max_line_num(&mut self, msp: &MultiSpan) -> usize { - let Some(ref sm) = self.sm else { - return 0; - }; - - let will_be_emitted = |span: Span| { - !span.is_dummy() && { - let file = sm.lookup_source_file(span.hi()); - should_show_source_code(&self.ignored_directories_in_source_blocks, sm, &file) - } - }; - - let mut max = 0; - for primary_span in msp.primary_spans() { - if will_be_emitted(*primary_span) { - let hi = sm.lookup_char_pos(primary_span.hi()); - max = (hi.line).max(max); - } - } - if !self.short_message { - for span_label in msp.span_labels() { - if will_be_emitted(span_label.span) { - let hi = sm.lookup_char_pos(span_label.span.hi()); - max = (hi.line).max(max); - } - } - } - - max - } - - fn get_max_line_num(&mut self, span: &MultiSpan, children: &[Subdiag]) -> usize { - let primary = self.get_multispan_max_line_num(span); - children - .iter() - .map(|sub| self.get_multispan_max_line_num(&sub.span)) - .max() - .unwrap_or(0) - .max(primary) - } - - /// Adds a left margin to every line but the first, given a padding length and the label being - /// displayed, keeping the provided highlighting. - fn msgs_to_buffer( - &self, - buffer: &mut StyledBuffer, - msgs: &[(DiagMessage, Style)], - args: &FluentArgs<'_>, - padding: usize, - label: &str, - override_style: Option