diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 10a8e181c840e..cbdc89f9deedc 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -6,7 +6,6 @@ // tidy-alphabetical-start #![cfg_attr(bootstrap, feature(array_windows))] -#![deny(clippy::manual_let_else)] #![doc(test(attr(deny(warnings), allow(internal_features))))] #![feature(associated_type_defaults)] #![feature(box_patterns)] diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index d82357fca2d45..8d61ffde116c5 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -2,7 +2,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![deny(clippy::manual_let_else)] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(file_buffered)] diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index a7a3bbebed5f1..44c817b33184e 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -6,14 +6,17 @@ mod simd; use std::assert_matches::assert_matches; -use rustc_abi::{FieldIdx, HasDataLayout, Size, VariantIdx}; +use rustc_abi::{FIRST_VARIANT, FieldIdx, HasDataLayout, Size, VariantIdx}; use rustc_apfloat::ieee::{Double, Half, Quad, Single}; +use rustc_hir::def_id::CRATE_DEF_ID; +use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir::interpret::{CTFE_ALLOC_SALT, read_target_uint, write_target_uint}; use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic}; use rustc_middle::ty::layout::TyAndLayout; -use rustc_middle::ty::{FloatTy, Ty, TyCtxt}; +use rustc_middle::ty::{FloatTy, PolyExistentialPredicate, Ty, TyCtxt, TypeFoldable}; use rustc_middle::{bug, span_bug, ty}; use rustc_span::{Symbol, sym}; +use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt}; use tracing::trace; use super::memory::MemoryKind; @@ -219,6 +222,49 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.write_scalar(Scalar::from_target_usize(offset, self), dest)?; } + sym::vtable_for => { + let tp_ty = instance.args.type_at(0); + let result_ty = instance.args.type_at(1); + + ensure_monomorphic_enough(tcx, tp_ty)?; + ensure_monomorphic_enough(tcx, result_ty)?; + let ty::Dynamic(preds, _) = result_ty.kind() else { + span_bug!( + self.find_closest_untracked_caller_location(), + "Invalid type provided to vtable_for::. U must be dyn Trait, got {result_ty}." + ); + }; + + let (infcx, param_env) = + self.tcx.infer_ctxt().build_with_typing_env(self.typing_env); + + let ocx = ObligationCtxt::new(&infcx); + ocx.register_obligations(preds.iter().map(|pred: PolyExistentialPredicate<'_>| { + let pred = pred.with_self_ty(tcx, tp_ty); + // Lifetimes can only be 'static because of the bound on T + let pred = pred.fold_with(&mut ty::BottomUpFolder { + tcx, + ty_op: |ty| ty, + lt_op: |lt| { + if lt == tcx.lifetimes.re_erased { tcx.lifetimes.re_static } else { lt } + }, + ct_op: |ct| ct, + }); + Obligation::new(tcx, ObligationCause::dummy(), param_env, pred) + })); + let type_impls_trait = ocx.evaluate_obligations_error_on_ambiguity().is_empty(); + // Since `assumed_wf_tys=[]` the choice of LocalDefId is irrelevant, so using the "default" + let regions_are_valid = ocx.resolve_regions(CRATE_DEF_ID, param_env, []).is_empty(); + + if regions_are_valid && type_impls_trait { + let vtable_ptr = self.get_vtable_ptr(tp_ty, preds)?; + // Writing a non-null pointer into an `Option` will automatically make it `Some`. + self.write_pointer(vtable_ptr, dest)?; + } else { + // Write `None` + self.write_discriminant(FIRST_VARIANT, dest)?; + } + } sym::variant_count => { let tp_ty = instance.args.type_at(0); let ty = match tp_ty.kind() { diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 6c74ed2a5121d..2fce4b8c0566e 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -1,6 +1,5 @@ // tidy-alphabetical-start #![allow(rustc::diagnostic_outside_of_impl)] -#![deny(clippy::manual_let_else)] #![feature(array_try_map)] #![feature(assert_matches)] #![feature(box_patterns)] diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs index 7f64dc3df23ed..9bb3189739582 100644 --- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs +++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs @@ -303,17 +303,6 @@ impl AnnotateSnippetEmitter { } } - let suggestions_expected = suggestions - .iter() - .filter(|s| { - matches!( - s.style, - SuggestionStyle::HideCodeInline - | SuggestionStyle::ShowCode - | SuggestionStyle::ShowAlways - ) - }) - .count(); for suggestion in suggestions { match suggestion.style { SuggestionStyle::CompletelyHidden => { @@ -526,12 +515,6 @@ impl AnnotateSnippetEmitter { } } - // FIXME: This hack should be removed once annotate_snippets is the - // default emitter. - if suggestions_expected > 0 && report.is_empty() { - group = group.element(Padding); - } - if !group.is_empty() { report.push(group); } diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 78feb60261bd8..2e41f74ee25d8 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -46,17 +46,14 @@ 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 enum HumanReadableErrorType { - Default { short: bool }, - AnnotateSnippet { short: bool, unicode: bool }, +pub struct HumanReadableErrorType { + pub short: bool, + pub unicode: bool, } impl HumanReadableErrorType { pub fn short(&self) -> bool { - match self { - HumanReadableErrorType::Default { short } - | HumanReadableErrorType::AnnotateSnippet { short, .. } => *short, - } + self.short } } @@ -607,7 +604,7 @@ pub enum OutputTheme { Unicode, } -/// Handles the writing of `HumanReadableErrorType::Default` and `HumanReadableErrorType::Short` +/// Handles the writing of `HumanReadableErrorType` #[derive(Setters)] pub struct HumanEmitter { #[setters(skip)] diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index 3b8c8baa5eff8..85801245bea90 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -28,8 +28,8 @@ use serde::Serialize; use crate::annotate_snippet_emitter_writer::AnnotateSnippetEmitter; use crate::diagnostic::IsLint; use crate::emitter::{ - ColorConfig, Destination, Emitter, HumanEmitter, HumanReadableErrorType, OutputTheme, - TimingEvent, should_show_source_code, + ColorConfig, Destination, Emitter, HumanReadableErrorType, OutputTheme, TimingEvent, + should_show_source_code, }; use crate::registry::Registry; use crate::timings::{TimingRecord, TimingSection}; @@ -378,38 +378,17 @@ impl Diagnostic { choice => choice, }, ); - match je.json_rendered { - HumanReadableErrorType::AnnotateSnippet { short, unicode } => { - AnnotateSnippetEmitter::new(dst, je.translator.clone()) - .short_message(short) - .sm(je.sm.clone()) - .diagnostic_width(je.diagnostic_width) - .macro_backtrace(je.macro_backtrace) - .track_diagnostics(je.track_diagnostics) - .terminal_url(je.terminal_url) - .ui_testing(je.ui_testing) - .ignored_directories_in_source_blocks( - je.ignored_directories_in_source_blocks.clone(), - ) - .theme(if unicode { OutputTheme::Unicode } else { OutputTheme::Ascii }) - .emit_diagnostic(diag, registry) - } - HumanReadableErrorType::Default { short } => { - HumanEmitter::new(dst, je.translator.clone()) - .short_message(short) - .sm(je.sm.clone()) - .diagnostic_width(je.diagnostic_width) - .macro_backtrace(je.macro_backtrace) - .track_diagnostics(je.track_diagnostics) - .terminal_url(je.terminal_url) - .ui_testing(je.ui_testing) - .ignored_directories_in_source_blocks( - je.ignored_directories_in_source_blocks.clone(), - ) - .theme(OutputTheme::Ascii) - .emit_diagnostic(diag, registry) - } - } + AnnotateSnippetEmitter::new(dst, je.translator.clone()) + .short_message(je.json_rendered.short) + .sm(je.sm.clone()) + .diagnostic_width(je.diagnostic_width) + .macro_backtrace(je.macro_backtrace) + .track_diagnostics(je.track_diagnostics) + .terminal_url(je.terminal_url) + .ui_testing(je.ui_testing) + .ignored_directories_in_source_blocks(je.ignored_directories_in_source_blocks.clone()) + .theme(if je.json_rendered.unicode { OutputTheme::Unicode } else { OutputTheme::Ascii }) + .emit_diagnostic(diag, registry); let buf = Arc::try_unwrap(buf.0).unwrap().into_inner().unwrap(); let buf = String::from_utf8(buf).unwrap(); diff --git a/compiler/rustc_errors/src/json/tests.rs b/compiler/rustc_errors/src/json/tests.rs index 30be06ae0bd3b..c1c9ecf7198f6 100644 --- a/compiler/rustc_errors/src/json/tests.rs +++ b/compiler/rustc_errors/src/json/tests.rs @@ -54,7 +54,7 @@ fn test_positions(code: &str, span: (u32, u32), expected_output: SpanTestData) { Some(sm), translator, true, // pretty - HumanReadableErrorType::Default { short: true }, + HumanReadableErrorType { short: true, unicode: false }, ColorConfig::Never, ); diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index c27954b6d14e4..7a5776f0d5a93 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -4,7 +4,6 @@ // tidy-alphabetical-start #![cfg_attr(bootstrap, feature(debug_closure_helpers))] -#![deny(clippy::manual_let_else)] #![feature(associated_type_defaults)] #![feature(closure_track_caller)] #![feature(const_default)] diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 676c9a980afff..4e8333f678b66 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -215,6 +215,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::type_name | sym::ub_checks | sym::variant_count + | sym::vtable_for | sym::wrapping_add | sym::wrapping_mul | sym::wrapping_sub @@ -643,6 +644,20 @@ pub(crate) fn check_intrinsic_type( (0, 0, vec![Ty::new_imm_ptr(tcx, tcx.types.unit)], tcx.types.usize) } + sym::vtable_for => { + let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, span); + let dyn_metadata_adt_ref = tcx.adt_def(dyn_metadata); + let dyn_metadata_args = tcx.mk_args(&[param(1).into()]); + let dyn_ty = Ty::new_adt(tcx, dyn_metadata_adt_ref, dyn_metadata_args); + + let option_did = tcx.require_lang_item(LangItem::Option, span); + let option_adt_ref = tcx.adt_def(option_did); + let option_args = tcx.mk_args(&[dyn_ty.into()]); + let ret_ty = Ty::new_adt(tcx, option_adt_ref, option_args); + + (2, 0, vec![], ret_ty) + } + // This type check is not particularly useful, but the `where` bounds // on the definition in `core` do the heavy lifting for checking it. sym::aggregate_raw_ptr => (3, 0, vec![param(1), param(2)], param(0)), diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 79c5fbab1ffa2..538fb8c7df1ea 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -59,7 +59,6 @@ This API is completely unstable and subject to change. #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] #![cfg_attr(bootstrap, feature(debug_closure_helpers))] -#![deny(clippy::manual_let_else)] #![feature(assert_matches)] #![feature(gen_blocks)] #![feature(if_let_guard)] diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 9ca5ddd494aeb..d3ef1d63e8ba9 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -1,5 +1,4 @@ // tidy-alphabetical-start -#![deny(clippy::manual_let_else)] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(if_let_guard)] diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 89b8a5fddb89e..8dab3a7f37f59 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -321,7 +321,7 @@ fn test_search_paths_tracking_hash_different_order() { let early_dcx = EarlyDiagCtxt::new(JSON); const JSON: ErrorOutputType = ErrorOutputType::Json { pretty: false, - json_rendered: HumanReadableErrorType::Default { short: false }, + json_rendered: HumanReadableErrorType { short: false, unicode: false }, color_config: ColorConfig::Never, }; diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 49929a0a9bc76..4e7a3e4051767 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -22,7 +22,6 @@ // tidy-alphabetical-start #![allow(internal_features)] #![cfg_attr(bootstrap, feature(array_windows))] -#![deny(clippy::manual_let_else)] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(if_let_guard)] diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index b15ed34fc3569..7da82835befb8 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1451,7 +1451,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { _ => false, } { - continue; + // MGCA doesn't have unnecessary DefIds + if !tcx.features().min_generic_const_args() { + continue; + } } if def_kind == DefKind::Field diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index ee3e89e57bd42..5f62d44df6b61 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -30,7 +30,6 @@ #![allow(rustc::direct_use_of_rustc_type_ir)] #![allow(rustc::untranslatable_diagnostic)] #![cfg_attr(bootstrap, feature(array_windows))] -#![deny(clippy::manual_let_else)] #![feature(allocator_api)] #![feature(assert_matches)] #![feature(associated_type_defaults)] diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index ea64a1e6c64dd..71bbd64ddc6ce 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -357,6 +357,16 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } fn visit_anon_const(&mut self, constant: &'a AnonConst) { + // `MgcaDisambiguation::Direct` is set even when MGCA is disabled, so + // to avoid affecting stable we have to feature gate the not creating + // anon consts + if let MgcaDisambiguation::Direct = constant.mgca_disambiguation + && self.resolver.tcx.features().min_generic_const_args() + { + visit::walk_anon_const(self, constant); + return; + } + let parent = self.create_def(constant.id, None, DefKind::AnonConst, constant.value.span); self.with_parent(parent, |this| visit::walk_anon_const(this, constant)); } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index b3141406e467e..775335e5008c3 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -10,7 +10,6 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -#![deny(clippy::manual_let_else)] #![feature(arbitrary_self_types)] #![feature(assert_matches)] #![feature(box_patterns)] diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index be4b36e3b926c..a3a97dfec61dc 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -806,7 +806,7 @@ pub enum ErrorOutputType { /// Output meant for the consumption of humans. #[default] HumanReadable { - kind: HumanReadableErrorType = HumanReadableErrorType::Default { short: false }, + kind: HumanReadableErrorType = HumanReadableErrorType { short: false, unicode: false }, color_config: ColorConfig = ColorConfig::Auto, }, /// Output that's consumed by other tools such as `rustfix` or the `RLS`. @@ -1965,16 +1965,8 @@ impl JsonUnusedExterns { /// /// The first value returned is how to render JSON diagnostics, and the second /// is whether or not artifact notifications are enabled. -pub fn parse_json( - early_dcx: &EarlyDiagCtxt, - matches: &getopts::Matches, - is_nightly_build: bool, -) -> JsonConfig { - let mut json_rendered = if is_nightly_build { - HumanReadableErrorType::AnnotateSnippet { short: false, unicode: false } - } else { - HumanReadableErrorType::Default { short: false } - }; +pub fn parse_json(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> JsonConfig { + let mut json_rendered = HumanReadableErrorType { short: false, unicode: false }; let mut json_color = ColorConfig::Never; let mut json_artifact_notifications = false; let mut json_unused_externs = JsonUnusedExterns::No; @@ -1991,15 +1983,10 @@ pub fn parse_json( for sub_option in option.split(',') { match sub_option { "diagnostic-short" => { - json_rendered = if is_nightly_build { - HumanReadableErrorType::AnnotateSnippet { short: true, unicode: false } - } else { - HumanReadableErrorType::Default { short: true } - }; + json_rendered = HumanReadableErrorType { short: true, unicode: false }; } "diagnostic-unicode" => { - json_rendered = - HumanReadableErrorType::AnnotateSnippet { short: false, unicode: true }; + json_rendered = HumanReadableErrorType { short: false, unicode: true }; } "diagnostic-rendered-ansi" => json_color = ColorConfig::Always, "artifacts" => json_artifact_notifications = true, @@ -2029,13 +2016,8 @@ pub fn parse_error_format( color_config: ColorConfig, json_color: ColorConfig, json_rendered: HumanReadableErrorType, - is_nightly_build: bool, ) -> ErrorOutputType { - let default_kind = if is_nightly_build { - HumanReadableErrorType::AnnotateSnippet { short: false, unicode: false } - } else { - HumanReadableErrorType::Default { short: false } - }; + let default_kind = HumanReadableErrorType { short: false, unicode: false }; // We need the `opts_present` check because the driver will send us Matches // with only stable options if no unstable options are used. Since error-format // is unstable, it will not be present. We have to use `opts_present` not @@ -2045,10 +2027,6 @@ pub fn parse_error_format( None | Some("human") => { ErrorOutputType::HumanReadable { color_config, kind: default_kind } } - Some("human-annotate-rs") => ErrorOutputType::HumanReadable { - kind: HumanReadableErrorType::AnnotateSnippet { short: false, unicode: false }, - color_config, - }, Some("json") => { ErrorOutputType::Json { pretty: false, json_rendered, color_config: json_color } } @@ -2056,15 +2034,11 @@ pub fn parse_error_format( ErrorOutputType::Json { pretty: true, json_rendered, color_config: json_color } } Some("short") => ErrorOutputType::HumanReadable { - kind: if is_nightly_build { - HumanReadableErrorType::AnnotateSnippet { short: true, unicode: false } - } else { - HumanReadableErrorType::Default { short: true } - }, + kind: HumanReadableErrorType { short: true, unicode: false }, color_config, }, Some("human-unicode") => ErrorOutputType::HumanReadable { - kind: HumanReadableErrorType::AnnotateSnippet { short: false, unicode: true }, + kind: HumanReadableErrorType { short: false, unicode: true }, color_config, }, Some(arg) => { @@ -2073,8 +2047,8 @@ pub fn parse_error_format( kind: default_kind, }); early_dcx.early_fatal(format!( - "argument for `--error-format` must be `human`, `human-annotate-rs`, \ - `human-unicode`, `json`, `pretty-json` or `short` (instead was `{arg}`)" + "argument for `--error-format` must be `human`, `human-unicode`, \ + `json`, `pretty-json` or `short` (instead was `{arg}`)" )) } } @@ -2136,8 +2110,7 @@ fn check_error_format_stability( let format = match format { ErrorOutputType::Json { pretty: true, .. } => "pretty-json", ErrorOutputType::HumanReadable { kind, .. } => match kind { - HumanReadableErrorType::AnnotateSnippet { unicode: false, .. } => "human-annotate-rs", - HumanReadableErrorType::AnnotateSnippet { unicode: true, .. } => "human-unicode", + HumanReadableErrorType { unicode: true, .. } => "human-unicode", _ => return, }, _ => return, @@ -2465,16 +2438,9 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M json_timings, json_unused_externs, json_future_incompat, - } = parse_json(early_dcx, matches, unstable_features.is_nightly_build()); + } = parse_json(early_dcx, matches); - let error_format = parse_error_format( - early_dcx, - matches, - color, - json_color, - json_rendered, - unstable_features.is_nightly_build(), - ); + let error_format = parse_error_format(early_dcx, matches, color, json_color, json_rendered); early_dcx.set_error_format(error_format); diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 14b80099bafe4..1a0ec600af47d 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -13,9 +13,7 @@ use rustc_data_structures::profiling::{SelfProfiler, SelfProfilerRef}; use rustc_data_structures::sync::{DynSend, DynSync, Lock, MappedReadGuard, ReadGuard, RwLock}; use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitter; use rustc_errors::codes::*; -use rustc_errors::emitter::{ - DynEmitter, HumanEmitter, HumanReadableErrorType, OutputTheme, stderr_destination, -}; +use rustc_errors::emitter::{DynEmitter, HumanReadableErrorType, OutputTheme, stderr_destination}; use rustc_errors::json::JsonEmitter; use rustc_errors::timings::TimingSectionHandler; use rustc_errors::translation::Translator; @@ -920,7 +918,7 @@ fn default_emitter( match sopts.error_format { config::ErrorOutputType::HumanReadable { kind, color_config } => match kind { - HumanReadableErrorType::AnnotateSnippet { short, unicode } => { + HumanReadableErrorType { short, unicode } => { let emitter = AnnotateSnippetEmitter::new(stderr_destination(color_config), translator) .sm(source_map) @@ -938,20 +936,6 @@ fn default_emitter( ); Box::new(emitter.ui_testing(sopts.unstable_opts.ui_testing)) } - HumanReadableErrorType::Default { short } => { - let emitter = HumanEmitter::new(stderr_destination(color_config), translator) - .sm(source_map) - .short_message(short) - .diagnostic_width(sopts.diagnostic_width) - .macro_backtrace(macro_backtrace) - .track_diagnostics(track_diagnostics) - .terminal_url(terminal_url) - .theme(OutputTheme::Ascii) - .ignored_directories_in_source_blocks( - sopts.unstable_opts.ignore_directory_in_diagnostics_source_blocks.clone(), - ); - Box::new(emitter.ui_testing(sopts.unstable_opts.ui_testing)) - } }, config::ErrorOutputType::Json { pretty, json_rendered, color_config } => Box::new( JsonEmitter::new( @@ -1460,16 +1444,11 @@ fn mk_emitter(output: ErrorOutputType) -> Box { Translator::with_fallback_bundle(vec![rustc_errors::DEFAULT_LOCALE_RESOURCE], false); let emitter: Box = match output { config::ErrorOutputType::HumanReadable { kind, color_config } => match kind { - HumanReadableErrorType::AnnotateSnippet { short, unicode } => Box::new( + HumanReadableErrorType { short, unicode } => Box::new( AnnotateSnippetEmitter::new(stderr_destination(color_config), translator) .theme(if unicode { OutputTheme::Unicode } else { OutputTheme::Ascii }) .short_message(short), ), - HumanReadableErrorType::Default { short } => Box::new( - HumanEmitter::new(stderr_destination(color_config), translator) - .theme(OutputTheme::Ascii) - .short_message(short), - ), }, config::ErrorOutputType::Json { pretty, json_rendered, color_config } => { Box::new(JsonEmitter::new( diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index c484476037e29..0e30abccb62b3 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2474,6 +2474,7 @@ symbols! { vsreg, vsx, vtable_align, + vtable_for, vtable_size, warn, wasip2, diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index c6b76f6a9ae65..42d204a8b0941 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -293,6 +293,13 @@ pub enum ExistentialPredicate { impl Eq for ExistentialPredicate {} impl ty::Binder> { + pub fn def_id(&self) -> I::DefId { + match self.skip_binder() { + ExistentialPredicate::Trait(tr) => tr.def_id.into(), + ExistentialPredicate::Projection(p) => p.def_id.into(), + ExistentialPredicate::AutoTrait(did) => did.into(), + } + } /// Given an existential predicate like `?Self: PartialEq` (e.g., derived from `dyn PartialEq`), /// and a concrete type `self_ty`, returns a full predicate where the existentially quantified variable `?Self` /// has been replaced with `self_ty` (e.g., `self_ty: PartialEq`, in our example). diff --git a/library/core/src/any.rs b/library/core/src/any.rs index ff55793340bd0..42f332f7d8ba8 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -86,7 +86,7 @@ #![stable(feature = "rust1", since = "1.0.0")] -use crate::{fmt, hash, intrinsics}; +use crate::{fmt, hash, intrinsics, ptr}; /////////////////////////////////////////////////////////////////////////////// // Any trait @@ -906,3 +906,109 @@ pub const fn type_name() -> &'static str { pub const fn type_name_of_val(_val: &T) -> &'static str { type_name::() } + +/// Returns `Some(&U)` if `T` can be coerced to the trait object type `U`. Otherwise, it returns `None`. +/// +/// # Compile-time failures +/// Determining whether `T` can be coerced to the trait object type `U` requires compiler trait resolution. +/// In some cases, that resolution can exceed the recursion limit, +/// and compilation will fail instead of this function returning `None`. +/// # Examples +/// +/// ```rust +/// #![feature(try_as_dyn)] +/// +/// use core::any::try_as_dyn; +/// +/// trait Animal { +/// fn speak(&self) -> &'static str; +/// } +/// +/// struct Dog; +/// impl Animal for Dog { +/// fn speak(&self) -> &'static str { "woof" } +/// } +/// +/// struct Rock; // does not implement Animal +/// +/// let dog = Dog; +/// let rock = Rock; +/// +/// let as_animal: Option<&dyn Animal> = try_as_dyn::(&dog); +/// assert_eq!(as_animal.unwrap().speak(), "woof"); +/// +/// let not_an_animal: Option<&dyn Animal> = try_as_dyn::(&rock); +/// assert!(not_an_animal.is_none()); +/// ``` +#[must_use] +#[unstable(feature = "try_as_dyn", issue = "144361")] +pub const fn try_as_dyn< + T: Any + 'static, + U: ptr::Pointee> + ?Sized + 'static, +>( + t: &T, +) -> Option<&U> { + let vtable: Option> = const { intrinsics::vtable_for::() }; + match vtable { + Some(dyn_metadata) => { + let pointer = ptr::from_raw_parts(t, dyn_metadata); + // SAFETY: `t` is a reference to a type, so we know it is valid. + // `dyn_metadata` is a vtable for T, implementing the trait of `U`. + Some(unsafe { &*pointer }) + } + None => None, + } +} + +/// Returns `Some(&mut U)` if `T` can be coerced to the trait object type `U`. Otherwise, it returns `None`. +/// +/// # Compile-time failures +/// Determining whether `T` can be coerced to the trait object type `U` requires compiler trait resolution. +/// In some cases, that resolution can exceed the recursion limit, +/// and compilation will fail instead of this function returning `None`. +/// # Examples +/// +/// ```rust +/// #![feature(try_as_dyn)] +/// +/// use core::any::try_as_dyn_mut; +/// +/// trait Animal { +/// fn speak(&self) -> &'static str; +/// } +/// +/// struct Dog; +/// impl Animal for Dog { +/// fn speak(&self) -> &'static str { "woof" } +/// } +/// +/// struct Rock; // does not implement Animal +/// +/// let mut dog = Dog; +/// let mut rock = Rock; +/// +/// let as_animal: Option<&mut dyn Animal> = try_as_dyn_mut::(&mut dog); +/// assert_eq!(as_animal.unwrap().speak(), "woof"); +/// +/// let not_an_animal: Option<&mut dyn Animal> = try_as_dyn_mut::(&mut rock); +/// assert!(not_an_animal.is_none()); +/// ``` +#[must_use] +#[unstable(feature = "try_as_dyn", issue = "144361")] +pub const fn try_as_dyn_mut< + T: Any + 'static, + U: ptr::Pointee> + ?Sized + 'static, +>( + t: &mut T, +) -> Option<&mut U> { + let vtable: Option> = const { intrinsics::vtable_for::() }; + match vtable { + Some(dyn_metadata) => { + let pointer = ptr::from_raw_parts_mut(t, dyn_metadata); + // SAFETY: `t` is a reference to a type, so we know it is valid. + // `dyn_metadata` is a vtable for T, implementing the trait of `U`. + Some(unsafe { &mut *pointer }) + } + None => None, + } +} diff --git a/library/core/src/borrow.rs b/library/core/src/borrow.rs index 78ba69fec1422..eb4562bda4ce3 100644 --- a/library/core/src/borrow.rs +++ b/library/core/src/borrow.rs @@ -187,7 +187,7 @@ pub const trait Borrow { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "BorrowMut"] #[rustc_const_unstable(feature = "const_convert", issue = "143773")] -pub const trait BorrowMut: Borrow { +pub const trait BorrowMut: [const] Borrow { /// Mutably borrows from an owned value. /// /// # Examples diff --git a/library/core/src/ffi/va_list.rs b/library/core/src/ffi/va_list.rs index 4c59ea0cc5328..d5166baf0c7ca 100644 --- a/library/core/src/ffi/va_list.rs +++ b/library/core/src/ffi/va_list.rs @@ -31,6 +31,9 @@ use crate::marker::PhantomCovariantLifetime; // the pointer decay behavior in Rust, while otherwise matching Rust semantics. // This attribute ensures that the compiler uses the correct ABI for functions // like `extern "C" fn takes_va_list(va: VaList<'_>)` by passing `va` indirectly. +// +// The Clang `BuiltinVaListKind` enumerates the `va_list` variations that Clang supports, +// and we mirror these here. crate::cfg_select! { all( target_arch = "aarch64", @@ -124,6 +127,23 @@ crate::cfg_select! { } } + all(target_arch = "hexagon", target_env = "musl") => { + /// Hexagon Musl implementation of a `va_list`. + /// + /// See the [LLVM source] for more details. On bare metal Hexagon uses an opaque pointer. + /// + /// [LLVM source]: + /// https://github.com/llvm/llvm-project/blob/0cdc1b6dd4a870fc41d4b15ad97e0001882aba58/clang/lib/CodeGen/Targets/Hexagon.cpp#L407-L417 + #[repr(C)] + #[derive(Debug)] + #[rustc_pass_indirectly_in_non_rustic_abis] + struct VaListInner { + __current_saved_reg_area_pointer: *const c_void, + __saved_reg_area_end_pointer: *const c_void, + __overflow_area_pointer: *const c_void, + } + } + // The fallback implementation, used for: // // - apple aarch64 (see https://github.com/rust-lang/rust/pull/56599) diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 722e16ab0fa49..2179b451c375e 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -2754,6 +2754,22 @@ pub unsafe fn vtable_size(ptr: *const ()) -> usize; #[rustc_intrinsic] pub unsafe fn vtable_align(ptr: *const ()) -> usize; +/// The intrinsic returns the `U` vtable for `T` if `T` can be coerced to the trait object type `U`. +/// +/// # Compile-time failures +/// Determining whether `T` can be coerced to the trait object type `U` requires trait resolution by the compiler. +/// In some cases, that resolution can exceed the recursion limit, +/// and compilation will fail instead of this function returning `None`. +/// +/// # Safety +/// +/// `ptr` must point to a vtable. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_intrinsic] +pub const fn vtable_for> + ?Sized>() +-> Option>; + /// The size of a type in bytes. /// /// Note that, unlike most intrinsics, this is safe to call; diff --git a/library/core/src/ops/function.rs b/library/core/src/ops/function.rs index 479368ba8f801..efe5c0871fb8b 100644 --- a/library/core/src/ops/function.rs +++ b/library/core/src/ops/function.rs @@ -73,7 +73,7 @@ use crate::marker::Tuple; #[fundamental] // so that regex can rely that `&str: !FnMut` #[must_use = "closures are lazy and do nothing unless called"] #[rustc_const_unstable(feature = "const_trait_impl", issue = "143874")] -pub const trait Fn: FnMut { +pub const trait Fn: [const] FnMut { /// Performs the call operation. #[unstable(feature = "fn_traits", issue = "29625")] extern "rust-call" fn call(&self, args: Args) -> Self::Output; diff --git a/library/coretests/tests/intrinsics.rs b/library/coretests/tests/intrinsics.rs index 744a6a0d2dd8f..c6d841b8383a8 100644 --- a/library/coretests/tests/intrinsics.rs +++ b/library/coretests/tests/intrinsics.rs @@ -1,5 +1,8 @@ use core::any::TypeId; -use core::intrinsics::assume; +use core::intrinsics::{assume, vtable_for}; +use std::fmt::Debug; +use std::option::Option; +use std::ptr::DynMetadata; #[test] fn test_typeid_sized_types() { @@ -193,3 +196,17 @@ fn carrying_mul_add_fallback_i128() { (u128::MAX - 1, -(i128::MIN / 2)), ); } + +#[test] +fn test_vtable_for() { + #[derive(Debug)] + struct A {} + + struct B {} + + const A_VTABLE: Option> = vtable_for::(); + assert!(A_VTABLE.is_some()); + + const B_VTABLE: Option> = vtable_for::(); + assert!(B_VTABLE.is_none()); +} diff --git a/library/std/src/io/buffered/tests.rs b/library/std/src/io/buffered/tests.rs index 068dca819775a..fc77b02a8e828 100644 --- a/library/std/src/io/buffered/tests.rs +++ b/library/std/src/io/buffered/tests.rs @@ -172,7 +172,7 @@ fn test_buffered_reader_stream_position_panic() { // cause internal buffer to be filled but read only partially let mut buffer = [0, 0]; assert!(reader.read_exact(&mut buffer).is_ok()); - // rewinding the internal reader will cause buffer to loose sync + // rewinding the internal reader will cause buffer to lose sync let inner = reader.get_mut(); assert!(inner.seek(SeekFrom::Start(0)).is_ok()); // overflow when subtracting the remaining buffer size from current position diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index 98b266663ad2f..528eb185df088 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -1,6 +1,13 @@ #[cfg(test)] mod tests; +// On 64-bit platforms, `io::Error` may use a bit-packed representation to +// reduce size. However, this representation assumes that error codes are +// always 32-bit wide. +// +// This assumption is invalid on 64-bit UEFI, where error codes are 64-bit. +// Therefore, the packed representation is explicitly disabled for UEFI +// targets, and the unpacked representation must be used instead. #[cfg(all(target_pointer_width = "64", not(target_os = "uefi")))] mod repr_bitpacked; #[cfg(all(target_pointer_width = "64", not(target_os = "uefi")))] diff --git a/src/ci/docker/scripts/build-gcc.sh b/src/ci/docker/scripts/build-gcc.sh index 11db5aa811ce8..ab4cae21e0254 100755 --- a/src/ci/docker/scripts/build-gcc.sh +++ b/src/ci/docker/scripts/build-gcc.sh @@ -7,7 +7,7 @@ source shared.sh # This version is specified in the Dockerfile GCC=$GCC_VERSION -curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.xz | xzcat | tar xf - +curl https://ci-mirrors.rust-lang.org/rustc/gcc/gcc-$GCC.tar.xz | xzcat | tar xf - cd gcc-$GCC # FIXME(#49246): Remove the `sed` below. diff --git a/src/doc/rustc-dev-guide/.github/workflows/ci.yml b/src/doc/rustc-dev-guide/.github/workflows/ci.yml index fe92bc876cf71..f2f2f7ed14858 100644 --- a/src/doc/rustc-dev-guide/.github/workflows/ci.yml +++ b/src/doc/rustc-dev-guide/.github/workflows/ci.yml @@ -7,7 +7,7 @@ on: pull_request: schedule: # Run multiple times a day as the successfull cached links are not checked every time. - - cron: '0 */8 * * *' + - cron: "0 */8 * * *" jobs: ci: @@ -83,16 +83,6 @@ jobs: git commit -m "Deploy ${GITHUB_SHA} to gh-pages" git push --quiet -f "https://x-token:${{ secrets.GITHUB_TOKEN }}@github.com/${GITHUB_REPOSITORY}" HEAD:gh-pages - - name: Cache sembr build - uses: actions/cache@v4 - with: - path: | - ~/.cargo/registry/index/ - ~/.cargo/registry/cache/ - ~/.cargo/git/db/ - ci/sembr/target/ - key: sembr-${{ hashFiles('ci/sembr/Cargo.lock') }} - - name: Check if files comply with semantic line breaks continue-on-error: true run: | diff --git a/src/doc/rustc-dev-guide/README.md b/src/doc/rustc-dev-guide/README.md index fee7cf042e1f8..59d6719c71cbd 100644 --- a/src/doc/rustc-dev-guide/README.md +++ b/src/doc/rustc-dev-guide/README.md @@ -1,19 +1,15 @@ [![CI](https://github.com/rust-lang/rustc-dev-guide/actions/workflows/ci.yml/badge.svg)](https://github.com/rust-lang/rustc-dev-guide/actions/workflows/ci.yml) - -This is a collaborative effort to build a guide that explains how rustc -works. The aim of the guide is to help new contributors get oriented -to rustc, as well as to help more experienced folks in figuring out +This is a collaborative effort to build a guide that explains how rustc works. +The aim of the guide is to help new contributors get oriented to rustc, +as well as to help more experienced folks in figuring out some new part of the compiler that they haven't worked on before. -[You can read the latest version of the guide here.](https://rustc-dev-guide.rust-lang.org/) +You may also find the [rustc API docs] useful. -You may also find the rustdocs [for the compiler itself][rustdocs] useful. Note that these are not intended as a guide; it's recommended that you search for the docs you're looking for instead of reading them top to bottom. -[rustdocs]: https://doc.rust-lang.org/nightly/nightly-rustc - For documentation on developing the standard library, see [`std-dev-guide`](https://std-dev-guide.rust-lang.org/). @@ -21,22 +17,26 @@ For documentation on developing the standard library, see The guide is useful today, but it has a lot of work still to go. -If you'd like to help improve the guide, we'd love to have you! You can find -plenty of issues on the [issue -tracker](https://github.com/rust-lang/rustc-dev-guide/issues). Just post a -comment on the issue you would like to work on to make sure that we don't -accidentally duplicate work. If you think something is missing, please open an -issue about it! +If you'd like to help improve the guide, we'd love to have you! +You can find plenty of issues on the [issue +tracker](https://github.com/rust-lang/rustc-dev-guide/issues). +Just post a comment on the issue you would like to work on to make sure that we don't +accidentally duplicate work. +If you think something is missing, please open an issue about it! **In general, if you don't know how the compiler works, that is not a problem!** In that case, what we will do is to schedule a bit of time for you to talk with someone who **does** know the code, or who wants -to pair with you and figure it out. Then you can work on writing up -what you learned. +to pair with you and figure it out. +Then you can work on writing up what you learned. In general, when writing about a particular part of the compiler's code, we -recommend that you link to the relevant parts of the [rustc -rustdocs][rustdocs]. +recommend that you link to the relevant parts of the [rustc API docs]. + +The guide has a much lower bar for what it takes for a PR to be merged. +Check out the forge documentation for [our policy][forge_policy]. + +[forge_policy]: https://forge.rust-lang.org/rustc-dev-guide/index.html#review-policy ### Build Instructions @@ -56,9 +56,9 @@ The build files are found in the `book/html` directory. ### Link Validations -We use `mdbook-linkcheck2` to validate URLs included in our documentation. Link -checking is **not** run by default locally, though it is in CI. To enable it -locally, set the environment variable `ENABLE_LINKCHECK=1` like in the +We use `mdbook-linkcheck2` to validate URLs included in our documentation. +Link checking is **not** run by default locally, though it is in CI. +To enable it locally, set the environment variable `ENABLE_LINKCHECK=1` like in the following example. ``` @@ -67,6 +67,9 @@ ENABLE_LINKCHECK=1 mdbook serve ## Synchronizing josh subtree with rustc -This repository is linked to `rust-lang/rust` as a [josh](https://josh-project.github.io/josh/intro.html) subtree. You can use the [rustc-josh-sync](https://github.com/rust-lang/josh-sync) tool to perform synchronization. +This repository is linked to `rust-lang/rust` as a [josh](https://josh-project.github.io/josh/intro.html) subtree. +You can use the [rustc-josh-sync](https://github.com/rust-lang/josh-sync) tool to perform synchronization. You can find a guide on how to perform the synchronization [here](./src/external-repos.md#synchronizing-a-josh-subtree). + +[rustc API docs]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle diff --git a/src/doc/rustc-dev-guide/ci/sembr/src/main.rs b/src/doc/rustc-dev-guide/ci/sembr/src/main.rs index 7ace34aed984a..2539a9eadda34 100644 --- a/src/doc/rustc-dev-guide/ci/sembr/src/main.rs +++ b/src/doc/rustc-dev-guide/ci/sembr/src/main.rs @@ -177,6 +177,9 @@ fn lengthen_lines(content: &str, limit: usize) -> String { let Some(next_line) = content.get(n + 1) else { continue; }; + if next_line.trim_start().starts_with("```") { + continue; + } if ignore(next_line, in_code_block) || REGEX_LIST_ENTRY.is_match(next_line) || REGEX_IGNORE_END.is_match(line) @@ -255,6 +258,12 @@ preserve next line preserve next line * three + +do not mess with code block chars +``` +leave the +text alone +``` "; let expected = "\ do not split short sentences @@ -269,6 +278,12 @@ preserve next line preserve next line * three + +do not mess with code block chars +``` +leave the +text alone +``` "; assert_eq!(expected, lengthen_lines(original, 50)); } @@ -294,40 +309,6 @@ fn test_prettify_ignore_link_targets() { assert_eq!(original, lengthen_lines(original, 100)); } -#[test] -fn test_sembr_then_prettify() { - let original = " -hi there. do -not split -short sentences. -hi again. -"; - let expected = " -hi there. -do -not split -short sentences. -hi again. -"; - let processed = comply(original); - assert_eq!(expected, processed); - let expected = " -hi there. -do not split -short sentences. -hi again. -"; - let processed = lengthen_lines(&processed, 50); - assert_eq!(expected, processed); - let expected = " -hi there. -do not split short sentences. -hi again. -"; - let processed = lengthen_lines(&processed, 50); - assert_eq!(expected, processed); -} - #[test] fn test_sembr_question_mark() { let original = " diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index 7a84872f266d1..71a84e2bda12c 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -dfe1b8c97bcde283102f706d5dcdc3649e5e12e3 +cec70080fd441d16e9fb08a0d1d1a04c72d1ed25 diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md index c136d37160c53..e80ee6a5137d8 100644 --- a/src/doc/rustc-dev-guide/src/SUMMARY.md +++ b/src/doc/rustc-dev-guide/src/SUMMARY.md @@ -66,6 +66,7 @@ - [ARM](notification-groups/arm.md) - [Emscripten](notification-groups/emscripten.md) - [Fuchsia](notification-groups/fuchsia.md) + - [LoongArch](notification-groups/loongarch.md) - [RISC-V](notification-groups/risc-v.md) - [Rust for Linux](notification-groups/rust-for-linux.md) - [WASI](notification-groups/wasi.md) @@ -126,8 +127,8 @@ - [Lang Items](./lang-items.md) - [The HIR (High-level IR)](./hir.md) - [Lowering AST to HIR](./hir/lowering.md) - - [Ambig/Unambig Types and Consts](./hir/ambig-unambig-ty-and-consts.md) - [Debugging](./hir/debugging.md) +- [Ambig/Unambig Types and Consts](./ambig-unambig-ty-and-consts.md) - [The THIR (Typed High-level IR)](./thir.md) - [The MIR (Mid-level IR)](./mir/index.md) - [MIR construction](./mir/construction.md) @@ -185,12 +186,14 @@ - [Proof trees](./solve/proof-trees.md) - [Opaque types](./solve/opaque-types.md) - [Significant changes and quirks](./solve/significant-changes.md) + - [Sharing the trait solver with rust-analyzer](./solve/sharing-crates-with-rust-analyzer.md) - [`Unsize` and `CoerceUnsized` traits](./traits/unsize.md) - [Variance](./variance.md) - [Coherence checking](./coherence.md) - [HIR Type checking](./hir-typeck/summary.md) - [Coercions](./hir-typeck/coercions.md) - [Method lookup](./hir-typeck/method-lookup.md) +- [Const Generics](./const-generics.md) - [Opaque types](./opaque-types-type-alias-impl-trait.md) - [Inference details](./opaque-types-impl-trait-inference.md) - [Return Position Impl Trait In Trait](./return-position-impl-trait-in-trait.md) @@ -230,11 +233,22 @@ - [Debugging LLVM](./backend/debugging.md) - [Backend Agnostic Codegen](./backend/backend-agnostic.md) - [Implicit caller location](./backend/implicit-caller-location.md) +- [Debug Info](./debuginfo/intro.md) + - [Rust Codegen](./debuginfo/rust-codegen.md) + - [LLVM Codegen](./debuginfo/llvm-codegen.md) + - [Debugger Internals](./debuginfo/debugger-internals.md) + - [LLDB Internals](./debuginfo/lldb-internals.md) + - [GDB Internals](./debuginfo/gdb-internals.md) + - [Debugger Visualizers](./debuginfo/debugger-visualizers.md) + - [LLDB - Python Providers](./debuginfo/lldb-visualizers.md) + - [GDB - Python Providers](./debuginfo/gdb-visualizers.md) + - [CDB - Natvis](./debuginfo/natvis-visualizers.md) + - [Testing](./debuginfo/testing.md) + - [(Lecture Notes) Debugging support in the Rust compiler](./debugging-support-in-rustc.md) - [Libraries and metadata](./backend/libs-and-metadata.md) - [Profile-guided optimization](./profile-guided-optimization.md) - [LLVM source-based code coverage](./llvm-coverage-instrumentation.md) - [Sanitizers support](./sanitizers.md) -- [Debugging support in the Rust compiler](./debugging-support-in-rustc.md) --- diff --git a/src/doc/rustc-dev-guide/src/about-this-guide.md b/src/doc/rustc-dev-guide/src/about-this-guide.md index 4f5733ae0821a..841691d859f98 100644 --- a/src/doc/rustc-dev-guide/src/about-this-guide.md +++ b/src/doc/rustc-dev-guide/src/about-this-guide.md @@ -58,21 +58,24 @@ please see the corresponding [subsection on writing documentation in this guide] [subsection on writing documentation in this guide]: contributing.md#contributing-to-rustc-dev-guide -> “‘All conditioned things are impermanent’ — +> “‘All conditioned things are impermanent’ — > when one sees this with wisdom, one turns away from suffering.” > _The Dhammapada, verse 277_ ## Other places to find information +This guide, the one you are currently reading, +contains information about how various parts of the compiler work, +and how to contribute to the compiler. + You might also find the following sites useful: -- This guide contains information about how various parts of the - compiler work and how to contribute to the compiler. - [rustc API docs] -- rustdoc documentation for the compiler, devtools, and internal tools - [Forge] -- contains documentation about Rust infrastructure, team procedures, and more - [compiler-team] -- the home-base for the Rust compiler team, with description of the team procedures, active working groups, and the team calendar. - [std-dev-guide] -- a similar guide for developing the standard library. +- [rust-analyzer book] -- documentation for the rust-analyzer. - [The t-compiler Zulip][z] - The [Rust Internals forum][rif], a place to ask questions and discuss Rust's internals @@ -110,4 +113,5 @@ You might also find the following sites useful: [Forge]: https://forge.rust-lang.org/ [compiler-team]: https://github.com/rust-lang/compiler-team/ [std-dev-guide]: https://std-dev-guide.rust-lang.org/ +[rust-analyzer book]: https://rust-analyzer.github.io/book/ [z]: https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler diff --git a/src/doc/rustc-dev-guide/src/ambig-unambig-ty-and-consts.md b/src/doc/rustc-dev-guide/src/ambig-unambig-ty-and-consts.md new file mode 100644 index 0000000000000..64a15b7f9aa82 --- /dev/null +++ b/src/doc/rustc-dev-guide/src/ambig-unambig-ty-and-consts.md @@ -0,0 +1,111 @@ +# Ambig/Unambig Types and Consts + +Types and Consts args in the AST/HIR can be in two kinds of positions ambiguous (ambig) or unambiguous (unambig). Ambig positions are where +it would be valid to parse either a type or a const, unambig positions are where only one kind would be valid to +parse. + +```rust +fn func(arg: T) { + // ^ Unambig type position + let a: _ = arg; + // ^ Unambig type position + + func::(arg); + // ^ ^ + // ^^^^ Ambig position + + let _: [u8; 10]; + // ^^ ^^ Unambig const position + // ^^ Unambig type position +} + +``` + +Most types/consts in ambig positions are able to be disambiguated as either a type or const during parsing. The only exceptions to this are paths and inferred generic arguments. + +## Paths + +```rust +struct Foo; + +fn foo(_: Foo) {} +``` + +At parse time we parse all unbraced generic arguments as *types* (ie they wind up as [`ast::GenericArg::Ty`]). In the above example this means we would parse the generic argument to `Foo` as an `ast::GenericArg::Ty` wrapping a [`ast::Ty::Path(N)`]. + +Then during name resolution: +- When encountering a single segment path with no generic arguments in generic argument position, we will first try to resolve it in the type namespace and if that fails we then attempt to resolve in the value namespace. +- All other kinds of paths we only try to resolve in the type namespace + +See [`LateResolutionVisitor::visit_generic_arg`] for where this is implemented. + +Finally during AST lowering when we attempt to lower a type argument, we first check if it is a `Ty::Path` and if it resolved to something in the value namespace. If it did then we create an *anon const* and lower to a const argument instead of a type argument. + +See [`LoweringContext::lower_generic_arg`] for where this is implemented. + +Note that the ambiguity for paths is not propgated into the HIR; there's no `hir::GenericArg::Path` which is turned into either a `Ty` or `Const` during HIR ty lowering (though we could do such a thing). + +## Inferred arguments (`_`) + +```rust +struct Foo; + +fn foo() { + let _unused: Foo<_>; +} +``` + +The only generic arguments which remain ambiguous after lowering are inferred generic arguments (`_`) in path segments. In the above example it is not clear at parse time whether the `_` argument to `Foo` is an inferred type argument, or an inferred const argument. + +In ambig AST positions, inferred argumentsd are parsed as an [`ast::GenericArg::Ty`] wrapping a [`ast::Ty::Infer`]. Then during AST lowering when lowering an `ast::GenericArg::Ty` we check if it is an inferred type and if so lower to a [`hir::GenericArg::Infer`]. + +In unambig AST positions, inferred arguments are parsed as either `ast::Ty::Infer` or [`ast::AnonConst`]. The `AnonConst` case is quite strange, we use [`ast::ExprKind::Underscore`] to represent the "body" of the "anon const" although in reality we do not actually lower this to an anon const in the HIR. + +It may be worth seeing if we can refactor the AST to have `ast::GenericArg::Infer` and then get rid of this overloaded meaning of `AnonConst`, as well as the reuse of `ast::Ty::Infer` in ambig positions. + +In unambig AST positions, during AST lowering we lower inferred arguments to [`hir::TyKind::Infer`][ty_infer] or [`hir::ConstArgKind::Infer`][const_infer] depending on whether it is a type or const position respectively. +In ambig AST positions, during AST lowering we lower inferred arguments to [`hir::GenericArg::Infer`][generic_arg_infer]. See [`LoweringContext::lower_generic_arg`] for where this is implemented. + +A naive implementation of this would result in there being potentially 5 places where you might think an inferred type/const could be found in the HIR from looking at the structure of the HIR: +1. In unambig type position as a `TyKind::Infer` +2. In unambig const arg position as a `ConstArgKind::Infer` +3. In an ambig position as a [`GenericArg::Type(TyKind::Infer)`][generic_arg_ty] +4. In an ambig position as a [`GenericArg::Const(ConstArgKind::Infer)`][generic_arg_const] +5. In an ambig position as a `GenericArg::Infer` + +Note that places 3 and 4 would never actually be possible to encounter as we always lower to `GenericArg::Infer` in generic arg position. + +This has a few failure modes: +- People may write visitors which check for `GenericArg::Infer` but forget to check for `hir::TyKind/ConstArgKind::Infer`, only handling infers in ambig positions by accident. +- People may write visitors which check for `TyKind/ConstArgKind::Infer` but forget to check for `GenericArg::Infer`, only handling infers in unambig positions by accident. +- People may write visitors which check for `GenericArg::Type/Const(TyKind/ConstArgKind::Infer)` and `GenericArg::Infer`, not realising that we never represent inferred types/consts in ambig positions as a `GenericArg::Type/Const`. +- People may write visitors which check for *only* `TyKind::Infer` and not `ConstArgKind::Infer` forgetting that there are also inferred const arguments (and vice versa). + +To make writing HIR visitors less error prone when caring about inferred types/consts we have a relatively complex system: + +1. We have different types in the compiler for when a type or const is in an unambig or ambig position, `Ty` and `Ty<()>`. [`AmbigArg`][ambig_arg] is an uninhabited type which we use in the `Infer` variant of `TyKind` and `ConstArgKind` to selectively "disable" it if we are in an ambig position. + +2. The [`visit_ty`][visit_ty] and [`visit_const_arg`][visit_const_arg] methods on HIR visitors only accept the ambig position versions of types/consts. Unambig types/consts are implicitly converted to ambig types/consts during the visiting process, with the `Infer` variant handled by a dedicated [`visit_infer`][visit_infer] method. + +This has a number of benefits: +- It's clear that `GenericArg::Type/Const` cannot represent inferred type/const arguments +- Implementors of `visit_ty` and `visit_const_arg` will never encounter inferred types/consts making it impossible to write a visitor that seems to work right but handles edge cases wrong +- The `visit_infer` method handles *all* cases of inferred type/consts in the HIR making it easy for visitors to handle inferred type/consts in one dedicated place and not forget cases + +[ty_infer]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.TyKind.html#variant.Infer +[const_infer]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.ConstArgKind.html#variant.Infer +[generic_arg_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.GenericArg.html#variant.Type +[generic_arg_const]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.GenericArg.html#variant.Const +[generic_arg_infer]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.GenericArg.html#variant.Infer +[ambig_arg]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.AmbigArg.html +[visit_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/intravisit/trait.Visitor.html#method.visit_ty +[visit_const_arg]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/intravisit/trait.Visitor.html#method.visit_const_arg +[visit_infer]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/intravisit/trait.Visitor.html#method.visit_infer +[`LateResolutionVisitor::visit_generic_arg`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_resolve/late/struct.LateResolutionVisitor.html#method.visit_generic_arg +[`LoweringContext::lower_generic_arg`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast_lowering/struct.LoweringContext.html#method.lower_generic_arg +[`ast::GenericArg::Ty`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/enum.GenericArg.html#variant.Type +[`ast::Ty::Infer`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/enum.TyKind.html#variant.Infer +[`ast::AnonConst`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/struct.AnonConst.html +[`hir::GenericArg::Infer`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.GenericArg.html#variant.Infer +[`ast::ExprKind::Underscore`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/enum.ExprKind.html#variant.Underscore +[`ast::Ty::Path(N)`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/enum.TyKind.html#variant.Path \ No newline at end of file diff --git a/src/doc/rustc-dev-guide/src/appendix/bibliography.md b/src/doc/rustc-dev-guide/src/appendix/bibliography.md index 3729194f5fa1a..13a9c3a0b40bf 100644 --- a/src/doc/rustc-dev-guide/src/appendix/bibliography.md +++ b/src/doc/rustc-dev-guide/src/appendix/bibliography.md @@ -15,7 +15,7 @@ Rust, as well as publications about Rust. * [Safe manual memory management in Cyclone](https://www.cs.umd.edu/projects/PL/cyclone/scp.pdf) * [Skolem Normal Form](https://en.wikipedia.org/wiki/Skolem_normal_form) * [Traits: composable units of behavior](http://scg.unibe.ch/archive/papers/Scha03aTraits.pdf) -* [Uniqueness and Reference Immutability for Safe Parallelism](https://research.microsoft.com/pubs/170528/msr-tr-2012-79.pdf) +* [Uniqueness and Reference Immutability for Safe Parallelism](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/msr-tr-2012-79.pdf) ## Concurrency @@ -25,12 +25,12 @@ Rust, as well as publications about Rust. * [Contention aware scheduling](https://www.blagodurov.net/files/a8-blagodurov.pdf) * [Dynamic circular work stealing deque](https://patents.google.com/patent/US7346753B2/en) - The Chase/Lev deque * [Epoch-based reclamation](https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-579.pdf). -* [Language support for fast and reliable message passing in singularity OS](https://research.microsoft.com/pubs/67482/singsharp.pdf) +* [Language support for fast and reliable message-based communication in singularity OS](https://www.microsoft.com/en-us/research/wp-content/uploads/2006/04/singsharp.pdf) * [Non-blocking steal-half work queues](https://www.cs.bgu.ac.il/%7Ehendlerd/papers/p280-hendler.pdf) * [Reagents: expressing and composing fine-grained concurrency](https://aturon.github.io/academic/reagents.pdf) * [Scheduling multithreaded computations by work stealing](https://www.lri.fr/~cecile/ENSEIGNEMENT/IPAR/Exposes/cilk1.pdf) * [Scheduling techniques for concurrent systems](https://www.stanford.edu/~ouster/cgi-bin/papers/coscheduling.pdf) -* [Singularity: rethinking the software stack](https://research.microsoft.com/pubs/69431/osr2007_rethinkingsoftwarestack.pdf) +* [Singularity: rethinking the software stack](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/osr2007_rethinkingsoftwarestack.pdf) * [The data locality of work stealing](http://www.aladdin.cs.cmu.edu/papers/pdfs/y2000/locality_spaa00.pdf) * [Thread scheduling for multiprogramming multiprocessors](https://dl.acm.org/doi/10.1145/277651.277678) * [Three layer cake for shared-memory programming](https://dl.acm.org/doi/10.1145/1953611.1953616) diff --git a/src/doc/rustc-dev-guide/src/const-generics.md b/src/doc/rustc-dev-guide/src/const-generics.md new file mode 100644 index 0000000000000..cb8c7adc07f46 --- /dev/null +++ b/src/doc/rustc-dev-guide/src/const-generics.md @@ -0,0 +1,222 @@ +# Const Generics + +## Kinds of const arguments + +Most of the kinds of `ty::Const` that exist have direct parallels to kinds of types that exist, for example `ConstKind::Param` is equivalent to `TyKind::Param`. + +The main interesting points here are: +- [`ConstKind::Unevaluated`], this is equivalent to `TyKind::Alias` and in the long term should be renamed (as well as introducing an `AliasConstKind` to parallel `ty::AliasKind`). +- [`ConstKind::Value`], this is the final value of a `ty::Const` after monomorphization. This is similar-ish to fully concrete to things like `TyKind::Str` or `TyKind::ADT`. + +For a complete list of *all* kinds of const arguments and how they are actually represented in the type system, see the [`ConstKind`] type. + +Inference Variables are quite boring and treated equivalently to type inference variables almost everywhere. Const Parameters are also similarly boring and equivalent to uses of type parameters almost everywhere. However, there are some interesting subtleties with how they are handled during parsing, name resolution, and AST lowering: [ambig-unambig-ty-and-consts]. + +## Anon Consts + +Anon Consts (short for anonymous const items) are how arbitrary expression are represented in const generics, for example an array length of `1 + 1` or `foo()` or even just `0`. These are unique to const generics and have no real type equivalent. + +### Desugaring + +```rust +struct Foo; +type Alias = [u8; 1 + 1]; +``` + +In this example we have a const argument of `1 + 1` (the array length) which is represented as an *anon const*. The desugaring would look something like: +```rust +struct Foo; + +const ANON: usize = 1 + 1; +type Alias = [u8; ANON]; +``` + +Where the array length in `[u8; ANON]` isn't itself an anon const containing a usage of `ANON`, but a kind of "direct" usage of the `ANON` const item ([`ConstKind::Unevaluated`]). + +Anon consts do not inherit any generic parameters of the item they are inside of: +```rust +struct Foo; +type Alias = [T; 1 + 1]; + +// Desugars To; + +struct Foo; + +const ANON: usize = 1 + 1; +type Alias = [T; ANON]; +``` + +Note how the `ANON` const has no generic parameters or where clauses, even though `Alias` has both a type parameter `T` and a where clauses `T: Sized`. This desugaring is part of how we enforce that anon consts can't make use of generic parameters. + +While it's useful to think of anon consts as being desugared to real const items, the compiler does not actually implement things this way. + +At AST lowering time we do not yet know the *type* of the anon const, so we can't desugar to a real HIR item with an explicitly written type. To work around this we have [`DefKind::AnonConst`] and [`hir::Node::AnonConst`] which are used to represent these anonymous const items that can't actually be desugared. + +The types of these anon consts are obtainable from the [`type_of`] query. However, the `type_of` query does not actually contain logic for computing the type (infact it just ICEs when called), instead HIR Ty lowering is responsible for *feeding* the value of the `type_of` query for any anon consts that get lowered. HIR Ty lowering can determine the type of the anon const by looking at the type of the Const Parameter that the anon const is an argument to. + +TODO: write a chapter on query feeding and link it here + +In some sense the desugarings from the previous examples are to: +```rust +struct Foo; +type Alias = [u8; 1 + 1]; + +// sort-of desugars to psuedo-rust: +struct Foo; + +const ANON = 1 + 1; +type Alias = [u8; ANON]; +``` + +Where when we go through HIR ty lowering for the array type in `Alias`, we will lower the array length too and feed `type_of(ANON) -> usize`. Effectively setting the type of the `ANON` const item during some later part of the compiler rather than when constructing the HIR. + +After all of this desugaring has taken place the final representation in the type system (ie as a `ty::Const`) is a `ConstKind::Unevaluated` with the `DefId` of the `AnonConst`. This is equivalent to how we would representa a usage of an actual const item if we were to represent them without going through an anon const (e.g. when `min_generic_const_args` is enabled). + +This allows the representation for const "aliases" to be the same as the representation of `TyKind::Alias`. Having a proper HIR body also allows for a *lot* of code re-use, e.g. we can reuse HIR typechecking and all of the lowering steps to MIR where we can then reuse const eval. + +### Enforcing lack of Generic Parameters + +There are three ways that we enforce anon consts can't use generic parameters: +1. Name Resolution will not resolve paths to generic parameters when inside of an anon const +2. HIR Ty lowering will error when a `Self` type alias to a type referencing generic parameters is encountered inside of an anon const +3. Anon Consts do not inherit where clauses or generics from their parent definition (ie [`generics_of`] does not contain a parent for anon consts) + +```rust +// *1* Errors in name resolution +type Alias = [u8; N + 1]; +//~^ ERROR: generic parameters may not be used in const operations + +// *2* Errors in HIR Ty lowering: +struct Foo(T); +impl Foo { + fn assoc() -> [u8; { let a: Self; 0 }] {} + //~^ ERROR: generic `Self` types are currently not permitted in anonymous constants +} + +// *3* Errors due to lack of where clauses on the desugared anon const +trait Trait { + const ASSOC: usize; +} +fn foo() -> [u8; <()>::ASSOC] +//~^ ERROR: no associated item named `ASSOC` found for unit type `()` +where + (): Trait {} +``` + +The second point is particularly subtle as it is very easy to get HIR Ty lowering wrong and not properly enforce that anon consts can't use generic parameters. The existing check is too conservative and accidentally permits some generic parameters to wind up in the body of the anon const [#144547](https://github.com/rust-lang/rust/issues/144547). + +Erroneously allowing generic parameters in anon consts can sometimes lead to ICEs but can also lead to accepting illformed programs. + +The third point is also somewhat subtle, by not inheriting any of the where clauses of the parent item we can't wind up with the trait solving inferring inference variables to generic parameters based off where clauses in scope that mention generic parameters. For example inferring `?x=T` from the expression `<() as Trait>::ASSOC` and an in scope where clause of `(): Trait`. + +This also makes it much more likely that the compiler will ICE or atleast incidentally emit some kind of error if we *do* accidentally allow generic parameters in an anon const, as the anon const will have none of the necessary information in its environment to properly handle the generic parameters. + +```rust +fn foo() { + let a = [1_u8; size_of::<*mut T>()]; +} +``` + +The one exception to all of the above is repeat counts of array expressions. As a *backwards compatibility hack* we allow the repeat count const argument to use generic parameters. + +However, to avoid most of the problems involved in allowing generic parameters in anon const const arguments we require that the constant be evaluated before monomorphization (e.g. during type checking). In some sense we only allow generic parameters here when they are semantically unused. + +In the previous example the anon const can be evaluated for any type parameter `T` because raw pointers to sized types always have the same size (e.g. `8` on 64bit platforms). + +When detecting that we evaluated an anon const that syntactically contained generic parameters, but did not actually depend on them for evaluation to succeed, we emit the [`const_evaluatable_unchecked` FCW][cec_fcw]. This is intended to become a hard error once we stabilize more ways of using generic parameters in const arguments, for example `min_generic_const_args` or (the now dead) `generic_const_exprs`. + +The implementation for this FCW can be found here: [`const_eval_resolve_for_typeck`] + +### Incompatibilities with `generic_const_parameter_types` + +Supporting const paramters such as `const N: [u8; M]` or `const N: Foo` does not work very nicely with the current anon consts setup. There are two reasons for this: +1. As anon consts cannot use generic parameters, their type *also* can't reference generic parameters. This means it is fundamentally not possible to use an anon const as an argument to a const parameeter whose type still references generic parameters. + + ```rust + #![feature(adt_const_params, generic_const_parameter_types)] + + fn foo() {} + + fn bar() { + // There is no way to specify the const argument to `M` + foo::(); + } + ``` + +2. We currently require knowing the type of anon consts when lowering them during HIR ty lowering. With generic const parameter types it may be the case that the currently known type contains inference variables (ie may not be fully known yet). + + ```rust + #![feature(adt_const_params, generic_const_parameter_types)] + + fn foo() {} + + fn bar() { + // The const argument to `N` must be explicitly specified + // even though it is able to be inferred + foo::<_, { [1_u8; 3] }>(); + } + ``` + +It is currently unclear what the right way to make `generic_const_parameter_types` work nicely with the rest of const generics is. + +`generic_const_exprs` would have allowed for anon consts with types referencing generic parameters, but that design wound up unworkable. + +`min_generic_const_args` will allow for some expressions (for example array construction) to be representable without an anon const and therefore without running into these issues, though whether this is *enough* has yet to be determined. + +## Checking types of Const Arguments + +In order for a const argument to be well formed it must have the same type as the const parameter it is an argument to. For example a const argument of type `bool` for an array length is not well formed, as an array's length parameter has type `usize`. + +```rust +type Alias = [u8; B]; +//~^ ERROR: +``` + +To check this we have [`ClauseKind::ConstArgHasType(ty::Const, Ty)`][const_arg_has_type], where for each Const Parameter defined on an item we also desugar an equivalent `ConstArgHasType` clause into its list of where cluases. This ensures that whenever we check wellformedness of anything by proving all of its clauses, we also check happen to check that all of the Const Arguments have the correct type. + +```rust +fn foo() {} + +// desugars to in psuedo-rust + +fn foo() +where +// ConstArgHasType(N, usize) + N: usize, {} +``` + +Proving `ConstArgHasType` goals is implemented by first computing the type of the const argument, then equating it with the provided type. A rough outline of how the type of a Const Argument may be computed: +- [`ConstKind::Param(N)`][`ConstKind::Param`] can be looked up in the [`ParamEnv`] to find a `ConstArgHasType(N, ty)` clause +- [`ConstKind::Value`] stores the type of the value inside itself so can trivially be accessed +- [`ConstKind::Unevaluated`] can have its type computed by calling the `type_of` query +- See the implementation of proving `ConstArgHasType` goals for more detailed information + +`ConstArgHasType` is *the* soundness critical way that we check Const Arguments have the correct type. However, we do *indirectly* check the types of Const Arguments a different way in some cases. + +```rust +type Alias = [u8; true]; + +// desugars to + +const ANON: usize = true; +type Alias = [u8; ANON]; +``` + +By feeding the type of an anon const with the type of the Const Parameter we guarantee that the `ConstArgHasType` goal involving the anon const will succeed. In cases where the type of the anon const doesn't match the type of the Const Parameter what actually happens is a *type checking* error when type checking the anon const's body. + +Looking at the above example, this corresponds to `[u8; ANON]` being a well formed type because `ANON` has type `usize`, but the *body* of `ANON` being illformed and resulting in a type checking error because `true` can't be returned from a const item of type `usize`. + +[ambig-unambig-ty-and-consts]: ./ambig-unambig-ty-and-consts.md +[`ConstKind`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.ConstKind.html +[`ConstKind::Infer`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.ConstKind.html#variant.Infer +[`ConstKind::Param`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.ConstKind.html#variant.Param +[`ConstKind::Unevaluated`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.ConstKind.html#variant.Unevaluated +[`ConstKind::Value`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.ConstKind.html#variant.Value +[const_arg_has_type]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.ClauseKind.html#variant.ConstArgHasType +[`ParamEnv`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.ParamEnv.html +[`generics_of`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#impl-TyCtxt%3C'tcx%3E/method.generics_of +[`type_of`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.type_of +[`DefKind::AnonConst`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def/enum.DefKind.html#variant.AnonConst +[`hir::Node::AnonConst`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.Node.html#variant.AnonConst# +[cec_fcw]: https://github.com/rust-lang/rust/issues/76200 +[`const_eval_resolve_for_typeck`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.const_eval_resolve_for_typeck diff --git a/src/doc/rustc-dev-guide/src/conventions.md b/src/doc/rustc-dev-guide/src/conventions.md index cce1d18506946..92ed0825c8c3e 100644 --- a/src/doc/rustc-dev-guide/src/conventions.md +++ b/src/doc/rustc-dev-guide/src/conventions.md @@ -21,6 +21,16 @@ Instead, formatting should be done using `./x fmt`. It's a good habit to run Formatting is checked by the `tidy` script. It runs automatically when you do `./x test` and can be run in isolation with `./x fmt --check`. +> **Note: Formatting and test suites** +> +> Most Rust source files under `tests/` directory are not formatted for reasons +> such as whitespace sensitivity, nature of snapshot tests, location-sensitive +> comments and more. +> +> Consult the `ignore` entries in +> for which test +> files are not formatted. + If you want to use format-on-save in your editor, the pinned version of `rustfmt` is built under `build//stage0/bin/rustfmt`. diff --git a/src/doc/rustc-dev-guide/src/debuginfo/CodeView.pdf b/src/doc/rustc-dev-guide/src/debuginfo/CodeView.pdf new file mode 100644 index 0000000000000..f899d25178458 Binary files /dev/null and b/src/doc/rustc-dev-guide/src/debuginfo/CodeView.pdf differ diff --git a/src/doc/rustc-dev-guide/src/debuginfo/debugger-internals.md b/src/doc/rustc-dev-guide/src/debuginfo/debugger-internals.md new file mode 100644 index 0000000000000..114ce8a998c58 --- /dev/null +++ b/src/doc/rustc-dev-guide/src/debuginfo/debugger-internals.md @@ -0,0 +1,14 @@ +# Debugger Internals + +It is the debugger's job to convert the debug info into an in-memory representation. Both the +interpretation of the debug info and the in-memory representation are arbitrary; anything will do +so long as meaningful information can be reconstructed while the program is running. The pipeline +from raw debug info to usable types can be quite complicated. + +Once the information is in a workable format, the debugger front-end then must provide a way to +interpret and display the data, a way for users to interact with it, and an API for extensibility. + +Debuggers are vast systems and cannot be covered completely here. This section will provide a brief +overview of the subsystems directly relevant to the Rust debugging experience. + +Microsoft's debugging engine is closed source, so it will not be covered here. \ No newline at end of file diff --git a/src/doc/rustc-dev-guide/src/debuginfo/debugger-visualizers.md b/src/doc/rustc-dev-guide/src/debuginfo/debugger-visualizers.md new file mode 100644 index 0000000000000..831acbd2f8f8e --- /dev/null +++ b/src/doc/rustc-dev-guide/src/debuginfo/debugger-visualizers.md @@ -0,0 +1,111 @@ +# Debugger Visualizers + +These are typically the last step before the debugger displays the information, but the results may +be piped through a debug adapter such as an IDE's debugger API. + +The term "Visualizer" is a bit of a misnomer. The real goal isn't just to prettify the output, but +to provide an interface for the user to interact with that is as useful as possible. In many cases +this means reconstructing the original type as closely as possible to its Rust representation, but +not always. + +The visualizer interface allows generating "synthetic children" - fields that don't exist in the +debug info, but can be derived from invariants about the language and the type itself. A simple +example is allowing one to interact with the elements of a `Vec` instead of just it's `*mut u8` +heap pointer, length, and capacity. + +## `rust-lldb`, `rust-gdb`, and `rust-windbg.cmd` + +These support scripts are distributed with Rust toolchains. They locate the appropriate debugger and +the toolchain's visualizer scripts, then launch the debugger with the appropriate arguments to load +the visualizer scripts before a debugee is launched/attached to. + +## `#![debugger_visualizer]` + +[This attribute][dbg_vis_attr] allows Rust library authors to include pretty printers for their +types within the library itself. These pretty printers are of the same format as typical +visualizers, but are embedded directly into the compiled binary. These scripts are loaded +automatically by the debugger, allowing a seamless experience for users. This attribute currently +works for GDB and natvis scripts. + +[dbg_vis_attr]: https://doc.rust-lang.org/reference/attributes/debugger.html#the-debugger_visualizer-attribute + +GDB python scripts are embedded in the `.debug_gdb_scripts` section of the binary. More information +can be found [here](https://sourceware.org/gdb/current/onlinedocs/gdb.html/dotdebug_005fgdb_005fscripts-section.html). Rustc accomplishes this in [`rustc_codegen_llvm/src/debuginfo/gdb.rs`][gdb_rs] + +[gdb_rs]: https://github.com/rust-lang/rust/blob/main/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs + +Natvis files can be embedded in the PDB debug info using the [`/NATVIS` linker option][linker_opt], +and have the [highest priority][priority] when a type is resolving which visualizer to use. The +files specified by the attribute are collected into +[`CrateInfo::natvis_debugger_visualizers`][natvis] which are then added as linker arguments in +[`rustc_codegen_ssa/src/back/linker.rs`][linker_rs] + +[linker_opt]: https://learn.microsoft.com/en-us/cpp/build/reference/natvis-add-natvis-to-pdb?view=msvc-170 +[priority]: https://learn.microsoft.com/en-us/visualstudio/debugger/create-custom-views-of-native-objects?view=visualstudio#BKMK_natvis_location +[natvis]: https://github.com/rust-lang/rust/blob/e0e204f3e97ad5f79524b9c259dc38df606ed82c/compiler/rustc_codegen_ssa/src/lib.rs#L212 +[linker_rs]: https://github.com/rust-lang/rust/blob/main/compiler/rustc_codegen_ssa/src/back/linker.rs#L1106 + +LLDB is not currently supported, but there are a few methods that could potentially allow support in +the future. Officially, the intended method is via a [formatter bytecode][bytecode]. This was +created to offer a comparable experience to GDB's, but without the safety concerns associated with +embedding an entire python script. The opcodes are limited, but it works with `SBValue` and `SBType` +in roughly the same way as python visualizer scripts. Implementing this would require writing some +sort of DSL/mini compiler. + +[bytecode]: https://lldb.llvm.org/resources/formatterbytecode.html + +Alternatively, it might be possible to copy GDB's strategy entirely: create a bespoke section in the +binary and embed a python script in it. LLDB will not load it automatically, but the python API does +allow one to access the [raw sections of the debug info][SBSection]. With this, it may be possible +to extract the python script from our bespoke section and then load it in during the startup of +Rust's visualizer scripts. + +[SBSection]: https://lldb.llvm.org/python_api/lldb.SBSection.html#sbsection + +## Performance + +Before tackling the visualizers themselves, it's important to note that these are part of a +performance-sensitive system. Please excuse the break in formality, but: if I have to spend +significant time debugging, I'm annoyed. If I have to *wait on my debugger*, I'm pissed. + +Every millisecond spent in these visualizers is a millisecond longer for the user to see output. +This can be especially painful for large stackframes that contain many/large container types. +Debugger GUI's such as VSCode will request the whole stack frame at once, and this can result in +delays of tens of seconds (or even minutes) before being able to interact with any variables in the +frame. + +There is a tendancy to balk at the idea of optimizing Python code, but it really can have a +substantial impact. Remember, there is no compiler to help keep the code fast. Even simple +transformations are not done for you. It can be difficult to find Python performance tips through +all the noise of people suggesting you don't bother optimizing Python, so here are some things to +keep in mind that are relevant to these scripts: + +* Everything allocates, even `int` +* Use tuples when possible. `list` is effectively `Vec>`, whereas tuples are equivalent +to `Box<[Any]>`. They have one less layer of indirection, don't carry extra capacity and can't +grow/shrink which can be advantageous in many cases. An additional benefit is that Python caches and +recycles the underlying allocations of all tuples up to size 20. +* Regexes are slow and should be avoided when simple string manipulation will do +* Strings are immutable, thus many string operations implictly copy the contents. +* When concatenating large lists of strings, `"".join(iterable_of_strings)` is typically the fastest +way to do it. +* f-strings are generally the fastest way to do small, simple string transformations such as +surrounding a string with parentheses. +* The act of calling a function is somewhat slow (even if the function is completely empty). If the +code section is very hot, consider inlining the function manually. +* Local variable access is significantly faster than global and built-in function access +* Member/method access via the `.` operator is also slow, consider reassigning deeply nested values +to local variables to avoid this cost (e.g. `h = a.b.c.d.e.f.g.h`). +* Accessing inherited methods and fields is about 2x slower than base-class methods and fields. +Avoid inheritance whenever possible. +* Use [`__slots__`](https://wiki.python.org/moin/UsingSlots) wherever possible. `__slots__` is a way +to indicate to Python that your class's fields won't change and speeds up field access by a +noticable amount. This does require you to name your fields in advance and initialize them in +`__init__`, but it's a small price to pay for the benefits. +* Match statements/if..elif..else are not optimized in any way. The conditions are checked in order, +1 by 1. If possible, use an alternative such as dictionary dispatch or a table of values +* Compute lazily when possible +* List comprehensions are typically faster than loops, generator comprehensions are a bit slower +than list comprehensions, but use less memory. You can think of comprehensions as equivalent to +Rust's `iter.map()`. List comprehensions effectively call `collect::>` at the end, whereas +generator comprehensions do not. \ No newline at end of file diff --git a/src/doc/rustc-dev-guide/src/debuginfo/gdb-internals.md b/src/doc/rustc-dev-guide/src/debuginfo/gdb-internals.md new file mode 100644 index 0000000000000..95f543c8e94a0 --- /dev/null +++ b/src/doc/rustc-dev-guide/src/debuginfo/gdb-internals.md @@ -0,0 +1,4 @@ +# (WIP) GDB Internals + +GDB's Rust support lives at `gdb/rust-lang.h` and `gdb/rust-lang.c`. The expression parsing support +can be found in `gdb/rust-exp.h` and `gdb/rust-parse.c` \ No newline at end of file diff --git a/src/doc/rustc-dev-guide/src/debuginfo/gdb-visualizers.md b/src/doc/rustc-dev-guide/src/debuginfo/gdb-visualizers.md new file mode 100644 index 0000000000000..4027ef897f28a --- /dev/null +++ b/src/doc/rustc-dev-guide/src/debuginfo/gdb-visualizers.md @@ -0,0 +1,9 @@ +# (WIP) GDB - Python Providers + +Below are links to relevant parts of the GDB documentation + +* [Overview on writing a pretty printer](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Writing-a-Pretty_002dPrinter.html#Writing-a-Pretty_002dPrinter) +* [Pretty Printer API](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Pretty-Printing-API.html#Pretty-Printing-API) (equivalent to LLDB's `SyntheticProvider`) +* [Value API](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Values-From-Inferior.html#Values-From-Inferior) (equivalent to LLDB's `SBValue`) +* [Type API](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Types-In-Python.html#Types-In-Python) (equivalent to LLDB's `SBType`) +* [Type Printing API](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Type-Printing-API.html#Type-Printing-API) (equivalent to LLDB's `SyntheticProvider.get_type_name`) diff --git a/src/doc/rustc-dev-guide/src/debuginfo/intro.md b/src/doc/rustc-dev-guide/src/debuginfo/intro.md new file mode 100644 index 0000000000000..0f1e59fa65e26 --- /dev/null +++ b/src/doc/rustc-dev-guide/src/debuginfo/intro.md @@ -0,0 +1,114 @@ +# Debug Info + +Debug info is a collection of information generated by the compiler that allows debuggers to +correctly interpret the state of a program while it is running. That includes things like mapping +instruction addresses to lines of code in the source file, and type layout information so that +bytes in memory can be read and displayed in a meaningful way. + +Debug info can be a slightly overloaded term, covering all the layers between Rust MIR, and the +end-user seeing the output of their debugger onscreen. In brief, the stack from beginning to end is +as follows: + +1. Rustc inspects the MIR and communicates the relevant source, symbol, and type information to LLVM +2. LLVM translates this information into a target-specific debug info format during compilation +3. A debugger reads and interprets the debug info, mapping source-lines and allowing the debugee's +variables in memory to be located and read with the correct layout +4. Built-in debugger formatting and styling is applied to variables +5. User-defined scripts are run, formatting and styling the variables further +6. The debugger frontend displays the variable to the user, possibly through the means of additional +API layers (e.g. VSCode extension by way of the +[Debug Adapter Protocol](https://microsoft.github.io/debug-adapter-protocol/)) + + +> NOTE: This subsection of the dev guide is perhaps more detailed than necessary. It aims to collect +> a large amount of scattered information into one place and equip the reader with as firm a grasp of +> the entire debug stack as possible. +> +> If you are only interested in working on the visualizer +> scripts, the information in the [debugger-visualizers](./debugger-visualizers.md) and +> [testing](./testing.md) will suffice. If you need to make changes to Rust's debug node generation, +> please see [rust-codegen](./rust-codegen.md). All other sections are supplementary, but can be +> vital to understanding some of the compromises the visualizers or codegen need to make. It can +> also be valuable to know when a problem might be better solved in LLVM or the debugger itself. + +# DWARF + +The is the primary debug info format for `*-gnu` targets. It is typically bundled in with the +binary, but it [can be generated as a separate file](https://gcc.gnu.org/wiki/DebugFission). The +DWARF standard is available [here](https://dwarfstd.org/). + +> NOTE: To inspect DWARF debug info, [gimli](https://crates.io/crates/gimli) can be used +> programatically. If you prefer a GUI, the author recommends [DWEX](https://github.com/sevaa/dwex) + +# PDB/CodeView + +The primary debug info format for `*-msvc` targets. PDB is a proprietary container format created by +Microsoft that, unfortunately, +[has multiple meanings](https://docs.rs/ms-pdb/0.1.10/ms_pdb/taster/enum.Flavor.html). +We are concerned with ordinary PDB files, as Portable PDB is used mainly for .Net applications. PDB +files are separate from the compiled binary and use the `.pdb` extension. + +PDB files contain CodeView objects, equivalent to DWARF's tags. CodeView, the debugger that +consumed CodeView objects, was originally released in 1985. Its original intent was for C debugging, +and was later extended to support Visual C++. There are still minor alterations to the format to +support modern architectures and languages, but many of these changes are undocumented and/or +sparsely used. + +It is important to keep this context in mind when working with CodeView objects. Due to its origins, +the "feature-set" of these objects is very limited, and focused around the core features of C. It +does not have many of the convenience or features of modern DWARF standards. A fair number of +workarounds exist within the debug info stack to compensate for CodeView's shortcomings. + +Due to its proprietary nature, it is very difficult to find information about PDB and CodeView. Many +of the sources were made at vastly different times and contain incomplete or somewhat contradictory +information. As such this page will aim to collect as many sources as possible. + +* [CodeView 1.0 specification](./CodeView.pdf) +* LLVM + * [CodeView Overview](https://llvm.org/docs/SourceLevelDebugging.html#codeview-debug-info-format) + * [PDB Overview and technical details](https://llvm.org/docs/PDB/index.html) +* Microsoft + * [microsoft-pdb](https://github.com/microsoft/microsoft-pdb) - A C/C++ implementation of a PDB + reader. The implementation does not contain the full PDB or CodeView specification, but does + contain enough information for other PDB consumers to be written. At time of writing (Nov 2025), + this repo has been archived for several years. + * [pdb-rs](https://github.com/microsoft/pdb-rs/) - A Rust-based PDB reader and writer based on + other publicly-available information. Does not guarantee stability or spec compliance. Also + contains `pdbtool`, which can dump PDB files (`cargo install pdbtool`) + * [Debug Interface Access SDK](https://learn.microsoft.com/en-us/visualstudio/debugger/debug-interface-access/getting-started-debug-interface-access-sdk). + While it does not document the PDB format directly, details can be gleaned from the interface + itself. + +# Debuggers + +Rust supports 3 major debuggers: GDB, LLDB, and CDB. Each has its own set of requirements, +limitations, and quirks. This unfortunately creates a large surface area to account for. + +> NOTE: CDB is a proprietary debugger created by Microsoft. The underlying engine also powers +>WinDbg, KD, the Microsoft C/C++ extension for VSCode, and part of the Visual Studio Debugger. In +>these docs, it will be referred to as CDB for consistency + +While GDB and LLDB do offer facilities to natively support Rust's value layout, this isn't +completely necessary. Rust currently outputs debug info very similar to that of C++, allowing +debuggers without Rust support to work with a slightly degraded experience. More detail will be +included in later sections, but here is a quick reference for the capabilities of each debugger: + +| Debugger | Debug Info Format | Native Rust support | Expression Style | Visualizer Scripts | +| --- | --- | --- | --- | --- | +| GDB | DWARF | Full | Rust | Python | +| LLDB | DWARF and PDB | Partial | C/C++ | Python | +| CDB | PDB | None | C/C++ | Natvis | + +> IMPORTANT: CDB can be assumed to run only on Windows. No assumptions can be made about the OS +>running GDB or LLDB. + +## Unsupported + +Below, are several unsupported debuggers that are of particular note due to their potential impact +in the future. + +* [Bugstalker](https://github.com/godzie44/BugStalker) is an x86-64 Linux debugger written in Rust, +specifically to debug Rust programs. While promising, it is still in early development. +* [RAD Debugger](https://github.com/EpicGamesExt/raddebugger) is a Windows-only GUI debugger. It has +a custom debug info format that PDB is translated into. The project also includes a linker that can +generate their new debug info format during the linking phase. \ No newline at end of file diff --git a/src/doc/rustc-dev-guide/src/debuginfo/lldb-internals.md b/src/doc/rustc-dev-guide/src/debuginfo/lldb-internals.md new file mode 100644 index 0000000000000..e104f1d245327 --- /dev/null +++ b/src/doc/rustc-dev-guide/src/debuginfo/lldb-internals.md @@ -0,0 +1,208 @@ +# LLDB Internals + +LLDB's debug info processing relies on a set of extensible interfaces largely defined in +[lldb/src/Plugins][lldb_plugins]. These are meant to allow third-party compiler developers to add +language support that is loaded at run-time by LLDB, but at time of writing (Nov 2025) the public +API has not been settled on, so plugins exist either in LLDB itself or in standalone forks of LLDB. + +[lldb_plugins]: https://github.com/llvm/llvm-project/tree/main/lldb/source/Plugins + +Typically, language support will be written as a pipeline of these plugins: `*ASTParser` -> +`TypeSystem` -> `ExpressionParser`/`Language`. + +Here are some existing implementations of LLDB's plugin API: + +* [Apple's fork with support for Swift](https://github.com/swiftlang/llvm-project) +* [CodeLLDB's former fork with support for Rust](https://archive.softwareheritage.org/browse/origin/directory/?branch=refs/heads/codelldb/16.x&origin_url=https://github.com/vadimcn/llvm-project&path=lldb/source/Plugins/TypeSystem/Rust×tamp=2023-09-11T04:55:10Z) +* [A work in progress reimplementation of Rust support](https://github.com/Walnut356/llvm-project/tree/lldbrust/19.x) +* [A Rust expression parser plugin](https://github.com/tromey/lldb/tree/a0fc10ce0dacb3038b7302fff9f6cb8cb34b37c6/source/Plugins/ExpressionParser/Rust). +This was written before the `TypeSystem` API was created. Due to the freeform nature of expression parsing, the +underlyng lexing, parsing, function calling, etc. should still offer valuable insights. + +## Rust Support and TypeSystemClang + +As mentioned in the debug info overview, LLDB has partial Rust support. To further clarify, Rust +uses the plugin-pipeline that was built for C/C++ (though it contains some helpers for Rust enum +types), which relies directly on the `clang` compiler's representation of types. This imposes heavy +restrictions on how much we can change when LLDB's output doesn't match what we want. Some +workarounds can help, but at the end of the day Rust's needs are secondary compared to making sure +C and C++ compilation and debugging work correctly. + +LLDB is receptive to adding a `TypeSystemRust`, but it is a massive undertaking. This section serves +to not only document how we currently interact with [`TypeSystemClang`][ts_clang], but also as light +guidance on implementing a `TypeSystemRust` in the future. + +[ts_clang]: https://github.com/llvm/llvm-project/tree/main/lldb/source/Plugins/TypeSystem/Clang + +It is worth noting that a `TypeSystem` directly interacting with the target language's compiler is +the intention, but it is not a requirement. One can create all the necessary supporting types within +their plugin implementation. + +> Note: LLDB's documentation, including comments in the source code, is pretty sparse. Trying to +> understand how language support works by reading `TypeSystemClang`'s implementation is somewhat +> difficult due to the added requirement of understanding the `clang` compiler's internals. It is +> recommended to look at the 2 `TypeSystemRust` implementations listed above, as they are written +> "from scratch" without leveraging a compiler's type representation. They are relatively close to +> the minimum necessary to implement language support. + +## DWARF vs PDB + +LLDB is unique in being able to handle both DWARF and PDB debug information. This does come with +some added complexity. To complicate matters further, PDB support is split between `dia`, which +relies on the `msdia140.dll` library distributed with Visual Studio, and `native`, which is written +from scratch using publicly available information about the PDB format. + +> Note: `dia` was the default up to LLDB version 21. `native` is the new default as of +> LLDB 22's release. There are plans to deprecate and completely remove the `dia`-based plugins. As +> such, only `native` parsing will be discussed below. For progress, please see +> [this discourse thread][dia_discourse] and the relevant [tracking issue][dia_tracking]. +> +> `native` can be toggled via the `plugin.symbol-file.pdb.reader` setting added in LLDB 22 or using +> the environment variable `LLDB_USE_NATIVE_PDB_READER=0/1` + +[dia_discourse]: https://discourse.llvm.org/t/rfc-removing-the-dia-pdb-plugin-from-lldb/87827 +[dia_tracking]: https://github.com/llvm/llvm-project/issues/114906 + +## Debug Node Parsing + +The first step is to process the raw debug nodes into something usable. This primarily occurs in +the [`DWARFASTParser`][dwarf_ast] and [`PdbAstBuilder`][pdb_ast] classes. These classes are fed a +deserialized form of the debug info generated from [`SymbolFileDWARF`][sf_dwarf] and +[`SymbolFileNativePDB`][sf_pdb] respectively. The `SymbolFile` implementers make almost no +transformations to the underlying debug info before passing it to the parsers. For both PDB and +DWARF, the debug info is read using LLVM's debug info handlers. + +[dwarf_ast]: https://github.com/llvm/llvm-project/tree/main/lldb/source/Plugins/SymbolFile/DWARF +[pdb_ast]: https://github.com/llvm/llvm-project/tree/main/lldb/source/Plugins/SymbolFile/NativePDB +[sf_dwarf]: https://github.com/llvm/llvm-project/blob/main/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +[sf_pdb]: https://github.com/llvm/llvm-project/blob/main/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h + +The parsers translate the nodes into more convenient formats for LLDB's purposes. For `clang`, these +formats are `clang::QualType`, `clang::Decl`, and `clang::DeclContext`, which are the types `clang` +uses internally when compiling C and C++. Again, using the compiler's representation of types is not a +requirement, but the plugin system was built with it as a possibility. + +> Note: The above types will be referred to language-agnostically as `LangType`, `Decl`, and +`DeclContext` when the specific implementation details of `TypeSystemClang` are not relevant. + +`LangType` represents a type. This includes information such as the name of the type, the size and +alignment, its classification (e.g. struct, primitive, pointer), its qualifiers (e.g. +`const`, `volatile`), template arguments, function argument and return types, etc. [Here][rust_type] +is an example of what a `RustType` might look like. + +[rust_type]: https://github.com/Walnut356/llvm-project/blob/13bcfd502452606d69faeea76aec3a06db554af9/lldb/source/Plugins/TypeSystem/Rust/TypeSystemRust.h#L618 + +`Decl` represents any kind of declaration. It could be a type, a variable, a static field of a +struct, the value that a static or const is initialized with, etc. + +`DeclContext` more or less represents a scope. `DeclContext`s typically contain `Decl`s and other +`DeclContexts`, though the relationship isn't that straight forward. For example, a function can be +both a `Decl` (because function signatures are types), **and** a `DeclContext` (because functions +contain variable declarations, nested functions declarations, etc.). + +The translation process can be quite verbose, but is usually straightforward. Much of the work here +is dependant on the exact information needed to fill out `LangType`, `Decl`, and `DeclContext`. + +Once a node is translated, a pointer to it is type-erased (`void*`) and wrapped in `CompilerType`, +`CompilerDecl`, or `CompilerDeclContext`. These wrappers associate the them with the `TypeSystem` +that owns them. Methods on these objects delegates to the `TypeSystem`, which casts the `void*` back +to the appropriate `LangType*`/`Decl*`/`DeclContext*` and operates on the internals. In Rust terms, +the relationship looks something like this: + +```Rust +struct CompilerType { + inner_type: *mut c_void, + type_system: Arc, +} + +impl CompilerType { + pub fn get_byte_size(&self) -> usize { + self.type_system.get_byte_size(self.lang_type) + } + +} + +... + +impl TypeSystem for TypeSystemLang { + pub fn get_byte_size(lang_type: *mut c_void) -> usize { + let lang_type = lang_type as *mut LangType; + + // Operate on the internals of the LangType to + // determine its size + ... + } +} +``` + +## Type Systems + +The [`TypeSystem` interface][ts_interface] has 3 major purposes: + +[ts_interface]: https://github.com/llvm/llvm-project/blob/main/lldb/include/lldb/Symbol/TypeSystem.h#L69 + +1. Act as the "sole authority" of a language's types. This allows the type system to be added to +LLDB's "pool" of type systems. When an executable is loaded, the target language is determined, and +the pool is queried to find a `TypeSystem` that claims it can handle the language. One can also use +the `TypeSystem` to retrieve the backing `SymbolFile`, search for types, and synthesize basic types +that might not exist in the debug info (e.g. primitives, arrays-of-`T`, pointers-to-`T`). +2. Manage the lifetimes of the `LangType`, `Decl`, and `DeclContext` objects +3. Customize the "defaults" of how those types appear and how they can be interacted with. + +The first two functions are pretty straightforward so we will focus on the third. + +Many of the functions in the `TypeSystem` interface will look familiar if you have worked with the +visualizer scripts. These functions underpin `SBType` the `SBValue` functions with matching names. +For example, `TypeSystem::GetFormat` returns the default format for the type if no custom formatter +has been applied to it. + +Of particular note are `GetIndexOfChildWithName` and `GetNumChildren`. The `TypeSystem` versions of +these functions operate on a *type*, not a value like the `SBValue` versions. The values returned +from the `TypeSystem` functions dictate what parts of the struct can be interacted with *at all* by +the rest of LLDB. If a field is ommitted, that field effectively no longer exists to LLDB. + +Additionally, since they do not work with objects, there is no underlying memory to inspect or +interpret. Essentially, this means these functions do not have the same purpose as their equivalent +`SyntheticProvider` functions. There is no way to determine how many elements a `Vec` has or what +address those elements live at. It is also not possible to determine the value of the discriminant +of a sum-type. + +Ideally, the `TypeSystem` should expose types as they appear in the debug info with as few +alterations as possible. LLDB's synthetics and frontend can handle making the type pretty. If some +piece of information is useless, the Rust compiler should be altered to not output that debug info +in the first place. + +## Expression Parsing + +The `TypeSystem` is typically written to have a counterpart that can handle expression parsing. It +requires implementing a few extra functions in the `TypeSystem` interface. The bulk of the +expression parsing code should live in [lldb/source/Plugins/ExpressionParser][expr]. + +[expr]: https://github.com/llvm/llvm-project/tree/main/lldb/source/Plugins/ExpressionParser + +There isn't too much of note about the parser. It requires implementing a simple interpreter that +can handle (possibly simplified) Rust syntax. They operate on `lldb::ValueObject`s, which are the +objects that underpin `SBValue`. + +## Language + +The [`Language` plugins][lang_plugin] are the C++ equivalent to the Python visualizer scripts. They +operate on `SBValue` objects for the same purpose: creating synthetic children and pretty-printing. +The [CPlusPlusLanguage's implementations][cpp_lang] for the LibCxx types are great resources to +learn how visualizers should be written. + +[lang_plugin]: https://github.com/llvm/llvm-project/tree/main/lldb/source/Plugins/Language +[cpp_lang]: https://github.com/llvm/llvm-project/tree/main/lldb/source/Plugins/Language/CPlusPlus + +These plugins can access LLDB's private internals (including the underlying `TypeSystem`), so +synthetic/summary providers written as a `Language` plugin can provide higher quality output than +their python equivalent. + +While debug node parsing, type systems, and expression parsing are all closely tied to eachother, +the `Language` plugin is encapsulated more and thus can be written "standalone" for any language +that an existing type system supports. Due to the lower barrier of entry, a `RustLanguage` plugin +may be a good stepping stone towards full language support in LLDB. + +## Visualizers + +WIP \ No newline at end of file diff --git a/src/doc/rustc-dev-guide/src/debuginfo/lldb-visualizers.md b/src/doc/rustc-dev-guide/src/debuginfo/lldb-visualizers.md new file mode 100644 index 0000000000000..bb27c0e97369f --- /dev/null +++ b/src/doc/rustc-dev-guide/src/debuginfo/lldb-visualizers.md @@ -0,0 +1,662 @@ +# LLDB - Python Providers + +> NOTE: LLDB's C++<->Python FFI expects a version of python designated at the time LLDB was +>compiled. LLDB is careful to correspond this version to the minimum in typical Linux and macOS +>distributions, but on Windows there is no easy solution. If you recieve an import error regarding +>`_lldb` not existing, a mismatched Python version is likely the cause. +> +> LLDB is considering solutions this issue. For updates, see +>[this discussion][minimal_python_install] and [this github issue][issue_167001] + +[minimal_python_install]: https://discourse.llvm.org/t/a-minimal-python-install-for-lldb/88658 +[issue_167001]: https://github.com/llvm/llvm-project/issues/167001 + +> NOTE: Currently (Nov 2025), LLDB's minimum supported Python version is 3.8 with plans to update it to +>3.9 or 3.10 depending on several outside factors. Scripts should ideally be written with only the +>features available in the minimum supported Python version. Please see [this discussion][mrpv] for +>more info. + +[mrpv]: https://discourse.llvm.org/t/rfc-upgrading-llvm-s-minimum-required-python-version/88605/ + +> NOTE: The path to LLDB's python package can be located via the CLI command `lldb -P` + +LLDB provides 3 mechanisms for customizing output: + +* Formats +* Synthetic providers +* Summary providers + +## Formats + +The official documentation is [here](https://lldb.llvm.org/use/variable.html#type-format). In short, +formats allow one to set the default print format for primitive types (e.g. print `25u8` as decimal +`25`, hex `0x19`, or binary `00011001`). + +Rust will almost always need to override `unsigned char`, `signed char`, `char`, `u8`, and `i8`, to +(unsigned) decimal format. + +## Synthetic Providers + +The official documentation is [here](https://lldb.llvm.org/use/variable.html#synthetic-children), +but some information is vague, outdated, or entirely missing. + +Nearly all interaction the user has with variables will be through LLDB's +[`SBValue` objects][sbvalue] which are used both in the Python API, and internally via LLDB's +plugins and CLI. + +[sbvalue]: https://lldb.llvm.org/python_api/lldb.SBValue.html + +A Synthetic Provider is a Python class, written with a specific interface, that is associated with +one or more Rust types. The Synthetic Provider wraps `SBValue` objects and LLDB will call our +class's functions when inspecting the variable. + +The wrapped value is still an `SBValue`, but when calling e.g. `SBValue.GetChildAtIndex`, it will +internally call `SyntheticProvider.get_child_at_index`. You can check if a value has a synthetic +provider via `SBValue.IsSynthetic()`, and which synthetic it is via `SBValue.GetTypeSynthetic()`. If +you want to interact with the underlying non-synthetic value, you can call +`SBValue.GetNonSyntheticValue()`. + + +The expected interface is as follows: + +```python +class SyntheticProvider: + def __init__(self, valobj: SBValue, _lldb_internal): ... + + # optional + def update(self) -> bool: ... + + # optional + def has_children(self) -> bool: ... + + # optional + def num_children(self, max_children: int) -> int: ... + + def get_child_index(self, name: str) -> int: ... + + def get_child_at_index(self, index: int) -> SBValue: ... + + # optional + def get_type_name(self) -> str: ... + + # optional + def get_value(self) -> SBValue: ... +``` + +Below are explanations of the methods, their quirks, and how they should generally be used. If a +method overrides an `SBValue` method, that method will be listed. + +### `__init__` + +This function is called once per object, and must store the `valobj` in the python class so that it +is accessible elsewhere. Very little else should be done here. + +### (optional) `update` + +This function is called prior to LLDB interacting with a variable, but after `__init__`. LLDB tracks +whether `update` has already been called. If it has been, and if it is not possible for the variable +to have changed (e.g. inspecting the same variable a second time without stepping), it will omit the +call to `update`. + +This function has 2 purposes: + +* Store/update any information that may have changed since the last time `update` was run +* Inform LLDB if there were changes to the children such that it should flush the child cache. + +Typical operations include storing the heap pointer, length, capacity, and element type of a `Vec`, +determining an enum variable's variant, or checking which slots of a `HashMap` are occupied. + +The bool returned from this function is somewhat complicated, see: +[`update` caching](#update-caching) below for more info. When in doubt, return `False`/`None`. +Currently (Nov 2025), none of the visualizers return `True`, but that may change as the debug info +test suite is improved. + +#### `update` caching + +LLDB attempts to cache values when possible, including child values. This cache is effectively the +number of child objects, and the addresses of the underlying debugee memory that the child object +represents. By returning `True`, you indicate to LLDB that the number of children and the addresses +of those children have not changed since the last time `update` was run, meaning it can reuse the +cached children. + +**Returning `True` in the wrong circumstances will result in the debugger outputting incorrect +information**. + +Returning `False` indicates that there have been changes, the cache will be flushed, and the +children will be fetched from scratch. It is the safer option if you are unsure. + +The only relationship that matters is parent-to-child. Grandchildren depend on the `update` function +of their direct parent, not that of the grandparent. + +It is important to view the child cache as pointers-to-memory. For example, if a slice's `data_ptr` +value and `length` have not changed, returning `True` is appropriate. Even if the slice is mutable +and elements of it are overwritten (e.g. `slice[0] = 15`), because the child cache consists of +*pointers*, they will reflect the new data at that memory location. + +Conversely, if `data_ptr` has changed, that means it is pointing to a new location in memory, the +child pointers are invalid, and the cache must be flushed. If the `length` has changed, we need to +flush the cache to reflect the new number of children. If `length` has changed but `data_ptr` has +not, it is possible to store the old children in the `SyntheticProvider` itself (e.g. +`list[SBValue]`) and dole those out rather than generating them from scratch, only creating new +children if they do not already exist in the `SyntheticProvider`'s list. + +For further clarification, see [this discussion](https://discourse.llvm.org/t/when-is-it-safe-to-cache-syntheticprovider-update/88608) + +> NOTE: when testing the caching behavior, do not rely on LLDB's heuristic to persist variables when +> stepping. Instead, store the variable in a python object (e.g. `v = lldb.frame.var("var_name")`), +> step forward, and then inspect the stored variable. + +### (optional) `has_children` + +> Overrides `SBValue.MightHaveChildren` + +This is a shortcut used by LLDB to check if the value has children *at all*, without doing +potentially expensive computations to determine how many children there are (e.g. linked list). +Often, this will be a one-liner of `return True`/`return False` or +`return self.valobj.MightHaveChildren()`. + +### (optional) `num_children` + +> Overrides `SBValue.GetNumChildren` + +Returns the total number of children that LLDB should try to access when printing the type. This +number **does not** need to match to total number of synthetic children. + +The `max_children` argument can be returned if calculating the number of children can be expensive +(e.g. linked list). If this is not a consideration, `max_children` can be omitted from the function +signature. + +Additionally, fields can be intentionally "hidden" from LLDB while still being accessible to the +user. For example, one might want a `vec![1, 2, 3]` to display only its elements, but still have the +`len` and `capacity` values accessible on request. By returning `3` from `num_children`, one can +restrict LLDB to only displaying `[1, 2, 3]`, while users can still directly access `v.len` and +`v.capacity`. See: [Example Provider: Vec\](#example-provider-vect) to see an implementation of +this. + +### `get_child_index` + +> Overrides `SBValue.GetIndexOfChildWithName` +> +> Affects `SBValue.GetChildMemberWithName` + +Given a name, returns the index that the child should be accessed at. It is expected that the return +value of this function is passed directly to `get_child_at_index`. As with `num_children`, the +values returned here *can* be arbitrary, so long as they are properly coordinated with +`get_child_at_index`. + +One special value is `$$dereference$$`. Accounting for this pseudo-field will allow LLDB to use the +`SBValue` returned from `get_child_at_index` as the result of a dereference via LLDB's expression +parser (e.g. `*val` and `val->field`) + +### `get_child_at_index` + +> Overrides `SBValue.GetChildAtIndex` + +Given an index, returns a child `SBValue`. Often these are generated via +`SBValue.CreateValueFromAddress`, but less commonly `SBValue.CreateChildAtOffset`, +`SBValue.CreateValueFromExpression`, and `SBValue.CreateValueFromData`. These functions can be a +little finicky, so you may need to fiddle with them to get the output you want. + +In some cases, `SBValue.Clone` is appropriate. It creates a new child that is an exact copy of an +existing child, but with a new name. This is useful for cases like tuples, which have field names of +the style `__0`, `__1`, ... when we would prefer they were named `0`, `1`, ... + +Small alterations can be made to the resulting child before it is returned. This is useful for +`&str`/`String`, where we would prefer if the children were displayed as +`lldb.eFormatBytesWithASCII` rather than just as a decimal value. + +### (optional) `get_type_name` + +> Overrides `SBValue.GetDisplayTypeName` + +Overrides the displayed name of a type. For a synthetic `SBValue` whose type name is overridden, the +original type name can still be retrieved via `SBValue.GetTypeName()` and +`SBValue.GetType().GetName()` + +This can be helpful in shortening the name of common standard library types (e.g. +`std::collections::hash::map::HashMap` -> `HashMap`), or +in normalizing MSVC type names (e.g. `ref$` -> `&str`). + +The string manipulation can be a little tricky, especially on MSVC where we cannot conveniently +access the generic parameters of the type. + +### (optional) `get_value` + +> Overrides `SBValue.GetValue()`, `SBValue.GetValueAsUnsigned()`, `SBValue.GetValueAsSigned()`, +>`SBValue.GetValueAsAddress()`, + +The `SBValue` returned is expected to be a primitive type or pointer, and is treated as the value of +the variable in expressions. + +> IMPORTANT: The `SBValue` returned **must be stored in the `SyntheticProvider`**. There is +>currently (Nov 2025) a bug where if the `SBValue` is acquired within `get_value` and not stored +>anywhere, Python will segfault when LLDB attempts to access the value. + +## Summary Providers + +Summary providers are python functions of the following form: + +```python +def SummaryProvider(valobj: SBValue, _lldb_internal) -> str: ... +``` + +Where the returned string is passed verbatim to the user. If the returned value isn't a string, it +is naively convered to a string (e.g. `return None` prints `"None"`, not an empty string). + +If the `SBValue` passed in is of a type that has a Synthetic Provider, `valobj.IsSynthetic()` will +return `True`, and the synthetic's corresponding functions will be used. If this is undesirable, the +original value can be retrieved via `valobj.GetNonSyntheticValue()`. This can be helpful in cases +like `String`, where individually calling `GetChildAtIndex` in a loop is much slower than accessing +the heap pointer, reading the whole byte array directly from the debugee's memory, and using +Python's `bytes.decode()`. + +### Instance Summaries + +Regular `SummaryProvider` functions take an opaque `SBValue`. That `SBValue` will reflect the type's +`SyntheticProvider` if one exists, but we cannot access the `SyntheticProvider` instance itself, or +any of its internal implementation details. This is deterimental in cases where we need some of +those internal details to help complete the summary. Currently (Nov 2025), in the synthetic we just +run the non-synthetic value through the synthetic provider +(`synth = SyntheticProvider(valobj.GetNonSyntheticValue(), _dict)`), but this is obviously +suboptimal and there are plans to use the method outlined below. + +Instead, we can leverage the Python module's state to allow for instance summaries. Prior art for +this technique exists in the [old CodeLLDB Rust visualizer scripts](https://github.com/vadimcn/codelldb/blob/cf9574977b80e29c6de2c44d12f1071a53a54caf/formatters/rust.py#L110). + +In short: every Synthetic Provider's `__init__` function stores a unique ID and a weak reference to +`self` in a global dictionary. The Synthetic Provider class also implements a `get_summary` +function. The type's `SummaryProvider` is a function that looks up the unique ID in this dictionary, +then calls a `get_summary` on the instance it retrieves. + +```python +import weakref + +SYNTH_BY_ID = weakref.WeakValueDictionary() + +class SyntheticProvider: + valobj: SBValue + + # slots requires opting-in to __weakref__ + __slots__ = ("valobj", "__weakref__") + + def __init__(valobj: SBValue, _dict): + SYNTH_BY_ID[valobj.GetID()] = self + self.valobj = valobj + + def get_summary(self) -> str: + ... + +def InstanceSummaryProvider(valobj: SBValue, _dict) -> str: + # GetNonSyntheticValue should never fail as InstanceSummaryProvider implies an instance of a + # `SyntheticProvider`. No non-synthetic types should ever have this summary assigned to them + # We use GetNonSyntheticValue because the synthetic vaobj has its own unique ID + return SYNTH_BY_ID[valobj.GetNonSyntheticValue().GetID()].get_summary() +``` + +For example, one might use this for the Enum synthetic provider. The summary would like to access +the variant name, but there isn't a convenient way to reflect this via the type name or child-values +of the synthetic. By implementing an instance summary, we can retrieve the variant name via +`self.variant.GetTypeName()` and some string manipulation. + +# Writing Visualizer Scripts + +> IMPORTANT: Unlike GDB and CDB, LLDB can debug executables with either DWARF or PDB debug info. +>Visualizers must be written to account for both formats whenever possible. See: +>[rust-codegen](./rust-codegen.md#dwarf-vs-pdb) for an overview of the differences + +Scripts are injected into LLDB via the CLI command `command script import .py`. Once +injected, classes and functions can be added to the synthetic/summary pool with `type synthetic add` +and `type summary add` respectively. The summaries and synthetics can be associated with a +"category", which is typically named after the language the providers are intended for. The category +we use will be called `Rust`. + +> TIP: all LLDB commands can be prefixed with `help` (e.g. `help type synthetic add`) for a brief +description, list of arguments, and examples. + +Currently (Nov 2025) we use `command source ...`, which executes a series of CLI commands from the +file [`lldb_commands`](https://github.com/rust-lang/rust/blob/main/src/etc/lldb_commands) to add +providers. This file is somewhat unwieldy, and will soon be supplanted by the Python API equivalent +outlined below. + +## `__lldb_init_module` + +This is an optional function of the form: + +```python +def __lldb_init_module(debugger: SBDebugger, _lldb_internal) -> None: ... +``` + +This function is called at the end of `command script import ...`, but before control returns back +to the CLI. It allows the script to initialize its own state. + +Crucially, it is passed a reference to the debugger itself. This allows us to create the `Rust` +category and add providers to it. It can also allow us to conditionally change which providers we +use depending on what version of LLDB the script detects. This is vital for backwards compatibility +once we begin using recognizer functions, as recognizers were added in lldb 19.0. + +## Visualizer Resolution + +The order that visualizers resolve in is listed [here][formatters_101]. In short: + +[formatters_101]: https://lldb.llvm.org/use/variable.html#finding-formatters-101 + +* If there is an exact match (non-regex name, recognizer function, or type already matched to +provider), use that +* If the object is a pointer/reference, try to use the dereferenced type's formatter +* If the object is a typedef, check the underlying type for a formatter +* If none of the above work, iterate through the regex type matchers + +Within each of those steps, **iteration is done backwards** to allow new commands to "override" old +commands. This is important for cases like `Box` vs `Box`, were we want a specialized +synthetic for the former, but a more generalized synthetic for the latter. + +## Minutiae + +LLDB's API is very powerful, but there are some "gotchas" and unintuitive behavior, some of which +will be outlined below. The python implementation can be viewed at the path returned by the CLI +command `lldb -P` in `lldb\__init__.py`. In addition to the +[examples in the lldb repo][synth_examples], there are also [C++ visualizers][plugin_cpp] that can +be used as a reference (e.g. [LibCxxVector, the equivalent to `Vec`][cxx_vector]). While C++'s +visualizers are written in C++ and have access to LLDB's internals, the API and general practices +are very similar. + +[synth_examples]:https://github.com/llvm/llvm-project/tree/main/lldb/examples/synthetic +[plugin_cpp]: https://github.com/llvm/llvm-project/tree/main/lldb/source/Plugins/Language/CPlusPlus +[cxx_vector]: https://github.com/llvm/llvm-project/blob/main/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp + +### `SBValue` + +* Pointer/reference `SBValue`s will effectively "auto-deref" in some cases, acting as if the +children of the pointed-to-object are its own children. +* The non-function fields are typically [`property()`][property] fields that point directly to the +function anyway (e.g. `SBValue.type = property(GetType, None)`). Accessing through these shorthands +is a bit slower to access than just calling the function directly, so they should be avoided. Some +of the properties return special objects with special properties (e.g. `SBValue.member` returns an +object that acts like `dict[str, SBValue]` to access children). Internally, many of these special +objects just allocate a new class instance and call the function on the `SBValue` anyway, resulting +in additional performance loss (e.g. `SBValue.member` internally just implements `__getitem__` which +is the one-liner `return self.valobj.GetChildMemberWithName(name)`) +* `SBValue.GetID` returns a unique `int` for each value for the duration of the debug session. +Synthetic `SBValue`'s have a different ID than their underlying `SBValue`. The underlying ID can be +retrieved via `SBValue.GetNonSyntheticValue().GetID()`. +* When manually calculating an address, `SBValue.GetValueAsAddress` should be preferred over +`SBValue.GetValueAsUnsigned` due to [target-specific behavior][get_address] +* Getting a string representation of an `SBValue` can be tricky because `GetSummary` requires a +summary provider and `GetValue` requires the type be representable by a primitive. In almost all +cases where neither of those conditions are met, the type is a user defined struct that can be +passed through `StructSummaryProvider`. + +[property]: https://docs.python.org/3/library/functions.html#property +[get_address]: https://lldb.llvm.org/python_api/lldb.SBValue.html#lldb.SBValue.GetValueAsAddress + +### `SBType` + +* "Aggregate type" means a non-primitive struct/class/union +* "Template" is equivalent to "Generic" +* Types can be looked up by their name via `SBTarget.FindFirstType(type_name)`. `SBTarget` can be +acquired via `SBValue.GetTarget` +* `SBType.template_args` returns `None` instead of an empty list if the type has no generics +* It is sometimes necessary to transform a type into the type you want via functions like +`SBType.GetArrayType` and `SBType.GetPointerType`. These functions cannot fail. They ask the +underlying LLDB `TypeSystem` plugin for the type, bypassing the debug info completely. Even if the +type does not exist in the debug info at all, these functions can create the appropriate type. +* `SBType.GetCanonicalType` is effectively `SBType.GetTypedefedType` + `SBType.GetUnqualifiedType`. +Unlike `SBType.GetTypedefedType`, it will always return a valid `SBType` regardless of whether or +not the original `SBType` is a typedef. +* `SBType.GetStaticFieldWithName` was added in LLDB 18. Unfortunately, backwards compatibility isn't +always possible since the static fields are otherwise completely inaccessible. + + +# Example Provider: `Vec` + +## SyntheticProvider + +We start with the typical prelude, using `__slots__` since we have known fields. In addition to the +object itself, we also need to store the type of the elements because `Vec`'s heap pointer is a +`*mut u8`, not a `*mut T`. Rust is a statically typed language, so the type of `T` will never +change. That means we can store it during initialization. The heap pointer, length, and capacity +*can* change though, and thus are default initialized here. + +```python +import lldb + +class VecSyntheticProvider: + valobj: SBValue + data_ptr: SBValue + len: int + cap: int + element_type: SBType + + __slots__ = ( + "valobj", + "data_ptr", + "len", + "cap", + "element_type", + "__weakref__", + ) + + def __init__(valobj: SBValue, _dict) -> None: + self.valobj = valobj + # invalid type is a better default than `None` + self.element_type = SBType() + + # special handling to account for DWARF/PDB differences + if (arg := valobj.GetType().GetTemplateArgumentType(0)): + self.element_type = arg + else: + arg_name = next(get_template_args(valobj.GetTypeName())) + self.element_type = resolve_msvc_template_arg(arg_name, valobj.GetTarget()) +``` + +For the implementation of `get_template_args` and `resolve_msvc_template_arg`, please see: +[`lldb_providers.py`](https://github.com/rust-lang/rust/blob/main/src/etc/lldb_providers.py#L136). + +Next, the update function. We check if the pointer or length have changed. We can ommit checking the +capacity, as the number of children will remain the same unless `len` changes. If changing the +capacity resulted in a reallocation, `data_ptr`'s address would be different. + +If `data_ptr` and `length` haven't changed, we can take advantage of LLDB's caching and return +early. If they have changed, we store the new values and tell LLDB to flush the cache. + +```python +def update(self): + ptr = self.valobj.GetChildMemberWithName("data_ptr") + len = self.valobj.GetChildMemberWithName("length").GetValueAsUnsigned() + + if ( + self.data_ptr.GetValueAsAddress() == ptr.GetValueAsAddress() + and self.len == len + ): + # Our child address offsets and child count are still valid + # so we can reuse cached children + return True + + self.data_ptr = ptr + self.len = len + + return False +``` + +`has_children` and `num_children` are both straightforward: + +```python +def has_children(self) -> bool: + return True + +def num_children(self) -> int: + return self.len +``` + +When accessing elements, we expect values of the format `[0]`, `[1]`, etc. to mimic indexing. +Additionally, we still want the user to be able to quickly access the length and capacity, as they +can be very useful when debugging. We assign these values `u32::MAX - 1` and `u32::MAX - 2` +respectively, as we can almost surely guarantee that they will not overlap with element values. Note +that we can account for both the full and shorthand `capacity` name. + +```python + def get_child_index(self, name: str) -> int: + index = name.lstrip("[").rstrip("]") + if index.isdigit(): + return int(index) + if name == "len": + return lldb.UINT32_MAX - 1 + if name == "cap" or name == "capacity": + return lldb.UINT32_MAX - 2 + + return -1 +``` + +We now have to properly coordinate `get_child_at_index` so that the elements, length, and capacity +are all accessible. + +```python +def get_child_at_index(self, index: int) -> SBValue: + if index == UINT32_MAX - 1: + return self.valobj.GetChildMemberWithName("len") + if index == UINT32_MAX - 2: + return ( + self.valobj.GetChildMemberWithName("buf") + .GetChildMemberWithName("inner") + .GetChildMemberWithName("cap") + .GetChildAtIndex(0) + .Clone("capacity") + ) + addr = self.data_ptr.GetValueAsAddress() + addr += index * self.element_type.GetByteSize() + return self.valobj.CreateValueFromAddress(f"[{index}]", addr, self.element_type) +``` + +For the type's display name, we can strip the path qualifier. User defined types named +`Vec` will end up fully qualified, so there shouldn't be any ambiguity. We can also remove the +allocator generic, as it's very very rarely useful. We use `get_template_args` instead of +`self.element_type.GetName()` for 3 reasons: + +1. If we fail to resolve the element type for any reason, `self.valobj`'s type name can still let +the user know what the real type of the element is +2. Type names are not subject to the limitations of DWARF and PDB nodes, so the template type in +the name will reflect things like `*const`/`*mut` and `&`/`&mut`. +3. We do not currently (Nov 2025) normalize MSVC type names, but once we do, we will need to work with the +string-names of types anyway. It's also much easier to cache a string-to-string conversion compared +to an `SBType`-to-string conversion. + +```python +def get_type_name(self) -> str: + return f"Vec<{next(get_template_args(self.valobj))}>" +``` + +There isn't an appropriate primitive value with which to represent a `Vec`, so we simply ommit +the `get_value` function. + +## SummaryProvider + +The summary provider is very simple thanks to our synthetic provider. The only real hiccup is that +`GetSummary` only returns a value if the object's type has a `SummaryProvider`. If it doesn't, it +will return an empty string which is not ideal. In a full set of visualizer scripts, we can ensure +that every type that doesn't have a `GetSummary()` or a `GetValue()` is a struct, and then delegate +to a generic `StructSummaryProvider`. For this demonstration, I will gloss over that detail. + +```python +def VecSummaryProvider(valobj: SBValue, _lldb_internal) -> str: + children = [] + for i in range(valobj.GetNumChildren()): + child = valobj.GetChildAtIndex(i) + summary = child.GetSummary() + if summary is None: + summary = child.GetValue() + if summary is None: + summary = "{...}" + + children.append(summary) + + return f"vec![{", ".join(children)}]" +``` + +## Enabling the providers + +Assume this synthetic is imported into `lldb_lookup.py` + +With CLI commands: + +```txt +type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)Vec<.+>$" --category Rust +type summary add -F lldb_lookup.summary_lookup -x "^(alloc::([a-z_]+::)+)Vec<.+>$" --category Rust +``` + +With `__lldb_init_module`: + +```python +def __lldb_init_module(debugger: SBDebugger, _dict: LLDBOpaque): + # Ensure the category exists and is enabled + rust_cat = debugger.GetCategory("Rust") + + if not rust_cat.IsValid(): + rust_cat = debugger.CreateCategory("Rust") + + rust_cat.SetEnabled(True) + + # Register Vec providers + vec_regex = r"^(alloc::([a-z_]+::)+)Vec<.+>$" + sb_name = lldb.SBTypeNameSpecifier(vec_regex, is_regex=True) + + sb_synth = lldb.SBTypeSynthetic.CreateWithClassName("lldb_lookup.VecSyntheticProvider") + sb_synth.SetOptions(lldb.eTypeOptionCascade) + + sb_summary = lldb.SBTypeSummary.CreateWithFunctionName("lldb_lookup.VecSummaryProvider") + sb_summary.SetOptions(lldb.eTypeOptionCascade) + + rust_cat.AddTypeSynthetic(sb_name, sb_synth) + rust_cat.AddSummary(sb_name, sb_summary) +``` + +## Output + +Without providers: + +```text +(lldb) v vec_v +(alloc::vec::Vec) vec_v = { + buf = { + inner = { + ptr = { + pointer = (pointer = "\n") + _marker = {} + } + cap = (__0 = 5) + alloc = {} + } + _marker = {} + } + len = 5 +} +(lldb) v vec_v[0] +error: :1:6: subscripted value is not an array or pointer + 1 | vec_v[0] + | ^ +``` + +With providers (`v ` prints the summary and then a list of all children): + +```text +(lldb) v vec_v +(Vec) vec_v = vec![10, 20, 30, 40, 50] { + [0] = 10 + [1] = 20 + [2] = 30 + [3] = 40 + [4] = 50 +} +(lldb) v vec_v[0] +(int) vec_v[0] = 10 +``` + +We can also confirm that the "hidden" length and capacity are still accessible: + +```text +(lldb) v vec_v.len +(unsigned long long) vec_v.len = 5 +(lldb) v vec_v.capacity +(unsigned long long) vec_v.capacity = 5 +(lldb) v vec_v.cap +(unsigned long long) vec_v.cap = 5 +``` \ No newline at end of file diff --git a/src/doc/rustc-dev-guide/src/debuginfo/llvm-codegen.md b/src/doc/rustc-dev-guide/src/debuginfo/llvm-codegen.md new file mode 100644 index 0000000000000..cc052b6b965f1 --- /dev/null +++ b/src/doc/rustc-dev-guide/src/debuginfo/llvm-codegen.md @@ -0,0 +1,12 @@ +# (WIP) LLVM Codegen + +When Rust calls an LLVM `DIBuilder` function, LLVM translates the given information to a +["debug record"][dbg_record] that is format-agnostic. These records can be inspected in the LLVM-IR. + +[dbg_record]: https://llvm.org/docs/SourceLevelDebugging.html#debug-records + +It is important to note that tags within the debug records are **always stored as DWARF tags**. If +the target calls for PDB debug info, during codegen the debug records will then be passed through +[a module that translates the DWARF tags to their CodeView counterparts][cv]. + +[cv]:https://github.com/llvm/llvm-project/blob/main/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp \ No newline at end of file diff --git a/src/doc/rustc-dev-guide/src/debuginfo/natvis-visualizers.md b/src/doc/rustc-dev-guide/src/debuginfo/natvis-visualizers.md new file mode 100644 index 0000000000000..653e7d5d65555 --- /dev/null +++ b/src/doc/rustc-dev-guide/src/debuginfo/natvis-visualizers.md @@ -0,0 +1,3 @@ +# (WIP) CDB - Natvis + +Official documentation for Natvis can be found [here](https://learn.microsoft.com/en-us/visualstudio/debugger/create-custom-views-of-native-objects) and [here](https://code.visualstudio.com/docs/cpp/natvis) diff --git a/src/doc/rustc-dev-guide/src/debuginfo/rust-codegen.md b/src/doc/rustc-dev-guide/src/debuginfo/rust-codegen.md new file mode 100644 index 0000000000000..73fa68d36076a --- /dev/null +++ b/src/doc/rustc-dev-guide/src/debuginfo/rust-codegen.md @@ -0,0 +1,183 @@ +# Rust Codegen + +The first phase in debug info generation requires Rust to inspect the MIR of the program and +communicate it to LLVM. This is primarily done in [`rustc_codegen_llvm/debuginfo`][llvm_di], though +some type-name processing exists in [`rustc_codegen_ssa/debuginfo`][ssa_di]. Rust communicates to +LLVM via the `DIBuilder` API - a thin wrapper around LLVM's internals that exists in +[rustc_llvm][rustc_llvm]. + +[llvm_di]: https://github.com/rust-lang/rust/tree/main/compiler/rustc_codegen_llvm/src/debuginfo +[ssa_di]: https://github.com/rust-lang/rust/tree/main/compiler/rustc_codegen_ssa/src/debuginfo +[rustc_llvm]: https://github.com/rust-lang/rust/tree/main/compiler/rustc_llvm + +# Type Information + +Type information typically consists of the type name, size, alignment, as well as things like +fields, generic parameters, and storage modifiers if they are relevant. Much of this work happens in +[rustc_codegen_llvm/src/debuginfo/metadata][di_metadata]. + +[di_metadata]: https://github.com/rust-lang/rust/blob/main/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs + +It is important to keep in mind that the goal is not necessarily "represent types exactly how they +appear in Rust", rather it is to represent them in a way that allows debuggers to most accurately +reconstruct the data during debugging. This distinction is vital to understanding the core work that +occurs on this layer; many changes made here will be for the purpose of working around debugger +limitations when no other option will work. + +## Quirks + +Rust's generated DI nodes "pretend" to be C/C++ for both CDB and LLDB's sake. This can result in +some unintuitive and non-idiomatic debug info. + +### Pointers and Reference + +Wide pointers/references/`Box` are treated as a struct with 2 fields: `data_ptr` and `length`. + +All non-wide pointers, references, and `Box` pointers are output as pointer nodes, and no +distinction is made between `mut` and non-`mut`. Several attempts have been made to rectify this, +but unfortunately there is not a straightforward solution. Using the `reference` DI nodes of the +respective formats has pitfalls. There is a semantic difference between C++ references and Rust +references that is unreconcilable. + +>From [cppreference](https://en.cppreference.com/w/cpp/language/reference.html): +> +>References are not objects; **they do not necessarily occupy storage**, although the compiler may +>allocate storage if it is necessary to implement the desired semantics (e.g. a non-static data +>member of reference type usually increases the size of the class by the amount necessary to store +>a memory address). +> +>Because references are not objects, **there are no arrays of references, no pointers to references, and no references to references** + +The current proposed solution is to simply [typedef the pointer nodes][issue_144394]. + +[issue_144394]: https://github.com/rust-lang/rust/pull/144394 + +Using the `const` qualifier to denote non-`mut` poses potential issues due to LLDB's internal +optimizations. In short, LLDB attempts to cache the child-values of variables (e.g. struct fields, +array elements) when stepping through code. A heuristic is used to determine which values are safely +cache-able, and `const` is part of that heuristic. Research has not been done into how this would +interact with things like Rust's interior mutability constructs. + +### DWARF vs PDB + +While most of the type information is fairly straight forward, one notable issue is the debug info +format of the target. Each format has different semantics and limitations, as such they require +slightly different debug info in some cases. This is gated by calls to +[`cpp_like_debuginfo`][cpp_like]. + +[cpp_like]: https://github.com/rust-lang/rust/blob/main/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs#L813 + +### Naming + +Rust attempts to communicate type names as accurately as possible, but debuggers and debug info +formats do not always respect that. + +Due to limitations in MSVC's expression parser, the following name transformations are made for PDB +debug info: + +| Rust name | MSVC name | +| --- | --- | +| `&str`/`&mut str` | `ref$`/`ref_mut$` | +| `&[T]`/`&mut [T]` | `ref$ >`/`ref_mut$ >`[^1] | +| `[T; N]` | `array$` | +| `RustEnum` | `enum2$` | +| `(T1, T2)` | `tuple$`| +| `*const T` | `ptr_const$` | +| `*mut T` | `ptr_mut$` | +| `usize` | `size_t`[^2] | +| `isize` | `ptrdiff_t`[^2] | +| `uN` | `unsigned __intN`[^2] | +| `iN` | `__intN`[^2] | +| `f32` | `float`[^2] | +| `f64` | `double`[^2] | +| `f128` | `fp128`[^2] | + +[^1]: MSVC's expression parser will treat `>>` as a right shift. It is necessary to separate +consecutive `>`'s with a space (`> >`) in type names. + +[^2]: While these type names are generated as part of the debug info node (which is then wrapped in +a typedef node with the Rust name), once the LLVM-IR node is converted to a CodeView node, the type +name information is lost. This is because CodeView has special shorthand nodes for primitive types, +and those shorthand nodes to not have a "name" field. + +### Generics + +Rust outputs generic *type* information (`T` in `ArrayVec`), but not generic *value* +information (`N` in `ArrayVec`). + +CodeView does not have a leaf node for generics/C++ templates, so all generic information is lost +when generating PDB debug info. There are workarounds that allow the debugger to retrieve the +generic arguments via the type name, but it is fragile solution at best. Efforts are being made to +contact Microsoft to correct this deficiency, and/or to use one of the unused CodeView node types as +a suitable equivalent. + +### Type aliases + +Rust outputs typedef nodes in several cases to help account for debugger limitiations, but it does +not currently output nodes for [type aliases in the source code][type_aliases]. + +[type_aliases]: https://doc.rust-lang.org/reference/items/type-aliases.html + +### Enums + +Enum DI nodes are generated in [rustc_codegen_llvm/src/debuginfo/metadata/enums][di_metadata_enums] + +[di_metadata_enums]: https://github.com/rust-lang/rust/tree/main/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums + +#### DWARF + +DWARF has a dedicated node for discriminated unions: `DW_TAG_variant`. It is a container that +references `DW_TAG_variant_part` nodes that may or may not contain a discriminant value. The +hierarchy looks as follows: + +```txt +DW_TAG_structure_type (top-level type for the coroutine) + DW_TAG_variant_part (variant part) + DW_AT_discr (reference to discriminant DW_TAG_member) + DW_TAG_member (discriminant member) + DW_TAG_variant (variant 1) + DW_TAG_variant (variant 2) + DW_TAG_variant (variant 3) + DW_TAG_structure_type (type of variant 1) + DW_TAG_structure_type (type of variant 2) + DW_TAG_structure_type (type of variant 3) +``` + +#### PDB +PDB does not have a dedicated node, so it generates the C equivalent of a discriminated union: + +```c +union enum2$ { + enum VariantNames { + First, + Second + }; + struct Variant0 { + struct First { + // fields + }; + static const enum2$::VariantNames NAME; + static const unsigned long DISCR_EXACT; + enum2$::Variant0::First value; + }; + struct Variant1 { + struct Second { + // fields + }; + static enum2$::VariantNames NAME; + static unsigned long DISCR_EXACT; + enum2$::Variant1::Second value; + }; + enum2$::Variant0 variant0; + enum2$::Variant1 variant1; + unsigned long tag; +} +``` + +An important note is that due to limitations in LLDB, the `DISCR_*` value generated is always a +`u64` even if the value is not `#[repr(u64)]`. This is largely a non-issue for LLDB because the +`DISCR_*` value and the `tag` are read into `uint64_t` values regardless of their type. + +# Source Information + +TODO \ No newline at end of file diff --git a/src/doc/rustc-dev-guide/src/debuginfo/testing.md b/src/doc/rustc-dev-guide/src/debuginfo/testing.md new file mode 100644 index 0000000000000..f58050875e1a0 --- /dev/null +++ b/src/doc/rustc-dev-guide/src/debuginfo/testing.md @@ -0,0 +1,8 @@ +# (WIP) Testing + +The debug info test suite is undergoing a substantial rewrite. This section will be filled out as +the rewrite makes progress. + +Please see [this tracking issue][148483] for more information. + +[148483]: https://github.com/rust-lang/rust/issues/148483 \ No newline at end of file diff --git a/src/doc/rustc-dev-guide/src/diagnostics/error-codes.md b/src/doc/rustc-dev-guide/src/diagnostics/error-codes.md index 1693432b90de7..c7bb6669dce46 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics/error-codes.md +++ b/src/doc/rustc-dev-guide/src/diagnostics/error-codes.md @@ -33,40 +33,22 @@ written, as always: ask your reviewer or ask around on the Rust Zulip. Error codes are stored in `compiler/rustc_error_codes`. -To create a new error, you first need to find the next available -code. You can find it with `tidy`: +To create a new error, you first need to find the next available code. +You can find it by opening `rustc_error_codes/src/lib.rs` and scrolling down +to the end of the `error_codes!` macro declaration. -``` -./x test tidy -``` - -This will invoke the tidy script, which generally checks that your code obeys -our coding conventions. Some of these jobs check error codes and ensure that -there aren't duplicates, etc (the tidy check is defined in -`src/tools/tidy/src/error_codes.rs`). Once it is finished with that, tidy will -print out the highest used error code: - -``` -... -tidy check -Found 505 error codes -Highest error code: `E0591` -... -``` - -Here we see the highest error code in use is `E0591`, so we _probably_ want -`E0592`. To be sure, run `rg E0592` and check, you should see no references. +Here we might see the highest error code in use is `E0805`, so we _probably_ want +`E0806`. To be sure, run `rg E0806` and check, you should see no references. You will have to write an extended description for your error, -which will go in `rustc_error_codes/src/error_codes/E0592.md`. -To register the error, open `rustc_error_codes/src/error_codes.rs` and add the -code (in its proper numerical order) into` register_diagnostics!` macro, like -this: +which will go in `rustc_error_codes/src/error_codes/E0806.md`. +To register the error, add the code (in its proper numerical order) to +the `error_codes!` macro, like this: ```rust -register_diagnostics! { - ... - E0592: include_str!("./error_codes/E0592.md"), +macro_rules! error_codes { +... +0806, } ``` @@ -75,7 +57,7 @@ To actually issue the error, you can use the `struct_span_code_err!` macro: ```rust struct_span_code_err!(self.dcx(), // some path to the `DiagCtxt` here span, // whatever span in the source you want - E0592, // your new error code + E0806, // your new error code fluent::example::an_error_message) .emit() // actually issue the error ``` diff --git a/src/doc/rustc-dev-guide/src/fuzzing.md b/src/doc/rustc-dev-guide/src/fuzzing.md index cc98b49a97c68..635c01d21aeec 100644 --- a/src/doc/rustc-dev-guide/src/fuzzing.md +++ b/src/doc/rustc-dev-guide/src/fuzzing.md @@ -3,12 +3,13 @@ For the purposes of this guide, *fuzzing* is any testing methodology that -involves compiling a wide variety of programs in an attempt to uncover bugs in -rustc. Fuzzing is often used to find internal compiler errors (ICEs). Fuzzing -can be beneficial, because it can find bugs before users run into them and -provide small, self-contained programs that make the bug easier to track down. +involves compiling a wide variety of programs in an attempt to uncover bugs in rustc. +Fuzzing is often used to find internal compiler errors (ICEs). +Fuzzing can be beneficial, because it can find bugs before users run into them. +It also provides small, self-contained programs that make the bug easier to track down. However, some common mistakes can reduce the helpfulness of fuzzing and end up -making contributors' lives harder. To maximize your positive impact on the Rust +making contributors' lives harder. +To maximize your positive impact on the Rust project, please read this guide before reporting fuzzer-generated bugs! ## Guidelines @@ -21,31 +22,31 @@ project, please read this guide before reporting fuzzer-generated bugs! - Include a reasonably minimal, standalone example along with any bug report - Include all of the information requested in the bug report template - Search for existing reports with the same message and query stack -- Format the test case with `rustfmt`, if it maintains the bug +- Format the test case with `rustfmt` - Indicate that the bug was found by fuzzing *Please don't:* - Don't report lots of bugs that use internal features, including but not limited to `custom_mir`, `lang_items`, `no_core`, and `rustc_attrs`. -- Don't seed your fuzzer with inputs that are known to crash rustc (details - below). +- Don't seed your fuzzer with inputs that are known to crash rustc (details below). ### Discussion If you're not sure whether or not an ICE is a duplicate of one that's already -been reported, please go ahead and report it and link to issues you think might -be related. In general, ICEs on the same line but with different *query stacks* -are usually distinct bugs. For example, [#109020][#109020] and [#109129][#109129] -had similar error messages: +been reported, please go ahead and report it and link to issues you think might be related. +In general, ICEs on the same line but with different *query stacks* are usually distinct bugs. +For example, [#109020] and [#109129] had similar error messages: ``` error: internal compiler error: compiler/rustc_middle/src/ty/normalize_erasing_regions.rs:195:90: Failed to normalize <[closure@src/main.rs:36:25: 36:28] as std::ops::FnOnce<(Emplacable<()>,)>>::Output, maybe try to call `try_normalize_erasing_regions` instead ``` + ``` error: internal compiler error: compiler/rustc_middle/src/ty/normalize_erasing_regions.rs:195:90: Failed to normalize <() as Project>::Assoc, maybe try to call `try_normalize_erasing_regions` instead ``` -but different query stacks: + +However, they have different query stacks: ``` query stack during panic: #0 [fn_abi_of_instance] computing call ABI of `<[closure@src/main.rs:36:25: 36:28] as core::ops::function::FnOnce<(Emplacable<()>,)>>::call_once - shim(vtable)` @@ -63,10 +64,10 @@ end of query stack ## Building a corpus -When building a corpus, be sure to avoid collecting tests that are already -known to crash rustc. A fuzzer that is seeded with such tests is more likely to -generate bugs with the same root cause, wasting everyone's time. The simplest -way to avoid this is to loop over each file in the corpus, see if it causes an +When building a corpus, be sure to avoid collecting tests that are already known to crash rustc. +A fuzzer that is seeded with such tests is more likely to +generate bugs with the same root cause. +The simplest way to avoid this is to loop over each file in the corpus, see if it causes an ICE, and remove it if so. To build a corpus, you may want to use: @@ -74,26 +75,26 @@ To build a corpus, you may want to use: - The rustc/rust-analyzer/clippy test suites (or even source code) --- though avoid tests that are already known to cause failures, which often begin with comments like `//@ failure-status: 101` or `//@ known-bug: #NNN`. -- The already-fixed ICEs in the archived [Glacier][glacier] repository --- though +- The already-fixed ICEs in the archived [Glacier] repository --- though avoid the unfixed ones in `ices/`! [glacier]: https://github.com/rust-lang/glacier ## Extra credit -Here are a few things you can do to help the Rust project after filing an ICE. +Here are a few things you can do to help the Rust project after filing an ICE: - [Bisect][bisect] the bug to figure out when it was introduced. - If you find the regressing PR / commit, you can mark the issue with the label - `S-has-bisection`. If not, consider applying `E-needs-bisection` instead. + If you find the regressing PR / commit, you can mark the issue with the label `S-has-bisection`. + If not, consider applying `E-needs-bisection` instead. - Fix "distractions": problems with the test case that don't contribute to triggering the ICE, such as syntax errors or borrow-checking errors -- Minimize the test case (see below). If successful, you can label the - issue with `S-has-mcve`. Otherwise, you can apply `E-needs-mcve`. +- Minimize the test case (see below). + If successful, you can label the issue with `S-has-mcve`. + Otherwise, you can apply `E-needs-mcve`. - Add the minimal test case to the rust-lang/rust repo as a [crash test]. While you're at it, consider including other "untracked" crashes in your PR. - Please don't forget to mark all relevant issues with `S-bug-has-test` once - your PR is merged. + Please don't forget to mark all relevant issues with `S-bug-has-test` once your PR is merged. See also [applying and removing labels][labeling]. @@ -103,13 +104,14 @@ See also [applying and removing labels][labeling]. ## Minimization -It is helpful to carefully *minimize* the fuzzer-generated input. When -minimizing, be careful to preserve the original error, and avoid introducing +It is helpful to carefully *minimize* the fuzzer-generated input. +When minimizing, be careful to preserve the original error, and avoid introducing distracting problems such as syntax, type-checking, or borrow-checking errors. -There are some tools that can help with minimization. If you're not sure how -to avoid introducing syntax, type-, and borrow-checking errors while using -these tools, post both the complete and minimized test cases. Generally, +There are some tools that can help with minimization. +If you're not sure how to avoid introducing syntax, type-, and borrow-checking errors while using +these tools, post both the complete and minimized test cases. +Generally, *syntax-aware* tools give the best results in the least amount of time. [`treereduce-rust`][treereduce] and [picireny][picireny] are syntax-aware. [`halfempty`][halfempty] is not, but is generally a high-quality tool. @@ -121,31 +123,32 @@ these tools, post both the complete and minimized test cases. Generally, ## Effective fuzzing When fuzzing rustc, you may want to avoid generating machine code, since this -is mostly done by LLVM. Try `--emit=mir` instead. +is mostly done by LLVM. +Try `--emit=mir` instead. -A variety of compiler flags can uncover different issues. `-Zmir-opt-level=4` -will turn on MIR optimization passes that are not run by default, potentially -uncovering interesting bugs. `-Zvalidate-mir` can help uncover such bugs. +A variety of compiler flags can uncover different issues. +`-Zmir-opt-level=4` will turn on MIR optimization passes that are not run by default, potentially +uncovering interesting bugs. +`-Zvalidate-mir` can help uncover such bugs. If you're fuzzing a compiler you built, you may want to build it with `-C -target-cpu=native` or even PGO/BOLT to squeeze out a few more executions per -second. Of course, it's best to try multiple build configurations and see +target-cpu=native` or even PGO/BOLT to squeeze out a few more executions per second. +Of course, it's best to try multiple build configurations and see what actually results in superior throughput. You may want to build rustc from source with debug assertions to find -additional bugs, though this is a trade-off: it can slow down fuzzing by -requiring extra work for every execution. To enable debug assertions, add this -to `bootstrap.toml` when compiling rustc: +additional bugs, though this can slow down fuzzing by +requiring extra work for every execution. +To enable debug assertions, add this to `bootstrap.toml` when compiling rustc: ```toml -[rust] -debug-assertions = true +rust.debug-assertions = true ``` -ICEs that require debug assertions to reproduce should be tagged -[`requires-debug-assertions`][requires-debug-assertions]. +ICEs that require debug assertions to reproduce should be tagged +[`requires-debug-assertions`]. -[requires-debug-assertions]: https://github.com/rust-lang/rust/labels/requires-debug-assertions +[`requires-debug-assertions`]: https://github.com/rust-lang/rust/labels/requires-debug-assertions ## Existing projects diff --git a/src/doc/rustc-dev-guide/src/getting-started.md b/src/doc/rustc-dev-guide/src/getting-started.md index 34bc5b59dd03c..36d19e6c570e2 100644 --- a/src/doc/rustc-dev-guide/src/getting-started.md +++ b/src/doc/rustc-dev-guide/src/getting-started.md @@ -96,7 +96,7 @@ For example: Not all important or beginner work has issue labels. See below for how to find work that isn't labelled. -[help-wanted-search]: https://github.com/issues?q=is%3Aopen+is%3Aissue+org%3Arust-lang+no%3Aassignee+label%3AE-easy%2C%22good+first+issue%22%2Cgood-first-issue%2CE-medium%2CEasy%2CE-help-wanted%2CE-mentor+-label%3AS-blocked+-linked%3Apr+ +[help-wanted-search]: https://github.com/issues?q=is%3Aopen%20is%3Aissue%20org%3Arust-lang%20no%3Aassignee%20label%3AE-easy%2CE-medium%2CE-help-wanted%2CE-mentor%20-label%3AS-blocked%20-linked%3Apr [Triage]: ./contributing.md#issue-triage ### Recurring work @@ -151,6 +151,9 @@ Issues that have been resolved but do not have a regression test are marked with Writing unit tests is a low-risk, lower-priority task that offers new contributors a great opportunity to familiarize themselves with the testing infrastructure and contribution workflow. +You can see a list of needs test issues [here][needs-test-issues]. + +[needs-test-issues]: https://github.com/rust-lang/rust/issues?q=is%3Aissue%20is%3Aopen%20label%3AE-needs-test%20no%3Aassignee ### Contributing to std (standard library) diff --git a/src/doc/rustc-dev-guide/src/hir/ambig-unambig-ty-and-consts.md b/src/doc/rustc-dev-guide/src/hir/ambig-unambig-ty-and-consts.md deleted file mode 100644 index d4f504ad2a98d..0000000000000 --- a/src/doc/rustc-dev-guide/src/hir/ambig-unambig-ty-and-consts.md +++ /dev/null @@ -1,63 +0,0 @@ -# Ambig/Unambig Types and Consts - -Types and Consts args in the HIR can be in two kinds of positions ambiguous (ambig) or unambiguous (unambig). Ambig positions are where -it would be valid to parse either a type or a const, unambig positions are where only one kind would be valid to -parse. - -```rust -fn func(arg: T) { - // ^ Unambig type position - let a: _ = arg; - // ^ Unambig type position - - func::(arg); - // ^ ^ - // ^^^^ Ambig position - - let _: [u8; 10]; - // ^^ ^^ Unambig const position - // ^^ Unambig type position -} - -``` - -Most types/consts in ambig positions are able to be disambiguated as either a type or const during parsing. Single segment paths are always represented as types in the AST but may get resolved to a const parameter during name resolution, then lowered to a const argument during ast-lowering. The only generic arguments which remain ambiguous after lowering are inferred generic arguments (`_`) in path segments. For example, in `Foo<_>` it is not clear whether the `_` argument is an inferred type argument, or an inferred const argument. - -In unambig positions, inferred arguments are represented with [`hir::TyKind::Infer`][ty_infer] or [`hir::ConstArgKind::Infer`][const_infer] depending on whether it is a type or const position respectively. -In ambig positions, inferred arguments are represented with `hir::GenericArg::Infer`. - -A naive implementation of this would result in there being potentially 5 places where you might think an inferred type/const could be found in the HIR from looking at the structure of the HIR: -1. In unambig type position as a `hir::TyKind::Infer` -2. In unambig const arg position as a `hir::ConstArgKind::Infer` -3. In an ambig position as a [`GenericArg::Type(TyKind::Infer)`][generic_arg_ty] -4. In an ambig position as a [`GenericArg::Const(ConstArgKind::Infer)`][generic_arg_const] -5. In an ambig position as a [`GenericArg::Infer`][generic_arg_infer] - -Note that places 3 and 4 would never actually be possible to encounter as we always lower to `GenericArg::Infer` in generic arg position. - -This has a few failure modes: -- People may write visitors which check for `GenericArg::Infer` but forget to check for `hir::TyKind/ConstArgKind::Infer`, only handling infers in ambig positions by accident. -- People may write visitors which check for `hir::TyKind/ConstArgKind::Infer` but forget to check for `GenericArg::Infer`, only handling infers in unambig positions by accident. -- People may write visitors which check for `GenericArg::Type/Const(TyKind/ConstArgKind::Infer)` and `GenericArg::Infer`, not realising that we never represent inferred types/consts in ambig positions as a `GenericArg::Type/Const`. -- People may write visitors which check for *only* `TyKind::Infer` and not `ConstArgKind::Infer` forgetting that there are also inferred const arguments (and vice versa). - -To make writing HIR visitors less error prone when caring about inferred types/consts we have a relatively complex system: - -1. We have different types in the compiler for when a type or const is in an unambig or ambig position, `hir::Ty` and `hir::Ty<()>`. [`AmbigArg`][ambig_arg] is an uninhabited type which we use in the `Infer` variant of `TyKind` and `ConstArgKind` to selectively "disable" it if we are in an ambig position. - -2. The [`visit_ty`][visit_ty] and [`visit_const_arg`][visit_const_arg] methods on HIR visitors only accept the ambig position versions of types/consts. Unambig types/consts are implicitly converted to ambig types/consts during the visiting process, with the `Infer` variant handled by a dedicated [`visit_infer`][visit_infer] method. - -This has a number of benefits: -- It's clear that `GenericArg::Type/Const` cannot represent inferred type/const arguments -- Implementors of `visit_ty` and `visit_const_arg` will never encounter inferred types/consts making it impossible to write a visitor that seems to work right but handles edge cases wrong -- The `visit_infer` method handles *all* cases of inferred type/consts in the HIR making it easy for visitors to handle inferred type/consts in one dedicated place and not forget cases - -[ty_infer]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.TyKind.html#variant.Infer -[const_infer]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.ConstArgKind.html#variant.Infer -[generic_arg_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.GenericArg.html#variant.Type -[generic_arg_const]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.GenericArg.html#variant.Const -[generic_arg_infer]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.GenericArg.html#variant.Infer -[ambig_arg]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.AmbigArg.html -[visit_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/intravisit/trait.Visitor.html#method.visit_ty -[visit_const_arg]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/intravisit/trait.Visitor.html#method.visit_const_arg -[visit_infer]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/intravisit/trait.Visitor.html#method.visit_infer diff --git a/src/doc/rustc-dev-guide/src/notification-groups/about.md b/src/doc/rustc-dev-guide/src/notification-groups/about.md index c649b930fe9ff..917a0f8a1020e 100644 --- a/src/doc/rustc-dev-guide/src/notification-groups/about.md +++ b/src/doc/rustc-dev-guide/src/notification-groups/about.md @@ -22,6 +22,7 @@ Here's the list of the notification groups: - [Apple](./apple.md) - [ARM](./arm.md) - [Emscripten](./emscripten.md) +- [LoongArch](./loongarch.md) - [RISC-V](./risc-v.md) - [WASI](./wasi.md) - [WebAssembly](./wasm.md) @@ -63,6 +64,7 @@ Example PRs: * [Example of adding yourself to the Apple group.](https://github.com/rust-lang/team/pull/1434) * [Example of adding yourself to the ARM group.](https://github.com/rust-lang/team/pull/358) * [Example of adding yourself to the Emscripten group.](https://github.com/rust-lang/team/pull/1579) +* [Example of adding yourself to the LoongArch group.](https://github.com/rust-lang/team/pull/2176) * [Example of adding yourself to the RISC-V group.](https://github.com/rust-lang/team/pull/394) * [Example of adding yourself to the WASI group.](https://github.com/rust-lang/team/pull/1580) * [Example of adding yourself to the WebAssembly group.](https://github.com/rust-lang/team/pull/1581) diff --git a/src/doc/rustc-dev-guide/src/notification-groups/loongarch.md b/src/doc/rustc-dev-guide/src/notification-groups/loongarch.md new file mode 100644 index 0000000000000..0a3707a9ad999 --- /dev/null +++ b/src/doc/rustc-dev-guide/src/notification-groups/loongarch.md @@ -0,0 +1,22 @@ +# LoongArch notification group + +**Github Label:** [O-loongarch]
+**Ping command:** `@rustbot ping loongarch` + +[O-loongarch]: https://github.com/rust-lang/rust/labels/O-loongarch + +This list will be used to ask for help both in diagnosing and testing +LoongArch-related issues as well as suggestions on how to resolve +interesting questions regarding our LoongArch support. + +The group also has an associated Zulip channel ([`#t-compiler/loong-arch`]) +where people can go to pose questions and discuss LoongArch-specific topics. + +So, if you are interested in participating, please sign up for the +LoongArch group! To do so, open a PR against the [rust-lang/team] +repository. Just [follow this example][eg], but change the username to +your own! + +[`#t-compiler/loong-arch`]: https://rust-lang.zulipchat.com/#narrow/channel/551512-t-compiler.2Floong-arch +[rust-lang/team]: https://github.com/rust-lang/team +[eg]: https://github.com/rust-lang/team/pull/2176 diff --git a/src/doc/rustc-dev-guide/src/opaque-types-type-alias-impl-trait.md b/src/doc/rustc-dev-guide/src/opaque-types-type-alias-impl-trait.md index 956f568285a02..9f20bfc708dce 100644 --- a/src/doc/rustc-dev-guide/src/opaque-types-type-alias-impl-trait.md +++ b/src/doc/rustc-dev-guide/src/opaque-types-type-alias-impl-trait.md @@ -12,15 +12,16 @@ type Foo = impl Bar; This declares an opaque type named `Foo`, of which the only information is that it implements `Bar`. Therefore, any of `Bar`'s interface can be used on a `Foo`, -but nothing else (regardless of whether it implements any other traits). +but nothing else (regardless of whether the concrete type implements any other traits). Since there needs to be a concrete background type, -you can (as of January 2021) express that type +you can (as of May 2025) express that type by using the opaque type in a "defining use site". ```rust,ignore struct Struct; impl Bar for Struct { /* stuff */ } +#[define_opaque(Foo)] fn foo() -> Foo { Struct } @@ -28,6 +29,27 @@ fn foo() -> Foo { Any other "defining use site" needs to produce the exact same type. +Note that defining a type alias to an opaque type is an unstable feature. +To use it, you need `nightly` and the annotations `#![feature(type_alias_impl_trait)]` on the file and `#[define_opaque(Foo)]` on the method that links the opaque type to the concrete type. +Complete example: + +```rust +#![feature(type_alias_impl_trait)] + +trait Bar { /* stuff */ } + +type Foo = impl Bar; + +struct Struct; + +impl Bar for Struct { /* stuff */ } + +#[define_opaque(Foo)] +fn foo() -> Foo { + Struct +} +``` + ## Defining use site(s) Currently only the return value of a function can be a defining use site @@ -61,3 +83,28 @@ impl Baz for Quux { fn foo() -> Self::Foo { ... } } ``` + +For this you would also need to use `nightly` and the (different) `#![feature(impl_trait_in_assoc_type)]` annotation. +Note that you don't need a `#[define_opaque(Foo)]` on the method anymore as the opaque type is mentioned in the function signature (behind the associated type). +Complete example: + +``` +#![feature(impl_trait_in_assoc_type)] + +trait Bar {} +struct Zap; + +impl Bar for Zap {} + +trait Baz { + type Foo; + fn foo() -> Self::Foo; +} + +struct Quux; + +impl Baz for Quux { + type Foo = impl Bar; + fn foo() -> Self::Foo { Zap } +} +``` diff --git a/src/doc/rustc-dev-guide/src/query.md b/src/doc/rustc-dev-guide/src/query.md index 8377a7b2f31a7..5df9de7620381 100644 --- a/src/doc/rustc-dev-guide/src/query.md +++ b/src/doc/rustc-dev-guide/src/query.md @@ -69,22 +69,24 @@ are cheaply cloneable; insert an `Rc` if necessary). If, however, the query is *not* in the cache, then the compiler will call the corresponding **provider** function. A provider is a function -implemented in a specific module and **manually registered** into the -[`Providers`][providers_struct] struct during compiler initialization. -The macro system generates the [`Providers`][providers_struct] struct, -which acts as a function table for all query implementations, where each +implemented in a specific module and **manually registered** into either +the [`Providers`][providers_struct] struct (for local crate queries) or +the [`ExternProviders`][extern_providers_struct] struct (for external crate queries) +during compiler initialization. The macro system generates both structs, +which act as function tables for all query implementations, where each field is a function pointer to the actual provider. -**Note:** The `Providers` struct is generated by macros and acts as a function table for all query implementations. -It is **not** a Rust trait, but a plain struct with function pointer fields. +**Note:** Both the `Providers` and `ExternProviders` structs are generated by macros and act as function tables for all query implementations. +They are **not** Rust traits, but plain structs with function pointer fields. **Providers are defined per-crate.** The compiler maintains, internally, a table of providers for every crate, at least -conceptually. Right now, there are really two sets: the providers for -queries about the **local crate** (that is, the one being compiled) -and providers for queries about **external crates** (that is, -dependencies of the local crate). Note that what determines the crate -that a query is targeting is not the *kind* of query, but the *key*. +conceptually. There are two sets of providers: +- The `Providers` struct for queries about the **local crate** (that is, the one being compiled) +- The `ExternProviders` struct for queries about **external crates** (that is, +dependencies of the local crate) + +Note that what determines the crate that a query is targeting is not the *kind* of query, but the *key*. For example, when you invoke `tcx.type_of(def_id)`, that could be a local query or an external query, depending on what crate the `def_id` is referring to (see the [`self::keys::Key`][Key] trait for more @@ -117,31 +119,31 @@ they define both a `provide` and a `provide_extern` function, through ### How providers are set up -When the tcx is created, it is given the providers by its creator using -the [`Providers`][providers_struct] struct. This struct is generated by -the macros here, but it is basically a big list of function pointers: - -[providers_struct]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/query/struct.Providers.html +When the tcx is created, it is given both the local and external providers by its creator using +the `Providers` struct from `rustc_middle::util`. This struct contains both the local and external providers: ```rust,ignore -struct Providers { - type_of: for<'tcx> fn(TyCtxt<'tcx>, DefId) -> Ty<'tcx>, - // ... one field for each query +pub struct Providers { + pub queries: crate::query::Providers, // Local crate providers + pub extern_queries: crate::query::ExternProviders, // External crate providers + pub hooks: crate::hooks::Providers, } ``` +Each of these provider structs is generated by the macros and contains function pointers for their respective queries. + #### How are providers registered? -The `Providers` struct is filled in during compiler initialization, mainly by the `rustc_driver` crate. -But the actual provider functions are implemented in various `rustc_*` crates (like `rustc_middle`, `rustc_hir_analysis`, etc). +The `util::Providers` struct is filled in during compiler initialization, by the `rustc_interface` crate from the `DEFAULT_QUERY_PROVIDERS` static. +The actual provider functions are defined across various `rustc_*` crates (like `rustc_middle`, `rustc_hir_analysis`, etc). To register providers, each crate exposes a [`provide`][provide_fn] function that looks like this: [provide_fn]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/fn.provide.html ```rust,ignore -pub fn provide(providers: &mut Providers) { - *providers = Providers { +pub fn provide(providers: &mut query::Providers) { + *providers = query::Providers { type_of, // ... add more providers here ..*providers @@ -149,27 +151,104 @@ pub fn provide(providers: &mut Providers) { } ``` -- This function takes a mutable reference to the `Providers` struct and sets the fields to point to the correct provider functions. -- You can also assign fields individually, e.g. `providers.type_of = type_of;`. +Note that this function accepts `query::Providers` not `util::Providers`. It is exceedingly rare to need a `provide` function that doesn't just accept `query::Providers`. If more than the `queries` field of `util::Providers` is being updated then `util::Providers` can be accepted instead: +```rust,ignore +pub fn provide(providers: &mut rustc_middle::util::Providers) { + providers.queries.type_of = type_of; + // ... add more local providers here + + providers.extern_queries.type_of = extern_type_of; + // ... add more external providers here + + providers.hooks.some_hook = some_hook; + // ... add more hooks here +} +``` + +Note that `util::Providers` implements `DerefMut` to `query::Providers` so callers of the `provide` functions can pass in a `util::Providers` and it will just work for provider functions that accept `query::Providers` too + +- This function takes a mutable reference to the `query::Providers` struct and sets the fields to point to the correct provider functions. +- You can also assign queries individually, e.g. `providers.type_of = type_of;`. +- You can assign fields individually for each provider type (local, external, and hooks). #### Adding a new provider -Suppose you want to add a new query called `fubar`. You would: +Suppose you want to add a new query called `fubar`. This section focuses on wiring up the providers; for how to declare the query itself in the big `rustc_queries!` macro, see [Adding a new query](#adding-a-new-query) below. + +In practice you usually: -1. Implement the provider function: +1. Decide which crate "owns" the query (for example `rustc_hir_analysis`, `rustc_mir_build`, or another `rustc_*` crate). +2. In that crate, look for an existing `provide` function: + ```rust,ignore + pub fn provide(providers: &mut query::Providers) { + // existing assignments + } + ``` + If it exists, you will extend it to set the field for your new query. If the crate does not yet have a `provide` function, add one and make sure it is included in `DEFAULT_QUERY_PROVIDERS` in the `rustc_interface` crate so that it actually gets called during initialization (see the discussion above). +3. Implement the provider function itself: ```rust,ignore - fn fubar<'tcx>(tcx: TyCtxt<'tcx>, key: DefId) -> Fubar<'tcx> { ... } + fn fubar<'tcx>(tcx: TyCtxt<'tcx>, key: LocalDefId) -> Fubar<'tcx> { ... } ``` -2. Register it in the `provide` function: +4. Register it in the crate's `provide` function: ```rust,ignore - pub fn provide(providers: &mut Providers) { - *providers = Providers { + pub fn provide(providers: &mut query::Providers) { + *providers = query::Providers { fubar, ..*providers }; } ``` +### How queries interact with external crate metadata + +When a query is made for an external crate (i.e., a dependency), the query system needs to load the information from that crate's metadata. +This is handled by the [`rustc_metadata` crate][rustc_metadata], which is responsible for decoding and providing the information stored in the `.rmeta` files. + +The process works like this: + +1. When a query is made, the query system first checks if the `DefId` refers to a local or external crate by checking if `def_id.krate == LOCAL_CRATE`. + This determines whether to use the local provider from [`Providers`][providers_struct] or the external provider from [`ExternProviders`][extern_providers_struct]. + +2. For external crates, the query system will look for a provider in the [`ExternProviders`][extern_providers_struct] struct. + The `rustc_metadata` crate registers these external providers through the `provide_extern` function in `rustc_metadata/src/rmeta/decoder/cstore_impl.rs`. Just like: + ```rust + pub fn provide_extern(providers: &mut ExternProviders) { + providers.foo = |tcx, def_id| { + // Load and decode metadata for external crate + let cdata = CStore::from_tcx(tcx).get_crate_data(def_id.krate); + cdata.foo(def_id.index) + }; + // Register other external providers... + } + ``` + +3. The metadata is stored in a binary format in `.rmeta` files that contains pre-computed information about the external crate, such as types, function signatures, trait implementations, and other information needed by the compiler. When an external query is made, the `rustc_metadata` crate: + - Loads the `.rmeta` file for the external crate + - Decodes the metadata using the `Decodable` trait + - Returns the decoded information to the query system + +This approach avoids recompiling external crates, allows for faster compilation of dependent crates, and enables incremental compilation to work across crate boundaries. +Here is a simplified example, when you call `tcx.type_of(def_id)` for a type defined in an external crate, the query system will: +1. Detect that the `def_id` refers to an external crate by checking `def_id.krate != LOCAL_CRATE` +2. Call the appropriate provider from `ExternProviders` which was registered by `rustc_metadata` +3. The provider will load and decode the type information from the external crate's metadata +4. Return the decoded type to the caller + +This is why most `rustc_*` crates only need to provide local providers - the external providers are handled by the metadata system. +The only exception is when a crate needs to provide special handling for external queries, in which case it would implement both local and external providers. + +When we define a new query that should work across crates, it does not automatically become cross-crate just because it is listed in `rustc_queries!`. You will typically need to: + +- Add the query to `rustc_queries!` with appropriate modifiers (for example whether it is cached on disk). +- Implement a local provider in the owning crate and register it via that crate's `provide` function. +- Add an external provider in `rustc_metadata` via `provide_extern`, and ensure the query's result is encoded and decoded in the crate metadata. + +An example of introducing such a cross-crate query can be found in commit [`996a185`](https://github.com/rust-lang/rust/commit/996a185) in the `rust-lang/rust` repository. + +[rustc_metadata]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_metadata/index.html +[providers_struct]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/query/struct.Providers.html +[extern_providers_struct]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/query/struct.ExternProviders.html + --- ## Adding a new query @@ -263,4 +342,3 @@ More discussion and issues: [GitHub issue #42633]: https://github.com/rust-lang/rust/issues/42633 [Incremental Compilation Beta]: https://internals.rust-lang.org/t/incremental-compilation-beta/4721 [Incremental Compilation Announcement]: https://blog.rust-lang.org/2016/09/08/incremental.html - diff --git a/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-json-test-suite.md b/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-json-test-suite.md index e19a8204ab41a..5781a12ca44c1 100644 --- a/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-json-test-suite.md +++ b/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-json-test-suite.md @@ -4,7 +4,7 @@ This page is specifically about the test suite named `rustdoc-json`, which tests For other test suites used for testing rustdoc, see [§Rustdoc test suites](../tests/compiletest.md#rustdoc-test-suites). Tests are run with compiletest, and have access to the usual set of [directives](../tests/directives.md). -Frequenly used directives here are: +Frequently used directives here are: - [`//@ aux-build`][aux-build] to have dependencies. - `//@ edition: 2021` (or some other edition). @@ -23,8 +23,8 @@ Also, talk about how it works ## jsondocck -[jsondocck] processes direcives given in comments, to assert that the values in the output are expected. -It's alot like [htmldocck](./rustdoc-test-suite.md) in that way. +[jsondocck] processes directives given in comments, to assert that the values in the output are expected. +It's a lot like [htmldocck](./rustdoc-test-suite.md) in that way. It uses [JSONPath] as a query language, which takes a path, and returns a *list* of values that that path is said to match to. @@ -48,7 +48,7 @@ These are defined in [`directive.rs`]. Values can be either JSON values, or variables. - JSON values are JSON literals, e.g. `true`, `"string"`, `{"key": "value"}`. - These often need to be quoted using `'`, to be processed as 1 value. See [§Argument spliting](#argument-spliting) + These often need to be quoted using `'`, to be processed as 1 value. See [§Argument splitting](#argument-splitting) - Variables can be used to store the value in one path, and use it in later queries. They are set with the `//@ set = ` directive, and accessed with `$` @@ -57,7 +57,7 @@ Values can be either JSON values, or variables. //@ is $.some.other.path $foo ``` -### Argument spliting +### Argument splitting Arguments to directives are split using the [shlex] crate, which implements POSIX shell escaping. This is because both `` and `` arguments to [directives](#directives) frequently have both diff --git a/src/doc/rustc-dev-guide/src/solve/invariants.md b/src/doc/rustc-dev-guide/src/solve/invariants.md index 8ec15f339e51b..4a2c22fec83fe 100644 --- a/src/doc/rustc-dev-guide/src/solve/invariants.md +++ b/src/doc/rustc-dev-guide/src/solve/invariants.md @@ -116,6 +116,12 @@ We do however break this invariant in a few cases, some of which are due to bugs - the builtin trait object trait implementation can overlap with a user-defined impl: [#57893](https://github.com/rust-lang/rust/issues/57893) +### Goals with can be proven in a non-empty environment also hold during monomorphization ✅ + +If a goal can be proven in a generic environment, the goal should still hold after instantiating +it with fully concrete types and no where-clauses in scope. + +This is assumed by codegen which ICEs when encountering non-overflow ambiguity. This invariant is currently broken by specialization ([#147507](https://github.com/rust-lang/rust/issues/147507)) and by marker traits ([#149502](https://github.com/rust-lang/rust/issues/149502)). #### The type system is complete during the implicit negative overlap check in coherence ✅ @@ -168,5 +174,10 @@ We lookup types using structural equality during codegen, but this shouldn't nec Semantically different `'static` types need different `TypeId`s to avoid transmutes, for example `for<'a> fn(&'a str)` vs `fn(&'static str)` must have a different `TypeId`. +## Evaluation of const items is deterministic ✅ + +As the values of const items can feed into the type system, it is important that the value of a const item is always the same in every crate. If this isn't the case then we can wind up with associated types with "equal" const arguments and so are "equal" associated types, and yet when normalized during codegen in different crates actually wind up as different types. + +Notably this does *not* extend to const *functions*, as the type system only works with the results of const *items* it's actually fine for const functions to be non deterministic so long as that doesn't affect the final value of a const item. [coherence chapter]: ../coherence.md diff --git a/src/doc/rustc-dev-guide/src/solve/sharing-crates-with-rust-analyzer.md b/src/doc/rustc-dev-guide/src/solve/sharing-crates-with-rust-analyzer.md new file mode 100644 index 0000000000000..bf0d4fe3a11b7 --- /dev/null +++ b/src/doc/rustc-dev-guide/src/solve/sharing-crates-with-rust-analyzer.md @@ -0,0 +1,192 @@ +# Sharing the trait solver with rust-analyzer + +rust-analyzer can be viewed as a compiler frontend: it performs tasks similar to the parts of rustc +that run before code generation, such as parsing, lexing, AST construction and lowering, HIR +lowering, and even limited MIR building and const evaluation. + +However, because rust-analyzer is primarily a language server, its architecture differs in several +important ways from that of rustc. +Despite these differences, a substantial portion of its responsibilities—most notably type +inference and trait solving—overlap with the compiler. + +To avoid duplication and to maintain consistency between the two implementations, rust-analyzer +reuses several crates from rustc, relying on shared abstractions wherever possible. + +## Shared Crates + +Currently, rust-analyzer depends on several `rustc_*` crates from the compiler: + +- `rustc_abi` +- `rustc_ast_ir` +- `rustc_index` +- `rustc_lexer` +- `rustc_next_trait_solver` +- `rustc_parse_format` +- `rustc_pattern_analysis` +- `rustc_type_ir` + +Since these crates are not published on `crates.io` as part of the compiler's normal distribution +process, rust-analyzer maintains its own publishing pipeline. +It uses the [rustc-auto-publish script][rustc-auto-publish] to publish these crates to `crates.io` +with the prefix `ra-ap-rustc_*` +(for example: https://crates.io/crates/ra-ap-rustc_next_trait_solver). +rust-analyzer then depends on these re-published crates in its own build. + +For trait solving specifically, the primary shared crates are `rustc_type_ir` and +`rustc_next_trait_solver`, which provide the core IR and solver logic used by both compiler +frontends. + +## The Abstraction Layer + +Because rust-analyzer is a language server, it must handle frequently changing source code and +partially invalid or incomplete source codes. +This requires an infrastructure quite different from rustc's, especially in the layers between +the source code and the HIR—for example, `Ty` and its backing interner. + +To bridge these differences, the compiler provides `rustc_type_ir` as an abstraction layer shared +between rustc and rust-analyzer. +This crate defines the fundamental interfaces used to represent types, predicates, and the context +required by the trait solver. +Both rustc and rust-analyzer implement these traits for their own concrete type representations, +and `rustc_next_trait_solver` is written to be generic over these abstractions. + +In addition to these interfaces, `rustc_type_ir` also includes several non-trivial components built +on top of the abstraction layer—such as elaboration logic and the search graph machinery used by the +solver. + +## Design Concepts + +`rustc_next_trait_solver` is intended to depend only on the abstract interfaces defined in +`rustc_type_ir`. +To support this, the type-system traits in `rustc_type_ir` must expose every interface the solver +requires—for example, [creating a new inference type variable][ir new_infer] +([rustc][rustc new_infer], [rust-analyzer][r-a new_infer]). +For items that do not need compiler-specific representations, `rustc_type_ir` defines them directly +as structs or enums parameterized over these traits—for example, [`TraitRef`][ir tr]. + +The following are some notable items from the `rustc_type_ir` crate. + +### `trait Interner` + +The central trait in this design is [`Interner`][ir interner], which specifies all +implementation-specific details for both rustc and rust-analyzer. +Among its essential responsibilities: + +- it **specifies** the concrete types used by the implementation via its + [associated types][ir interner assocs]; these form the backbone of how each compiler frontend + instantiates the shared IR, +- it provides the context required by the solver (e.g., querying [lang items][ir require_lang_item], + enumerating [all blanket impls for a trait][ir for_each_blanket_impl]); +- and it must implement [`IrPrint`][ir irprint] for formatting and tracing. + In practice, these `IrPrint` impls simply route to existing formatting logic inside rustc or + rust-analyzer. + +In rustc, [`TyCtxt` implements `Interner`][rustc interner impl]: it exposes the rustc's query +methods, and the required `Interner` trait methods are implemented by invoking those queries. +In rust-analyzer, the implementing type is named [`DbInterner`][r-a interner impl] (as it performs +most interning through the [salsa] database), and most of its methods are backed by salsa queries +rather than rustc queries. + +### `mod inherent` + +Another notable item in `rustc_type_ir` is the [`inherent` module][ir inherent]. +This module provides *forward definitions* of inherent methods—expressed as traits—corresponding to +methods that exist on compiler-specific types such as `Ty` or `GenericArg`. +These definitions allow the generic crates (such as `rustc_next_trait_solver`) to call methods that +are implemented differently in rustc and rust-analyzer. + +Code in generic crates should import these definitions with: + +```rust +use inherent::*; +``` + +These forward definitions **must never be used inside the concrete implementations themselves**. +Crates that implement the traits from `mod inherent` should call the actual inherent methods on +their concrete types once those types are nameable. + +You can find rustc’s implementations of these traits in the +[rustc_middle::ty::inherent][rustc inherent impl] module. +For rust-analyzer, the corresponding implementations are located across several modules under +`hir_ty::next_solver`, such as [hir_ty::next_solver::region][r-a inherent impl]. + +### `trait InferCtxtLike` and `trait SolverDelegate` + +These two traits correspond to the role of [`InferCtxt`][rustc inferctxt] in rustc. + +[`InferCtxtLike`][ir inferctxtlike] must be defined in `rustc_infer` due to coherence +constraints(orphan rules). +As a result, it cannot provide functionality that lives in `rustc_trait_selection`. +Instead, behavior that depends on trait-solving logic is abstracted into a separate trait, +[`SolverDelegate`][ir solverdelegate]. +Its implementator in rustc is [simply a newtype struct over `InferCtxt`][rustc solverdelegate impl] +in `rustc_trait_selection`. + +(In rust-analyzer, it is also implemented for a newtype wrapper over its own +[`InferCtxt`][r-a inferctxtlike impl], primarily to mirror rustc’s structure, although this is not +strictly necessary because all solver-related logic already resides in the `hir-ty` crate.) + +In the long term, the ideal design is to move all of the logic currently expressed through +`SolverDelegate` into `rustc_next_trait_solver`, with any required core operations added directly to +`InferCtxtLike`. +This would allow more of the solver’s behavior to live entirely inside the shared solver crate. + +### `rustc_type_ir::search_graph::{Cx, Delegate}` + +The abstraction traits [`Cx`][ir searchgraph cx impl] and [`Delegate`][ir searchgraph delegate impl] +are already implemented within `rustc_next_trait_solver` itself. +Therefore, users of the shared crates—both rustc and rust-analyzer—do not need to provide their own +implementations. + +These traits exist primarily to support fuzzing of the search graph independently of the full trait +solver. +This infrastructure is used by the external fuzzing project: +. + +## Long-term plans for supporting rust-analyzer + +In general, we aim to support rust-analyzer just as well as rustc in these shared crates—provided +doing so does not substantially harm rustc's performance or maintainability. +(e.g., [#145377][pr 145377], [#146111][pr 146111], [#146182][pr 146182] and [#147723][pr 147723]) + +Shared crates that require nightly-only features must guard such code behind a `nightly` feature +flag, since rust-analyzer is built with the stable toolchain. + +Looking forward, we plan to uplift more shared logic into `rustc_type_ir`. +There are still duplicated implementations between rustc and rust-analyzer—such as `ObligationCtxt` +([rustc][rustc oblctxt], [rust-analyzer][r-a oblctxt]) and type coercion logic +([rustc][rustc coerce], [rust-analyzer][r-a coerce])—that we would like to unify over time. + +[rustc-auto-publish]: https://github.com/rust-analyzer/rustc-auto-publish +[ir new_infer]: https://doc.rust-lang.org/1.91.1/nightly-rustc/rustc_type_ir/inherent/trait.Ty.html#tymethod.new_infer +[rustc new_infer]: https://github.com/rust-lang/rust/blob/63b1db05801271e400954e41b8600a3cf1482363/compiler/rustc_middle/src/ty/sty.rs#L413-L420 +[r-a new_infer]: https://github.com/rust-lang/rust-analyzer/blob/34f47d9298c478c12c6c4c0348771d1b05706e09/crates/hir-ty/src/next_solver/ty.rs#L59-L92 +[ir tr]: https://doc.rust-lang.org/1.91.1/nightly-rustc/rustc_type_ir/struct.TraitRef.html +[ir interner]: https://doc.rust-lang.org/1.91.1/nightly-rustc/rustc_type_ir/trait.Interner.html +[ir interner assocs]: https://doc.rust-lang.org/1.91.1/nightly-rustc/rustc_type_ir/trait.Interner.html#required-associated-types +[ir require_lang_item]: https://doc.rust-lang.org/1.91.1/nightly-rustc/rustc_type_ir/trait.Interner.html#tymethod.require_lang_item +[ir for_each_blanket_impl]: https://doc.rust-lang.org/1.91.1/nightly-rustc/rustc_type_ir/trait.Interner.html#tymethod.for_each_blanket_impl +[ir irprint]: https://doc.rust-lang.org/1.91.1/nightly-rustc/rustc_type_ir/ir_print/trait.IrPrint.html +[rustc interner impl]: https://doc.rust-lang.org/1.91.1/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#impl-Interner-for-TyCtxt%3C'tcx%3E +[r-a interner impl]: https://github.com/rust-lang/rust-analyzer/blob/a50c1ccc9cf3dab1afdc857a965a9992fbad7a53/crates/hir-ty/src/next_solver/interner.rs +[salsa]: https://github.com/salsa-rs/salsa +[ir inherent]: https://doc.rust-lang.org/1.91.1/nightly-rustc/rustc_type_ir/inherent/index.html +[rustc inherent impl]: https://doc.rust-lang.org/1.91.1/nightly-rustc/rustc_middle/ty/inherent/index.html +[r-a inherent impl]: https://github.com/rust-lang/rust-analyzer/blob/a50c1ccc9cf3dab1afdc857a965a9992fbad7a53/crates/hir-ty/src/next_solver/region.rs +[ir inferctxtlike]: https://doc.rust-lang.org/1.91.1/nightly-rustc/rustc_type_ir/trait.InferCtxtLike.html +[rustc inferctxt]: https://doc.rust-lang.org/1.91.1/nightly-rustc/rustc_infer/infer/struct.InferCtxt.html +[rustc inferctxtlike impl]: https://doc.rust-lang.org/1.91.1/nightly-rustc/src/rustc_infer/infer/context.rs.html#14-332 +[r-a inferctxtlike impl]: https://github.com/rust-lang/rust-analyzer/blob/a50c1ccc9cf3dab1afdc857a965a9992fbad7a53/crates/hir-ty/src/next_solver/infer/context.rs +[ir solverdelegate]: https://doc.rust-lang.org/1.91.1/nightly-rustc/rustc_next_trait_solver/delegate/trait.SolverDelegate.html +[rustc solverdelegate impl]: https://doc.rust-lang.org/1.91.1/nightly-rustc/rustc_trait_selection/solve/delegate/struct.SolverDelegate.html +[r-a solverdelegate impl]: https://github.com/rust-lang/rust-analyzer/blob/a50c1ccc9cf3dab1afdc857a965a9992fbad7a53/crates/hir-ty/src/next_solver/solver.rs#L27-L330 +[ir searchgraph cx impl]: https://doc.rust-lang.org/1.91.1/nightly-rustc/src/rustc_type_ir/interner.rs.html#550-575 +[ir searchgraph delegate impl]: https://doc.rust-lang.org/1.91.1/nightly-rustc/src/rustc_next_trait_solver/solve/search_graph.rs.html#20-123 +[pr 145377]: https://github.com/rust-lang/rust/pull/145377 +[pr 146111]: https://github.com/rust-lang/rust/pull/146111 +[pr 146182]: https://github.com/rust-lang/rust/pull/146182 +[pr 147723]: https://github.com/rust-lang/rust/pull/147723 +[rustc oblctxt]: https://github.com/rust-lang/rust/blob/63b1db05801271e400954e41b8600a3cf1482363/compiler/rustc_trait_selection/src/traits/engine.rs#L48-L386 +[r-a oblctxt]: https://github.com/rust-lang/rust-analyzer/blob/34f47d9298c478c12c6c4c0348771d1b05706e09/crates/hir-ty/src/next_solver/obligation_ctxt.rs +[rustc coerce]: https://github.com/rust-lang/rust/blob/63b1db05801271e400954e41b8600a3cf1482363/compiler/rustc_hir_typeck/src/coercion.rs +[r-a coerce]: https://github.com/rust-lang/rust-analyzer/blob/34f47d9298c478c12c6c4c0348771d1b05706e09/crates/hir-ty/src/infer/coerce.rs \ No newline at end of file diff --git a/src/doc/rustc-dev-guide/src/tests/ci.md b/src/doc/rustc-dev-guide/src/tests/ci.md index a30af309a54eb..e132946ae83ee 100644 --- a/src/doc/rustc-dev-guide/src/tests/ci.md +++ b/src/doc/rustc-dev-guide/src/tests/ci.md @@ -447,23 +447,6 @@ More information is available in the [toolstate documentation]. [rust-toolstate]: https://rust-lang-nursery.github.io/rust-toolstate [toolstate documentation]: https://forge.rust-lang.org/infra/toolstate.html -## Public CI dashboard - -To monitor the Rust CI, you can have a look at the [public dashboard] maintained by the infra team. - -These are some useful panels from the dashboard: - -- Pipeline duration: check how long the auto builds take to run. -- Top slowest jobs: check which jobs are taking the longest to run. -- Change in median job duration: check what jobs are slowest than before. Useful - to detect regressions. -- Top failed jobs: check which jobs are failing the most. - -To learn more about the dashboard, see the [Datadog CI docs]. - -[Datadog CI docs]: https://docs.datadoghq.com/continuous_integration/ -[public dashboard]: https://p.datadoghq.com/sb/3a172e20-e9e1-11ed-80e3-da7ad0900002-b5f7bb7e08b664a06b08527da85f7e30 - ## Determining the CI configuration If you want to determine which `bootstrap.toml` settings are used in CI for a diff --git a/src/doc/rustc-dev-guide/src/tests/compiletest.md b/src/doc/rustc-dev-guide/src/tests/compiletest.md index a691380234cd1..e0924f8538ef0 100644 --- a/src/doc/rustc-dev-guide/src/tests/compiletest.md +++ b/src/doc/rustc-dev-guide/src/tests/compiletest.md @@ -90,7 +90,8 @@ The following test suites are available, with links for more information: | `rustdoc-ui` | Check terminal output of `rustdoc` ([see also](ui.md)) | Some rustdoc-specific tests can also be found in `ui/rustdoc/`. -These check rustdoc-related or -specific lints that (also) run as part of `rustc`, not (only) `rustdoc`. +These tests ensure that certain lints that are emitted as part of executing rustdoc +are also run when executing rustc. Run-make tests pertaining to rustdoc are typically named `run-make/rustdoc-*/`. [rustdoc-html-tests]: ../rustdoc-internals/rustdoc-test-suite.md diff --git a/src/doc/rustc-dev-guide/src/ty_module/instantiating_binders.md b/src/doc/rustc-dev-guide/src/ty_module/instantiating_binders.md index 0d1108c72e0ef..7e29b95437140 100644 --- a/src/doc/rustc-dev-guide/src/ty_module/instantiating_binders.md +++ b/src/doc/rustc-dev-guide/src/ty_module/instantiating_binders.md @@ -1,6 +1,6 @@ # Instantiating `Binder`s -Much like [`EarlyBinder`], when accessing the inside of a [`Binder`] we must first discharge it by replacing the bound vars with some other value. This is for much the same reason as with `EarlyBinder`, types referencing parameters introduced by the `Binder` do not make any sense outside of that binder, for example: +Much like [`EarlyBinder`], when accessing the inside of a [`Binder`] we must first discharge it by replacing the bound vars with some other value. This is for much the same reason as with `EarlyBinder`, types referencing parameters introduced by the `Binder` do not make any sense outside of that binder. See the following erroring example: ```rust,ignore fn foo<'a>(a: &'a u32) -> &'a u32 { a @@ -11,10 +11,11 @@ fn bar(a: fn(&u32) -> T) -> T { fn main() { let higher_ranked_fn_ptr = foo as for<'a> fn(&'a u32) -> &'a u32; + // Attempt to infer `T=for<'a> &'a u32` which is not satsifiable let references_bound_vars = bar(higher_ranked_fn_ptr); } ``` -In this example we are providing an argument of type `for<'a> fn(&'^0 u32) -> &'^0 u32` to `bar`, we do not want to allow `T` to be inferred to the type `&'^0 u32` as it would be rather nonsensical (and likely unsound if we did not happen to ICE, `main` has no idea what `'a` is so how would the borrow checker handle a borrow with lifetime `'a`). +In this example we are providing an argument of type `for<'a> fn(&'^0 u32) -> &'^0 u32` to `bar`, we do not want to allow `T` to be inferred to the type `&'^0 u32` as it would be rather nonsensical (and likely unsound if we did not happen to ICE). `main` doesn't know about `'a` so the borrow checker would not be able to handle a borrow with lifetime `'a`. Unlike `EarlyBinder` we typically do not instantiate `Binder` with some concrete set of arguments from the user, i.e. `['b, 'static]` as arguments to a `for<'a1, 'a2> fn(&'a1 u32, &'a2 u32)`. Instead we usually instantiate the binder with inference variables or placeholders. diff --git a/src/doc/rustc-dev-guide/triagebot.toml b/src/doc/rustc-dev-guide/triagebot.toml index 4a88523915209..fbfe742341480 100644 --- a/src/doc/rustc-dev-guide/triagebot.toml +++ b/src/doc/rustc-dev-guide/triagebot.toml @@ -53,10 +53,6 @@ allow-unauthenticated = [ # Documentation at: https://forge.rust-lang.org/triagebot/note.html [note] -# Prevents mentions in commits to avoid users being spammed -# Documentation at: https://forge.rust-lang.org/triagebot/no-mentions.html -[no-mentions] - # Canonicalize issue numbers to avoid closing the wrong issue # when commits are included in subtrees, as well as warning links in commits. # Documentation at: https://forge.rust-lang.org/triagebot/issue-links.html diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index e5a4593260a42..3d4b4e969157c 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -404,15 +404,9 @@ impl Options { let unstable_features = rustc_feature::UnstableFeatures::from_environment(crate_name.as_deref()); let config::JsonConfig { json_rendered, json_unused_externs, json_color, .. } = - config::parse_json(early_dcx, matches, unstable_features.is_nightly_build()); - let error_format = config::parse_error_format( - early_dcx, - matches, - color, - json_color, - json_rendered, - unstable_features.is_nightly_build(), - ); + config::parse_json(early_dcx, matches); + let error_format = + config::parse_error_format(early_dcx, matches, color, json_color, json_rendered); let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_default(); let mut target_modifiers = BTreeMap::::new(); diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 6e70f5b41c426..fb20889632840 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -7,9 +7,7 @@ use rustc_driver::USING_INTERNAL_FEATURES; use rustc_errors::TerminalUrl; use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitter; use rustc_errors::codes::*; -use rustc_errors::emitter::{ - DynEmitter, HumanEmitter, HumanReadableErrorType, OutputTheme, stderr_destination, -}; +use rustc_errors::emitter::{DynEmitter, HumanReadableErrorType, OutputTheme, stderr_destination}; use rustc_errors::json::JsonEmitter; use rustc_feature::UnstableFeatures; use rustc_hir::def::Res; @@ -162,7 +160,7 @@ pub(crate) fn new_dcx( let translator = rustc_driver::default_translator(); let emitter: Box = match error_format { ErrorOutputType::HumanReadable { kind, color_config } => match kind { - HumanReadableErrorType::AnnotateSnippet { short, unicode } => Box::new( + HumanReadableErrorType { short, unicode } => Box::new( AnnotateSnippetEmitter::new(stderr_destination(color_config), translator) .sm(source_map.map(|sm| sm as _)) .short_message(short) @@ -171,15 +169,6 @@ pub(crate) fn new_dcx( .theme(if unicode { OutputTheme::Unicode } else { OutputTheme::Ascii }) .ui_testing(unstable_opts.ui_testing), ), - HumanReadableErrorType::Default { short } => Box::new( - HumanEmitter::new(stderr_destination(color_config), translator) - .sm(source_map.map(|sm| sm as _)) - .short_message(short) - .diagnostic_width(diagnostic_width) - .track_diagnostics(unstable_opts.track_diagnostics) - .theme(OutputTheme::Ascii) - .ui_testing(unstable_opts.ui_testing), - ), }, ErrorOutputType::Json { pretty, json_rendered, color_config } => { let source_map = source_map.unwrap_or_else(|| { diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 85fecb87533db..25868e24ce164 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -625,7 +625,7 @@ fn run_test( ]); if let ErrorOutputType::HumanReadable { kind, color_config } = rustdoc_options.error_format { let short = kind.short(); - let unicode = kind == HumanReadableErrorType::AnnotateSnippet { unicode: true, short }; + let unicode = kind == HumanReadableErrorType { unicode: true, short }; if short { compiler_args.extend_from_slice(&["--error-format".to_owned(), "short".to_owned()]); diff --git a/src/tools/clippy/tests/ui/unit_arg.stderr b/src/tools/clippy/tests/ui/unit_arg.stderr index 0dcfb02b9fa08..eb7c56c45b595 100644 --- a/src/tools/clippy/tests/ui/unit_arg.stderr +++ b/src/tools/clippy/tests/ui/unit_arg.stderr @@ -204,21 +204,18 @@ error: passing a unit value to a function | LL | fn_take_unit(mac!(def)); | ^^^^^^^^^^^^^^^^^^^^^^^ - | error: passing a unit value to a function --> tests/ui/unit_arg.rs:173:5 | LL | fn_take_unit(mac!(func Default::default)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | error: passing a unit value to a function --> tests/ui/unit_arg.rs:175:5 | LL | fn_take_unit(mac!(nonempty_block Default::default())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | error: aborting due to 13 previous errors diff --git a/tests/ui/README.md b/tests/ui/README.md index 25e870fd8f188..ca9f89f002ee4 100644 --- a/tests/ui/README.md +++ b/tests/ui/README.md @@ -256,6 +256,10 @@ Some traits' implementation must be compared with their definition, checking for This subdirectory is *not* intended comparison traits (`PartialEq`, `Eq`, `PartialOrd`, `Ord`). +## `tests/ui/compile-flags/` + +Tests for compile flags. + ## `tests/ui/compiletest-self-test/`: compiletest "meta" tests Meta test suite of the test harness `compiletest` itself. @@ -548,6 +552,8 @@ A broad directory for tests on expressions. Tests on the `extern` keyword and `extern` blocks and functions. +**FIXME**: Merge with `tests/ui/abi/extern`. + ## `tests/ui/extern-flag/`: `--extern` command line flag Tests for the `--extern` CLI flag. @@ -556,6 +562,12 @@ Tests for the `--extern` CLI flag. Tests on feature-gating, and the `#![feature(..)]` mechanism itself. +## `tests/ui/ffi/`: Foreign Function Interface + +Tests for the `std::ffi` module. + +See [`std::ffi`](https://doc.rust-lang.org/std/ffi/index.html) + ## `tests/ui/ffi-attrs/`: `#![feature(ffi_const, ffi_pure)]` The `#[ffi_const]` and `#[ffi_pure]` attributes applies clang's `const` and `pure` attributes to foreign functions declarations, respectively. These attributes are the core element of the tests in this category. @@ -733,15 +745,9 @@ Various tests related to rejecting invalid inputs. **FIXME**: This is rather uninformative, possibly rehome into more meaningful directories. -## `tests/ui/invalid-compile-flags/` - -Tests for checking that invalid usage of compiler flags are rejected. - -## `tests/ui/io-checks/` - -Contains a single test. The test tries to output a file into an invalid directory with `-o`, then checks that the result is an error, not an internal compiler error. +## `tests/ui/io-checks/`: Input Output -**FIXME**: Rehome to invalid compiler flags maybe. +Tests for I/O related behaviour, covering stdout/stderr handling and error propagation. ## `tests/ui/issues/`: Tests directly related to GitHub issues diff --git a/tests/ui/annotate-snippet/missing-type.rs b/tests/ui/annotate-snippet/missing-type.rs index 54088def3eeaf..2d06c13b96ab8 100644 --- a/tests/ui/annotate-snippet/missing-type.rs +++ b/tests/ui/annotate-snippet/missing-type.rs @@ -1,5 +1,5 @@ //@ edition: 2015 -//@ compile-flags: --error-format human-annotate-rs -Z unstable-options +//@ compile-flags: --error-format human pub fn main() { let x: Iter; diff --git a/tests/ui/annotate-snippet/multiple-files.rs b/tests/ui/annotate-snippet/multiple-files.rs index c67a31d8f0714..060e817bea08a 100644 --- a/tests/ui/annotate-snippet/multiple-files.rs +++ b/tests/ui/annotate-snippet/multiple-files.rs @@ -1,5 +1,5 @@ //@ aux-build:other_file.rs -//@ compile-flags: --error-format human-annotate-rs -Z unstable-options +//@ compile-flags: --error-format human extern crate other_file; diff --git a/tests/ui/annotate-snippet/multispan.rs b/tests/ui/annotate-snippet/multispan.rs index c2054f62d24c5..adbbef6d42f75 100644 --- a/tests/ui/annotate-snippet/multispan.rs +++ b/tests/ui/annotate-snippet/multispan.rs @@ -1,5 +1,5 @@ //@ proc-macro: multispan.rs -//@ compile-flags: --error-format human-annotate-rs -Z unstable-options +//@ compile-flags: --error-format human #![feature(proc_macro_hygiene)] diff --git a/tests/ui/any/try_as_dyn.rs b/tests/ui/any/try_as_dyn.rs new file mode 100644 index 0000000000000..ee220f797ced9 --- /dev/null +++ b/tests/ui/any/try_as_dyn.rs @@ -0,0 +1,29 @@ +//@ run-pass +#![feature(try_as_dyn)] + +use std::fmt::Debug; + +// Look ma, no `T: Debug` +fn debug_format_with_try_as_dyn(t: &T) -> String { + match std::any::try_as_dyn::<_, dyn Debug>(t) { + Some(d) => format!("{d:?}"), + None => "default".to_string() + } +} + +// Test that downcasting to a dyn trait works as expected +fn main() { + #[allow(dead_code)] + #[derive(Debug)] + struct A { + index: usize + } + let a = A { index: 42 }; + let result = debug_format_with_try_as_dyn(&a); + assert_eq!("A { index: 42 }", result); + + struct B {} + let b = B {}; + let result = debug_format_with_try_as_dyn(&b); + assert_eq!("default", result); +} diff --git a/tests/ui/any/try_as_dyn_mut.rs b/tests/ui/any/try_as_dyn_mut.rs new file mode 100644 index 0000000000000..ff7baa32ea874 --- /dev/null +++ b/tests/ui/any/try_as_dyn_mut.rs @@ -0,0 +1,20 @@ +//@ run-pass +#![feature(try_as_dyn)] + +use std::fmt::{Error, Write}; + +// Look ma, no `T: Write` +fn try_as_dyn_mut_write(t: &mut T, s: &str) -> Result<(), Error> { + match std::any::try_as_dyn_mut::<_, dyn Write>(t) { + Some(w) => w.write_str(s), + None => Ok(()) + } +} + +// Test that downcasting to a mut dyn trait works as expected +fn main() { + let mut buf = "Hello".to_string(); + + try_as_dyn_mut_write(&mut buf, " world!").unwrap(); + assert_eq!(buf, "Hello world!"); +} diff --git a/tests/ui/any/try_as_dyn_soundness_test1.rs b/tests/ui/any/try_as_dyn_soundness_test1.rs new file mode 100644 index 0000000000000..0772e9a2d77ee --- /dev/null +++ b/tests/ui/any/try_as_dyn_soundness_test1.rs @@ -0,0 +1,22 @@ +//@ run-pass +#![feature(try_as_dyn)] + +use std::any::try_as_dyn; + +trait Trait { + +} + +impl Trait for for<'a> fn(&'a Box) { + +} + +fn store(_: &'static Box) { + +} + +fn main() { + let fn_ptr: fn(&'static Box) = store; + let dt = try_as_dyn::<_, dyn Trait>(&fn_ptr); + assert!(dt.is_none()); +} diff --git a/tests/ui/any/try_as_dyn_soundness_test2.rs b/tests/ui/any/try_as_dyn_soundness_test2.rs new file mode 100644 index 0000000000000..c16b50d0261ed --- /dev/null +++ b/tests/ui/any/try_as_dyn_soundness_test2.rs @@ -0,0 +1,16 @@ +//@ run-pass +#![feature(try_as_dyn)] +use std::any::try_as_dyn; + +trait Trait { + +} + +impl Trait fn(&'a Box)> for () { + +} + +fn main() { + let dt = try_as_dyn::<_, dyn Trait)>>(&()); + assert!(dt.is_none()); +} diff --git a/tests/ui/attributes/crate-type-delimited.stderr b/tests/ui/attributes/crate-type-delimited.stderr index 23234efe169f1..e9616f27174c8 100644 --- a/tests/ui/attributes/crate-type-delimited.stderr +++ b/tests/ui/attributes/crate-type-delimited.stderr @@ -5,7 +5,6 @@ LL | #![crate_type(lib)] | ^^^^^^^^^^^^^^^^^^^ | = note: for more information, visit - | error: aborting due to 1 previous error diff --git a/tests/ui/attributes/crate-type-empty.stderr b/tests/ui/attributes/crate-type-empty.stderr index c1d474d9f17ff..b8eca61748ead 100644 --- a/tests/ui/attributes/crate-type-empty.stderr +++ b/tests/ui/attributes/crate-type-empty.stderr @@ -5,7 +5,6 @@ LL | #![crate_type] | ^^^^^^^^^^^^^^ | = note: for more information, visit - | error: aborting due to 1 previous error diff --git a/tests/ui/attributes/crate-type-macro-call.stderr b/tests/ui/attributes/crate-type-macro-call.stderr index cd17b324041bd..b3927fef47183 100644 --- a/tests/ui/attributes/crate-type-macro-call.stderr +++ b/tests/ui/attributes/crate-type-macro-call.stderr @@ -5,7 +5,6 @@ LL | #![crate_type = foo!()] | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: for more information, visit - | error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-46472.rs b/tests/ui/borrowck/return-ref-to-temporary.rs similarity index 55% rename from tests/ui/issues/issue-46472.rs rename to tests/ui/borrowck/return-ref-to-temporary.rs index b9e20e8dbcb5f..90609b8d6da6d 100644 --- a/tests/ui/issues/issue-46472.rs +++ b/tests/ui/borrowck/return-ref-to-temporary.rs @@ -1,6 +1,7 @@ +//! regression test for issue https://github.com/rust-lang/rust/issues/46472 fn bar<'a>() -> &'a mut u32 { &mut 4 //~^ ERROR cannot return reference to temporary value [E0515] } -fn main() { } +fn main() {} diff --git a/tests/ui/issues/issue-46472.stderr b/tests/ui/borrowck/return-ref-to-temporary.stderr similarity index 88% rename from tests/ui/issues/issue-46472.stderr rename to tests/ui/borrowck/return-ref-to-temporary.stderr index 6115da28cc91c..85faf0a9e3758 100644 --- a/tests/ui/issues/issue-46472.stderr +++ b/tests/ui/borrowck/return-ref-to-temporary.stderr @@ -1,5 +1,5 @@ error[E0515]: cannot return reference to temporary value - --> $DIR/issue-46472.rs:2:5 + --> $DIR/return-ref-to-temporary.rs:3:5 | LL | &mut 4 | ^^^^^- diff --git a/tests/ui/issues/issue-19499.rs b/tests/ui/closures/closure-upvar-trait-caching.rs similarity index 85% rename from tests/ui/issues/issue-19499.rs rename to tests/ui/closures/closure-upvar-trait-caching.rs index d2a6862e05c4f..82588631c99c3 100644 --- a/tests/ui/issues/issue-19499.rs +++ b/tests/ui/closures/closure-upvar-trait-caching.rs @@ -7,8 +7,9 @@ // reasonable examples) let to ambiguity errors about not being able // to infer sufficient type information. - fn main() { let n = 0; - let it = Some(1_usize).into_iter().inspect(|_| {n;}); + let it = Some(1_usize).into_iter().inspect(|_| { + n; + }); } diff --git a/tests/ui/closures/nested-closure-call.rs b/tests/ui/closures/nested-closure-call.rs new file mode 100644 index 0000000000000..9d0860167a1ac --- /dev/null +++ b/tests/ui/closures/nested-closure-call.rs @@ -0,0 +1,5 @@ +//! regression test for https://github.com/rust-lang/rust/issues/24779 +//@ run-pass +fn main() { + assert_eq!((|| || 42)()(), 42); +} diff --git a/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGS.stderr b/tests/ui/compile-flags/invalid/branch-protection-missing-pac-ret.BADFLAGS.stderr similarity index 100% rename from tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGS.stderr rename to tests/ui/compile-flags/invalid/branch-protection-missing-pac-ret.BADFLAGS.stderr diff --git a/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGSPC.stderr b/tests/ui/compile-flags/invalid/branch-protection-missing-pac-ret.BADFLAGSPC.stderr similarity index 100% rename from tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGSPC.stderr rename to tests/ui/compile-flags/invalid/branch-protection-missing-pac-ret.BADFLAGSPC.stderr diff --git a/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADTARGET.stderr b/tests/ui/compile-flags/invalid/branch-protection-missing-pac-ret.BADTARGET.stderr similarity index 100% rename from tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADTARGET.stderr rename to tests/ui/compile-flags/invalid/branch-protection-missing-pac-ret.BADTARGET.stderr diff --git a/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.rs b/tests/ui/compile-flags/invalid/branch-protection-missing-pac-ret.rs similarity index 100% rename from tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.rs rename to tests/ui/compile-flags/invalid/branch-protection-missing-pac-ret.rs diff --git a/tests/ui/invalid-compile-flags/codegen-option-without-group.rs b/tests/ui/compile-flags/invalid/codegen-option-without-group.rs similarity index 100% rename from tests/ui/invalid-compile-flags/codegen-option-without-group.rs rename to tests/ui/compile-flags/invalid/codegen-option-without-group.rs diff --git a/tests/ui/invalid-compile-flags/codegen-option-without-group.stderr b/tests/ui/compile-flags/invalid/codegen-option-without-group.stderr similarity index 100% rename from tests/ui/invalid-compile-flags/codegen-option-without-group.stderr rename to tests/ui/compile-flags/invalid/codegen-option-without-group.stderr diff --git a/tests/ui/invalid-compile-flags/crate-type-flag.empty_crate_type.stderr b/tests/ui/compile-flags/invalid/crate-type-flag.empty_crate_type.stderr similarity index 100% rename from tests/ui/invalid-compile-flags/crate-type-flag.empty_crate_type.stderr rename to tests/ui/compile-flags/invalid/crate-type-flag.empty_crate_type.stderr diff --git a/tests/ui/invalid-compile-flags/crate-type-flag.proc_underscore_macro.stderr b/tests/ui/compile-flags/invalid/crate-type-flag.proc_underscore_macro.stderr similarity index 100% rename from tests/ui/invalid-compile-flags/crate-type-flag.proc_underscore_macro.stderr rename to tests/ui/compile-flags/invalid/crate-type-flag.proc_underscore_macro.stderr diff --git a/tests/ui/invalid-compile-flags/crate-type-flag.rs b/tests/ui/compile-flags/invalid/crate-type-flag.rs similarity index 100% rename from tests/ui/invalid-compile-flags/crate-type-flag.rs rename to tests/ui/compile-flags/invalid/crate-type-flag.rs diff --git a/tests/ui/invalid-compile-flags/crate-type-flag.unknown.stderr b/tests/ui/compile-flags/invalid/crate-type-flag.unknown.stderr similarity index 100% rename from tests/ui/invalid-compile-flags/crate-type-flag.unknown.stderr rename to tests/ui/compile-flags/invalid/crate-type-flag.unknown.stderr diff --git a/tests/ui/invalid-compile-flags/debug-option-without-group.rs b/tests/ui/compile-flags/invalid/debug-option-without-group.rs similarity index 100% rename from tests/ui/invalid-compile-flags/debug-option-without-group.rs rename to tests/ui/compile-flags/invalid/debug-option-without-group.rs diff --git a/tests/ui/invalid-compile-flags/debug-option-without-group.stderr b/tests/ui/compile-flags/invalid/debug-option-without-group.stderr similarity index 100% rename from tests/ui/invalid-compile-flags/debug-option-without-group.stderr rename to tests/ui/compile-flags/invalid/debug-option-without-group.stderr diff --git a/tests/ui/invalid-compile-flags/emit-output-types-without-args.rs b/tests/ui/compile-flags/invalid/emit-output-types-without-args.rs similarity index 100% rename from tests/ui/invalid-compile-flags/emit-output-types-without-args.rs rename to tests/ui/compile-flags/invalid/emit-output-types-without-args.rs diff --git a/tests/ui/invalid-compile-flags/emit-output-types-without-args.stderr b/tests/ui/compile-flags/invalid/emit-output-types-without-args.stderr similarity index 100% rename from tests/ui/invalid-compile-flags/emit-output-types-without-args.stderr rename to tests/ui/compile-flags/invalid/emit-output-types-without-args.stderr diff --git a/tests/ui/invalid-compile-flags/function-return/requires-x86-or-x86_64.aarch64.stderr b/tests/ui/compile-flags/invalid/function-return/requires-x86-or-x86_64.aarch64.stderr similarity index 100% rename from tests/ui/invalid-compile-flags/function-return/requires-x86-or-x86_64.aarch64.stderr rename to tests/ui/compile-flags/invalid/function-return/requires-x86-or-x86_64.aarch64.stderr diff --git a/tests/ui/invalid-compile-flags/function-return/requires-x86-or-x86_64.rs b/tests/ui/compile-flags/invalid/function-return/requires-x86-or-x86_64.rs similarity index 100% rename from tests/ui/invalid-compile-flags/function-return/requires-x86-or-x86_64.rs rename to tests/ui/compile-flags/invalid/function-return/requires-x86-or-x86_64.rs diff --git a/tests/ui/invalid-compile-flags/function-return/thunk-extern-requires-non-large-code-model.large.stderr b/tests/ui/compile-flags/invalid/function-return/thunk-extern-requires-non-large-code-model.large.stderr similarity index 100% rename from tests/ui/invalid-compile-flags/function-return/thunk-extern-requires-non-large-code-model.large.stderr rename to tests/ui/compile-flags/invalid/function-return/thunk-extern-requires-non-large-code-model.large.stderr diff --git a/tests/ui/invalid-compile-flags/function-return/thunk-extern-requires-non-large-code-model.rs b/tests/ui/compile-flags/invalid/function-return/thunk-extern-requires-non-large-code-model.rs similarity index 100% rename from tests/ui/invalid-compile-flags/function-return/thunk-extern-requires-non-large-code-model.rs rename to tests/ui/compile-flags/invalid/function-return/thunk-extern-requires-non-large-code-model.rs diff --git a/tests/ui/invalid-compile-flags/indirect-branch-cs-prefix/requires-x86-or-x86_64.aarch64.stderr b/tests/ui/compile-flags/invalid/indirect-branch-cs-prefix/requires-x86-or-x86_64.aarch64.stderr similarity index 100% rename from tests/ui/invalid-compile-flags/indirect-branch-cs-prefix/requires-x86-or-x86_64.aarch64.stderr rename to tests/ui/compile-flags/invalid/indirect-branch-cs-prefix/requires-x86-or-x86_64.aarch64.stderr diff --git a/tests/ui/invalid-compile-flags/indirect-branch-cs-prefix/requires-x86-or-x86_64.rs b/tests/ui/compile-flags/invalid/indirect-branch-cs-prefix/requires-x86-or-x86_64.rs similarity index 100% rename from tests/ui/invalid-compile-flags/indirect-branch-cs-prefix/requires-x86-or-x86_64.rs rename to tests/ui/compile-flags/invalid/indirect-branch-cs-prefix/requires-x86-or-x86_64.rs diff --git a/tests/ui/invalid-compile-flags/invalid-llvm-passes.rs b/tests/ui/compile-flags/invalid/invalid-llvm-passes.rs similarity index 100% rename from tests/ui/invalid-compile-flags/invalid-llvm-passes.rs rename to tests/ui/compile-flags/invalid/invalid-llvm-passes.rs diff --git a/tests/ui/invalid-compile-flags/invalid-llvm-passes.stderr b/tests/ui/compile-flags/invalid/invalid-llvm-passes.stderr similarity index 100% rename from tests/ui/invalid-compile-flags/invalid-llvm-passes.stderr rename to tests/ui/compile-flags/invalid/invalid-llvm-passes.stderr diff --git a/tests/ui/invalid-compile-flags/need-crate-arg-ignore-tidy$x.rs b/tests/ui/compile-flags/invalid/need-crate-arg-ignore-tidy$x.rs similarity index 100% rename from tests/ui/invalid-compile-flags/need-crate-arg-ignore-tidy$x.rs rename to tests/ui/compile-flags/invalid/need-crate-arg-ignore-tidy$x.rs diff --git a/tests/ui/invalid-compile-flags/need-crate-arg-ignore-tidy$x.stderr b/tests/ui/compile-flags/invalid/need-crate-arg-ignore-tidy$x.stderr similarity index 100% rename from tests/ui/invalid-compile-flags/need-crate-arg-ignore-tidy$x.stderr rename to tests/ui/compile-flags/invalid/need-crate-arg-ignore-tidy$x.stderr diff --git a/tests/ui/invalid-compile-flags/print-crate-name-request-malformed-crate-name.rs b/tests/ui/compile-flags/invalid/print-crate-name-request-malformed-crate-name.rs similarity index 100% rename from tests/ui/invalid-compile-flags/print-crate-name-request-malformed-crate-name.rs rename to tests/ui/compile-flags/invalid/print-crate-name-request-malformed-crate-name.rs diff --git a/tests/ui/invalid-compile-flags/print-crate-name-request-malformed-crate-name.stderr b/tests/ui/compile-flags/invalid/print-crate-name-request-malformed-crate-name.stderr similarity index 100% rename from tests/ui/invalid-compile-flags/print-crate-name-request-malformed-crate-name.stderr rename to tests/ui/compile-flags/invalid/print-crate-name-request-malformed-crate-name.stderr diff --git a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-1.rs b/tests/ui/compile-flags/invalid/print-file-names-request-malformed-crate-name-1.rs similarity index 100% rename from tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-1.rs rename to tests/ui/compile-flags/invalid/print-file-names-request-malformed-crate-name-1.rs diff --git a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-1.stderr b/tests/ui/compile-flags/invalid/print-file-names-request-malformed-crate-name-1.stderr similarity index 100% rename from tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-1.stderr rename to tests/ui/compile-flags/invalid/print-file-names-request-malformed-crate-name-1.stderr diff --git a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-2.rs b/tests/ui/compile-flags/invalid/print-file-names-request-malformed-crate-name-2.rs similarity index 100% rename from tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-2.rs rename to tests/ui/compile-flags/invalid/print-file-names-request-malformed-crate-name-2.rs diff --git a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-2.stderr b/tests/ui/compile-flags/invalid/print-file-names-request-malformed-crate-name-2.stderr similarity index 100% rename from tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-2.stderr rename to tests/ui/compile-flags/invalid/print-file-names-request-malformed-crate-name-2.stderr diff --git a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name.rs b/tests/ui/compile-flags/invalid/print-file-names-request-malformed-crate-name.rs similarity index 100% rename from tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name.rs rename to tests/ui/compile-flags/invalid/print-file-names-request-malformed-crate-name.rs diff --git a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name.stderr b/tests/ui/compile-flags/invalid/print-file-names-request-malformed-crate-name.stderr similarity index 100% rename from tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name.stderr rename to tests/ui/compile-flags/invalid/print-file-names-request-malformed-crate-name.stderr diff --git a/tests/ui/invalid-compile-flags/print-without-arg.rs b/tests/ui/compile-flags/invalid/print-without-arg.rs similarity index 100% rename from tests/ui/invalid-compile-flags/print-without-arg.rs rename to tests/ui/compile-flags/invalid/print-without-arg.rs diff --git a/tests/ui/invalid-compile-flags/print-without-arg.stderr b/tests/ui/compile-flags/invalid/print-without-arg.stderr similarity index 100% rename from tests/ui/invalid-compile-flags/print-without-arg.stderr rename to tests/ui/compile-flags/invalid/print-without-arg.stderr diff --git a/tests/ui/invalid-compile-flags/print.rs b/tests/ui/compile-flags/invalid/print.rs similarity index 100% rename from tests/ui/invalid-compile-flags/print.rs rename to tests/ui/compile-flags/invalid/print.rs diff --git a/tests/ui/invalid-compile-flags/print.stderr b/tests/ui/compile-flags/invalid/print.stderr similarity index 100% rename from tests/ui/invalid-compile-flags/print.stderr rename to tests/ui/compile-flags/invalid/print.stderr diff --git a/tests/ui/invalid-compile-flags/reg-struct-return/requires-x86.aarch64.stderr b/tests/ui/compile-flags/invalid/reg-struct-return/requires-x86.aarch64.stderr similarity index 100% rename from tests/ui/invalid-compile-flags/reg-struct-return/requires-x86.aarch64.stderr rename to tests/ui/compile-flags/invalid/reg-struct-return/requires-x86.aarch64.stderr diff --git a/tests/ui/invalid-compile-flags/reg-struct-return/requires-x86.rs b/tests/ui/compile-flags/invalid/reg-struct-return/requires-x86.rs similarity index 100% rename from tests/ui/invalid-compile-flags/reg-struct-return/requires-x86.rs rename to tests/ui/compile-flags/invalid/reg-struct-return/requires-x86.rs diff --git a/tests/ui/invalid-compile-flags/reg-struct-return/requires-x86.x86_64.stderr b/tests/ui/compile-flags/invalid/reg-struct-return/requires-x86.x86_64.stderr similarity index 100% rename from tests/ui/invalid-compile-flags/reg-struct-return/requires-x86.x86_64.stderr rename to tests/ui/compile-flags/invalid/reg-struct-return/requires-x86.x86_64.stderr diff --git a/tests/ui/invalid-compile-flags/regparm/regparm-valid-values.regparm4.stderr b/tests/ui/compile-flags/invalid/regparm/regparm-valid-values.regparm4.stderr similarity index 100% rename from tests/ui/invalid-compile-flags/regparm/regparm-valid-values.regparm4.stderr rename to tests/ui/compile-flags/invalid/regparm/regparm-valid-values.regparm4.stderr diff --git a/tests/ui/invalid-compile-flags/regparm/regparm-valid-values.rs b/tests/ui/compile-flags/invalid/regparm/regparm-valid-values.rs similarity index 100% rename from tests/ui/invalid-compile-flags/regparm/regparm-valid-values.rs rename to tests/ui/compile-flags/invalid/regparm/regparm-valid-values.rs diff --git a/tests/ui/invalid-compile-flags/regparm/requires-x86.aarch64.stderr b/tests/ui/compile-flags/invalid/regparm/requires-x86.aarch64.stderr similarity index 100% rename from tests/ui/invalid-compile-flags/regparm/requires-x86.aarch64.stderr rename to tests/ui/compile-flags/invalid/regparm/requires-x86.aarch64.stderr diff --git a/tests/ui/invalid-compile-flags/regparm/requires-x86.rs b/tests/ui/compile-flags/invalid/regparm/requires-x86.rs similarity index 100% rename from tests/ui/invalid-compile-flags/regparm/requires-x86.rs rename to tests/ui/compile-flags/invalid/regparm/requires-x86.rs diff --git a/tests/ui/invalid-compile-flags/regparm/requires-x86.x86_64.stderr b/tests/ui/compile-flags/invalid/regparm/requires-x86.x86_64.stderr similarity index 100% rename from tests/ui/invalid-compile-flags/regparm/requires-x86.x86_64.stderr rename to tests/ui/compile-flags/invalid/regparm/requires-x86.x86_64.stderr diff --git a/tests/ui/issues/issue-24945-repeat-dash-opts.rs b/tests/ui/compile-flags/run-pass/repeated-debug-opt-flags.rs similarity index 72% rename from tests/ui/issues/issue-24945-repeat-dash-opts.rs rename to tests/ui/compile-flags/run-pass/repeated-debug-opt-flags.rs index 5d8044b0a1a06..d584ec9fd280d 100644 --- a/tests/ui/issues/issue-24945-repeat-dash-opts.rs +++ b/tests/ui/compile-flags/run-pass/repeated-debug-opt-flags.rs @@ -1,3 +1,4 @@ +//! regression test for https://github.com/rust-lang/rust/issues/24945 //@ run-pass // This test is just checking that we continue to accept `-g -g -O -O` // as options to the compiler. diff --git a/tests/ui/const-generics/generic_const_exprs/issue-105608.stderr b/tests/ui/const-generics/generic_const_exprs/issue-105608.stderr index 1c97eaddfe1bb..cc35035edf95d 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-105608.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-105608.stderr @@ -3,7 +3,6 @@ error[E0282]: type annotations needed | LL | Combination::<0>.and::<_>().and::<_>(); | ^^^ cannot infer type of the type parameter `M` declared on the method `and` - | error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts.rs b/tests/ui/const-generics/mgca/explicit_anon_consts.rs index 4592827762660..31391b023bfe3 100644 --- a/tests/ui/const-generics/mgca/explicit_anon_consts.rs +++ b/tests/ui/const-generics/mgca/explicit_anon_consts.rs @@ -1,5 +1,8 @@ #![feature(associated_const_equality, generic_const_items, min_generic_const_args)] #![expect(incomplete_features)] +// library crates exercise weirder code paths around +// DefIds which were created for const args. +#![crate_type = "lib"] struct Foo; @@ -66,5 +69,3 @@ struct Default3; struct Default4; //~^ ERROR: complex const arguments must be placed inside of a `const` block struct Default5; - -fn main() {} diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts.stderr b/tests/ui/const-generics/mgca/explicit_anon_consts.stderr index e4bf49c71efed..b3d960e315eac 100644 --- a/tests/ui/const-generics/mgca/explicit_anon_consts.stderr +++ b/tests/ui/const-generics/mgca/explicit_anon_consts.stderr @@ -1,5 +1,5 @@ error: generic parameters may not be used in const operations - --> $DIR/explicit_anon_consts.rs:8:41 + --> $DIR/explicit_anon_consts.rs:11:41 | LL | type Adt3 = Foo; | ^ cannot perform const operation using `N` @@ -8,7 +8,7 @@ LL | type Adt3 = Foo; = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/explicit_anon_consts.rs:16:42 + --> $DIR/explicit_anon_consts.rs:19:42 | LL | type Arr3 = [(); const { N }]; | ^ cannot perform const operation using `N` @@ -17,7 +17,7 @@ LL | type Arr3 = [(); const { N }]; = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/explicit_anon_consts.rs:25:27 + --> $DIR/explicit_anon_consts.rs:28:27 | LL | let _3 = [(); const { N }]; | ^ cannot perform const operation using `N` @@ -26,7 +26,7 @@ LL | let _3 = [(); const { N }]; = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/explicit_anon_consts.rs:37:46 + --> $DIR/explicit_anon_consts.rs:40:46 | LL | const ITEM3: usize = const { N }; | ^ cannot perform const operation using `N` @@ -35,7 +35,7 @@ LL | const ITEM3: usize = const { N }; = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/explicit_anon_consts.rs:55:31 + --> $DIR/explicit_anon_consts.rs:58:31 | LL | T3: Trait, | ^ cannot perform const operation using `N` @@ -44,7 +44,7 @@ LL | T3: Trait, = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/explicit_anon_consts.rs:64:58 + --> $DIR/explicit_anon_consts.rs:67:58 | LL | struct Default3; | ^ cannot perform const operation using `N` @@ -53,37 +53,37 @@ LL | struct Default3; = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts.rs:10:33 + --> $DIR/explicit_anon_consts.rs:13:33 | LL | type Adt4 = Foo<{ 1 + 1 }>; | ^^^^^^^^^ error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts.rs:18:34 + --> $DIR/explicit_anon_consts.rs:21:34 | LL | type Arr4 = [(); 1 + 1]; | ^^^^^ error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts.rs:27:19 + --> $DIR/explicit_anon_consts.rs:30:19 | LL | let _4 = [(); 1 + 1]; | ^^^^^ error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts.rs:40:38 + --> $DIR/explicit_anon_consts.rs:43:38 | LL | const ITEM4: usize = { 1 + 1 }; | ^^^^^^^^^ error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts.rs:57:23 + --> $DIR/explicit_anon_consts.rs:60:23 | LL | T4: Trait, | ^^^^^^^^^ error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts.rs:66:50 + --> $DIR/explicit_anon_consts.rs:69:50 | LL | struct Default4; | ^^^^^^^^^ diff --git a/tests/ui/const-generics/mgca/unused_speculative_def_id.rs b/tests/ui/const-generics/mgca/unused_speculative_def_id.rs new file mode 100644 index 0000000000000..e617daba24b68 --- /dev/null +++ b/tests/ui/const-generics/mgca/unused_speculative_def_id.rs @@ -0,0 +1,24 @@ +#![feature(min_generic_const_args, generic_const_exprs, generic_const_items)] +#![expect(incomplete_features)] + +// Previously we would create a `DefId` to represent the const argument to `A` +// except it would go unused as it's a MGCA path const arg. We would also make +// a `DefId` for the `const { 1 }` anon const arg to `ERR` which would wind up +// with a `DefId` parent of the speculatively created `DefId` for the argument to +// `A`. +// +// This then caused Problems:tm: in the rest of the compiler that did not expect +// to encounter such nonsensical `DefId`s. +// +// The `ERR` path must fail to resolve as if it can be resolved then broken GCE +// logic will attempt to evaluate the constant directly which is wrong for +// `type_const`s which do not have bodies. + +struct A; + +struct Foo { + field: A<{ ERR:: }>, + //~^ ERROR: cannot find value `ERR` in this scope +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/unused_speculative_def_id.stderr b/tests/ui/const-generics/mgca/unused_speculative_def_id.stderr new file mode 100644 index 0000000000000..e087e046ec35d --- /dev/null +++ b/tests/ui/const-generics/mgca/unused_speculative_def_id.stderr @@ -0,0 +1,18 @@ +error[E0425]: cannot find value `ERR` in this scope + --> $DIR/unused_speculative_def_id.rs:20:16 + | +LL | field: A<{ ERR:: }>, + | ^^^ + | + --> $SRC_DIR/core/src/result.rs:LL:COL + | + = note: similarly named tuple variant `Err` defined here +help: a tuple variant with a similar name exists + | +LL - field: A<{ ERR:: }>, +LL + field: A<{ Err:: }>, + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/delegation/ice-line-bounds-issue-148732.stderr b/tests/ui/delegation/ice-line-bounds-issue-148732.stderr index 1f43ec335448b..f332bc6a7a210 100644 --- a/tests/ui/delegation/ice-line-bounds-issue-148732.stderr +++ b/tests/ui/delegation/ice-line-bounds-issue-148732.stderr @@ -5,7 +5,6 @@ LL | dbg!(b); | ^^^^^^^ expected named lifetime parameter | = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) - | error[E0425]: cannot find function `a` in this scope --> $DIR/ice-line-bounds-issue-148732.rs:1:7 diff --git a/tests/ui/enum/enum-variant-no-field.rs b/tests/ui/enum/enum-variant-no-field.rs new file mode 100644 index 0000000000000..a69766b7c48d0 --- /dev/null +++ b/tests/ui/enum/enum-variant-no-field.rs @@ -0,0 +1,9 @@ +//! regression test for https://github.com/rust-lang/rust/issues/23253 +enum Foo { + Bar, +} + +fn main() { + Foo::Bar.a; + //~^ ERROR no field `a` on type `Foo` +} diff --git a/tests/ui/issues/issue-23253.stderr b/tests/ui/enum/enum-variant-no-field.stderr similarity index 83% rename from tests/ui/issues/issue-23253.stderr rename to tests/ui/enum/enum-variant-no-field.stderr index ec7696909e725..4d02bf8761891 100644 --- a/tests/ui/issues/issue-23253.stderr +++ b/tests/ui/enum/enum-variant-no-field.stderr @@ -1,5 +1,5 @@ error[E0609]: no field `a` on type `Foo` - --> $DIR/issue-23253.rs:4:14 + --> $DIR/enum-variant-no-field.rs:7:14 | LL | Foo::Bar.a; | ^ unknown field diff --git a/tests/ui/issues/issue-50442.rs b/tests/ui/enum/enum-with-uninhabited-variant.rs similarity index 58% rename from tests/ui/issues/issue-50442.rs rename to tests/ui/enum/enum-with-uninhabited-variant.rs index 70c764f33ddf9..8dfa492e6ea5c 100644 --- a/tests/ui/issues/issue-50442.rs +++ b/tests/ui/enum/enum-with-uninhabited-variant.rs @@ -1,3 +1,4 @@ +//! regression test for issue https://github.com/rust-lang/rust/issues/50442 //@ run-pass #![allow(dead_code)] enum Void {} @@ -5,7 +6,7 @@ enum Void {} enum Foo { A(i32), B(Void), - C(i32) + C(i32), } fn main() { diff --git a/tests/ui/expr/return-in-block-tuple.rs b/tests/ui/expr/return-in-block-tuple.rs new file mode 100644 index 0000000000000..2b3a59f21412f --- /dev/null +++ b/tests/ui/expr/return-in-block-tuple.rs @@ -0,0 +1,7 @@ +//! regression test for https://github.com/rust-lang/rust/issues/18110 +//@ run-pass +#![allow(unreachable_code)] + +fn main() { + ({ return },); +} diff --git a/tests/ui/issues/issue-19398.rs b/tests/ui/extern/extern-rust-trait-method.rs similarity index 66% rename from tests/ui/issues/issue-19398.rs rename to tests/ui/extern/extern-rust-trait-method.rs index 473e43650c2c5..d71e5a8b6d532 100644 --- a/tests/ui/issues/issue-19398.rs +++ b/tests/ui/extern/extern-rust-trait-method.rs @@ -1,3 +1,4 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/19398 //@ check-pass trait T { diff --git a/tests/ui/issues/issue-3656.rs b/tests/ui/ffi/ffi-struct-size-alignment.rs similarity index 100% rename from tests/ui/issues/issue-3656.rs rename to tests/ui/ffi/ffi-struct-size-alignment.rs diff --git a/tests/ui/fmt/println-float.rs b/tests/ui/fmt/println-float.rs new file mode 100644 index 0000000000000..3adb0b4343496 --- /dev/null +++ b/tests/ui/fmt/println-float.rs @@ -0,0 +1,5 @@ +//! regression test for https://github.com/rust-lang/rust/issues/11382 +//@ run-pass +fn main() { + println!("{}", 1.2); +} diff --git a/tests/ui/indexing/ref-array-indexing.rs b/tests/ui/indexing/ref-array-indexing.rs new file mode 100644 index 0000000000000..302255798df2d --- /dev/null +++ b/tests/ui/indexing/ref-array-indexing.rs @@ -0,0 +1,6 @@ +//! regression test for https://github.com/rust-lang/rust/issues/43205 +//@ run-pass +fn main() { + let _ = &&[()][0]; + println!("{:?}", &[(), ()][1]); +} diff --git a/tests/ui/issues/issue-10656.rs b/tests/ui/issues/issue-10656.rs deleted file mode 100644 index 250c4bc442f98..0000000000000 --- a/tests/ui/issues/issue-10656.rs +++ /dev/null @@ -1,3 +0,0 @@ -#![deny(missing_docs)] -#![crate_type="lib"] -//~^^ ERROR missing documentation for the crate diff --git a/tests/ui/issues/issue-11382.rs b/tests/ui/issues/issue-11382.rs deleted file mode 100644 index 18c8c756f32e3..0000000000000 --- a/tests/ui/issues/issue-11382.rs +++ /dev/null @@ -1,4 +0,0 @@ -//@ run-pass -fn main() { - println!("{}", 1.2); -} diff --git a/tests/ui/issues/issue-17001.rs b/tests/ui/issues/issue-17001.rs deleted file mode 100644 index 68cb2865fdc82..0000000000000 --- a/tests/ui/issues/issue-17001.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod foo {} - -fn main() { - let p = foo { x: () }; //~ ERROR expected struct, variant or union type, found module `foo` -} diff --git a/tests/ui/issues/issue-17450.rs b/tests/ui/issues/issue-17450.rs deleted file mode 100644 index d8b20169ee0c4..0000000000000 --- a/tests/ui/issues/issue-17450.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ build-pass -#![allow(dead_code, warnings)] - -static mut x: isize = 3; -static mut y: isize = unsafe { x }; - -fn main() {} diff --git a/tests/ui/issues/issue-18110.rs b/tests/ui/issues/issue-18110.rs deleted file mode 100644 index 6d563a5bae1c9..0000000000000 --- a/tests/ui/issues/issue-18110.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ run-pass -#![allow(unreachable_code)] - -fn main() { - ({return},); -} diff --git a/tests/ui/issues/issue-18159.rs b/tests/ui/issues/issue-18159.rs deleted file mode 100644 index bd347d6329846..0000000000000 --- a/tests/ui/issues/issue-18159.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - let x; //~ ERROR type annotations needed -} diff --git a/tests/ui/issues/issue-18532.rs b/tests/ui/issues/issue-18532.rs deleted file mode 100644 index 31fd87961dc9f..0000000000000 --- a/tests/ui/issues/issue-18532.rs +++ /dev/null @@ -1,7 +0,0 @@ -// Test that overloaded call parameter checking does not ICE -// when a type error or unconstrained type variable propagates -// into it. - -fn main() { - (return)((),()); //~ ERROR expected function, found `!` -} diff --git a/tests/ui/issues/issue-20772.rs b/tests/ui/issues/issue-20772.rs deleted file mode 100644 index 1500bc831528a..0000000000000 --- a/tests/ui/issues/issue-20772.rs +++ /dev/null @@ -1,5 +0,0 @@ -trait T : Iterator -//~^ ERROR cycle detected -{} - -fn main() {} diff --git a/tests/ui/issues/issue-21177.rs b/tests/ui/issues/issue-21177.rs deleted file mode 100644 index 258e362d1317c..0000000000000 --- a/tests/ui/issues/issue-21177.rs +++ /dev/null @@ -1,9 +0,0 @@ -trait Trait { - type A; - type B; -} - -fn foo>() { } -//~^ ERROR cycle detected - -fn main() { } diff --git a/tests/ui/issues/issue-21291.rs b/tests/ui/issues/issue-21291.rs deleted file mode 100644 index 06f50ac6996df..0000000000000 --- a/tests/ui/issues/issue-21291.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ run-pass -//@ needs-threads - -// Regression test for unwrapping the result of `join`, issue #21291 - -use std::thread; - -fn main() { - thread::spawn(|| {}).join().unwrap() -} diff --git a/tests/ui/issues/issue-21449.rs b/tests/ui/issues/issue-21449.rs deleted file mode 100644 index 00ce2b7fffa88..0000000000000 --- a/tests/ui/issues/issue-21449.rs +++ /dev/null @@ -1,6 +0,0 @@ -mod MyMod {} - -fn main() { - let myVar = MyMod { T: 0 }; - //~^ ERROR expected struct, variant or union type, found module `MyMod` -} diff --git a/tests/ui/issues/issue-21449.stderr b/tests/ui/issues/issue-21449.stderr deleted file mode 100644 index cd1059d48993a..0000000000000 --- a/tests/ui/issues/issue-21449.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0574]: expected struct, variant or union type, found module `MyMod` - --> $DIR/issue-21449.rs:4:17 - | -LL | let myVar = MyMod { T: 0 }; - | ^^^^^ not a struct, variant or union type - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0574`. diff --git a/tests/ui/issues/issue-23189.rs b/tests/ui/issues/issue-23189.rs deleted file mode 100644 index e5526357cb0ef..0000000000000 --- a/tests/ui/issues/issue-23189.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod module {} - -fn main() { - let _ = module { x: 0 }; //~ERROR expected struct -} diff --git a/tests/ui/issues/issue-23189.stderr b/tests/ui/issues/issue-23189.stderr deleted file mode 100644 index 37d778dc992eb..0000000000000 --- a/tests/ui/issues/issue-23189.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0574]: expected struct, variant or union type, found module `module` - --> $DIR/issue-23189.rs:4:13 - | -LL | let _ = module { x: 0 }; - | ^^^^^^ not a struct, variant or union type - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0574`. diff --git a/tests/ui/issues/issue-23253.rs b/tests/ui/issues/issue-23253.rs deleted file mode 100644 index b285cb81ee230..0000000000000 --- a/tests/ui/issues/issue-23253.rs +++ /dev/null @@ -1,6 +0,0 @@ -enum Foo { Bar } - -fn main() { - Foo::Bar.a; - //~^ ERROR no field `a` on type `Foo` -} diff --git a/tests/ui/issues/issue-24779.rs b/tests/ui/issues/issue-24779.rs deleted file mode 100644 index f371828606c4b..0000000000000 --- a/tests/ui/issues/issue-24779.rs +++ /dev/null @@ -1,4 +0,0 @@ -//@ run-pass -fn main() { - assert_eq!((||||42)()(), 42); -} diff --git a/tests/ui/issues/issue-43205.rs b/tests/ui/issues/issue-43205.rs deleted file mode 100644 index 9f54d4258bf1d..0000000000000 --- a/tests/ui/issues/issue-43205.rs +++ /dev/null @@ -1,5 +0,0 @@ -//@ run-pass -fn main() { - let _ = &&[()][0]; - println!("{:?}", &[(),()][1]); -} diff --git a/tests/ui/issues/issue-4968.rs b/tests/ui/issues/issue-4968.rs deleted file mode 100644 index 08539d6debd82..0000000000000 --- a/tests/ui/issues/issue-4968.rs +++ /dev/null @@ -1,12 +0,0 @@ -// Regression test for issue #4968 - -//@ dont-require-annotations: NOTE - -const A: (isize,isize) = (4,2); -fn main() { - match 42 { A => () } - //~^ ERROR mismatched types - //~| NOTE expected type `{integer}` - //~| NOTE found tuple `(isize, isize)` - //~| NOTE expected integer, found `(isize, isize)` -} diff --git a/tests/ui/issues/issue-4968.stderr b/tests/ui/issues/issue-4968.stderr deleted file mode 100644 index 2c1e1d7bfe5a1..0000000000000 --- a/tests/ui/issues/issue-4968.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/issue-4968.rs:7:16 - | -LL | const A: (isize,isize) = (4,2); - | ---------------------- constant defined here -LL | fn main() { -LL | match 42 { A => () } - | -- ^ - | | | - | | expected integer, found `(isize, isize)` - | | `A` is interpreted as a constant, not a new binding - | | help: introduce a new binding instead: `other_a` - | this expression has type `{integer}` - | - = note: expected type `{integer}` - found tuple `(isize, isize)` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/issues/issue-17758.rs b/tests/ui/lifetimes/trait-method-lifetime-suggestion.rs similarity index 50% rename from tests/ui/issues/issue-17758.rs rename to tests/ui/lifetimes/trait-method-lifetime-suggestion.rs index e2ee84694e390..39cf4ae641857 100644 --- a/tests/ui/issues/issue-17758.rs +++ b/tests/ui/lifetimes/trait-method-lifetime-suggestion.rs @@ -1,5 +1,6 @@ -// Test that regionck suggestions in a provided method of a trait -// don't ICE +//! regression test for https://github.com/rust-lang/rust/issues/17758 +//! Test that regionck suggestions in a provided method of a trait +//! don't ICE trait Foo<'a> { fn foo(&'a self); diff --git a/tests/ui/issues/issue-17758.stderr b/tests/ui/lifetimes/trait-method-lifetime-suggestion.stderr similarity index 87% rename from tests/ui/issues/issue-17758.stderr rename to tests/ui/lifetimes/trait-method-lifetime-suggestion.stderr index 7a7d2374ef879..64347577d0704 100644 --- a/tests/ui/issues/issue-17758.stderr +++ b/tests/ui/lifetimes/trait-method-lifetime-suggestion.stderr @@ -1,5 +1,5 @@ error: lifetime may not live long enough - --> $DIR/issue-17758.rs:7:9 + --> $DIR/trait-method-lifetime-suggestion.rs:8:9 | LL | trait Foo<'a> { | -- lifetime `'a` defined here diff --git a/tests/ui/lint/lint-missing-doc-crate-attr.rs b/tests/ui/lint/lint-missing-doc-crate-attr.rs new file mode 100644 index 0000000000000..51959785c53bd --- /dev/null +++ b/tests/ui/lint/lint-missing-doc-crate-attr.rs @@ -0,0 +1,4 @@ +// regression test for https://github.com/rust-lang/rust/issues/10656 +#![deny(missing_docs)] +//~^ ERROR missing documentation for the crate +#![crate_type = "lib"] diff --git a/tests/ui/issues/issue-10656.stderr b/tests/ui/lint/lint-missing-doc-crate-attr.stderr similarity index 58% rename from tests/ui/issues/issue-10656.stderr rename to tests/ui/lint/lint-missing-doc-crate-attr.stderr index 61828f9c02a6c..caff87df664b3 100644 --- a/tests/ui/issues/issue-10656.stderr +++ b/tests/ui/lint/lint-missing-doc-crate-attr.stderr @@ -1,12 +1,13 @@ error: missing documentation for the crate - --> $DIR/issue-10656.rs:1:1 + --> $DIR/lint-missing-doc-crate-attr.rs:2:1 | LL | / #![deny(missing_docs)] -LL | | #![crate_type="lib"] - | |____________________^ +LL | | +LL | | #![crate_type = "lib"] + | |______________________^ | note: the lint level is defined here - --> $DIR/issue-10656.rs:1:9 + --> $DIR/lint-missing-doc-crate-attr.rs:2:9 | LL | #![deny(missing_docs)] | ^^^^^^^^^^^^ diff --git a/tests/ui/lint/lint-missing-doc-crate.rs b/tests/ui/lint/lint-missing-doc-crate-flags.rs similarity index 100% rename from tests/ui/lint/lint-missing-doc-crate.rs rename to tests/ui/lint/lint-missing-doc-crate-flags.rs diff --git a/tests/ui/lint/lint-missing-doc-crate.stderr b/tests/ui/lint/lint-missing-doc-crate-flags.stderr similarity index 81% rename from tests/ui/lint/lint-missing-doc-crate.stderr rename to tests/ui/lint/lint-missing-doc-crate-flags.stderr index 8efd3a17263fe..040d60a56ebf0 100644 --- a/tests/ui/lint/lint-missing-doc-crate.stderr +++ b/tests/ui/lint/lint-missing-doc-crate-flags.stderr @@ -1,5 +1,5 @@ error: missing documentation for the crate - --> $DIR/lint-missing-doc-crate.rs:4:47 + --> $DIR/lint-missing-doc-crate-flags.rs:4:47 | LL | | ^ diff --git a/tests/ui/macros/cfg_select.stderr b/tests/ui/macros/cfg_select.stderr index 5e2d705760cf6..510fc33d6d113 100644 --- a/tests/ui/macros/cfg_select.stderr +++ b/tests/ui/macros/cfg_select.stderr @@ -38,14 +38,12 @@ error[E0539]: malformed `cfg_select` macro input | LL | "str" => {} | ^^^^^ expected a valid identifier here - | error[E0539]: malformed `cfg_select` macro input --> $DIR/cfg_select.rs:80:5 | LL | a::b => {} | ^^^^ expected a valid identifier here - | error[E0537]: invalid predicate `a` --> $DIR/cfg_select.rs:85:5 diff --git a/tests/ui/issues/issue-19734.rs b/tests/ui/macros/undefined-macro-in-impl.rs similarity index 60% rename from tests/ui/issues/issue-19734.rs rename to tests/ui/macros/undefined-macro-in-impl.rs index fe4a327aef49c..64b394f984be0 100644 --- a/tests/ui/issues/issue-19734.rs +++ b/tests/ui/macros/undefined-macro-in-impl.rs @@ -1,3 +1,4 @@ +//! regression test for https://github.com/rust-lang/rust/issues/19734 fn main() {} struct Type; diff --git a/tests/ui/issues/issue-19734.stderr b/tests/ui/macros/undefined-macro-in-impl.stderr similarity index 75% rename from tests/ui/issues/issue-19734.stderr rename to tests/ui/macros/undefined-macro-in-impl.stderr index ed48714fe5078..8d1bd958d7f6a 100644 --- a/tests/ui/issues/issue-19734.stderr +++ b/tests/ui/macros/undefined-macro-in-impl.stderr @@ -1,5 +1,5 @@ error: cannot find macro `undef` in this scope - --> $DIR/issue-19734.rs:6:5 + --> $DIR/undefined-macro-in-impl.rs:7:5 | LL | undef!(); | ^^^^^ diff --git a/tests/ui/match/match-const-tuple-type-mismatch.rs b/tests/ui/match/match-const-tuple-type-mismatch.rs new file mode 100644 index 0000000000000..c9358e3d5faac --- /dev/null +++ b/tests/ui/match/match-const-tuple-type-mismatch.rs @@ -0,0 +1,13 @@ +//! Regression test for issue https://github.com/rust-lang/rust/issues/4968 +//@ dont-require-annotations: NOTE + +const A: (isize, isize) = (4, 2); +fn main() { + match 42 { + A => (), + //~^ ERROR mismatched types + //~| NOTE expected type `{integer}` + //~| NOTE found tuple `(isize, isize)` + //~| NOTE expected integer, found `(isize, isize)` + } +} diff --git a/tests/ui/match/match-const-tuple-type-mismatch.stderr b/tests/ui/match/match-const-tuple-type-mismatch.stderr new file mode 100644 index 0000000000000..e7dd97c4e9a60 --- /dev/null +++ b/tests/ui/match/match-const-tuple-type-mismatch.stderr @@ -0,0 +1,21 @@ +error[E0308]: mismatched types + --> $DIR/match-const-tuple-type-mismatch.rs:7:9 + | +LL | const A: (isize, isize) = (4, 2); + | ----------------------- constant defined here +LL | fn main() { +LL | match 42 { + | -- this expression has type `{integer}` +LL | A => (), + | ^ + | | + | expected integer, found `(isize, isize)` + | `A` is interpreted as a constant, not a new binding + | help: introduce a new binding instead: `other_a` + | + = note: expected type `{integer}` + found tuple `(isize, isize)` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/issues/issue-18464.rs b/tests/ui/match/match-range-char-const.rs similarity index 65% rename from tests/ui/issues/issue-18464.rs rename to tests/ui/match/match-range-char-const.rs index 9950647198395..84881fd56cc0f 100644 --- a/tests/ui/issues/issue-18464.rs +++ b/tests/ui/match/match-range-char-const.rs @@ -1,3 +1,4 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/18464 //@ run-pass #![deny(dead_code)] @@ -7,6 +8,6 @@ const HIGH_RANGE: char = '9'; fn main() { match '5' { LOW_RANGE..=HIGH_RANGE => (), - _ => () + _ => (), }; } diff --git a/tests/ui/issues/issue-17933.rs b/tests/ui/match/match-static-pattern.rs similarity index 56% rename from tests/ui/issues/issue-17933.rs rename to tests/ui/match/match-static-pattern.rs index 6da4e6e15284b..5d367f9ec17c7 100644 --- a/tests/ui/issues/issue-17933.rs +++ b/tests/ui/match/match-static-pattern.rs @@ -1,9 +1,10 @@ +//! regression test for issue https://github.com/rust-lang/rust/issues/17933 pub static X: usize = 1; fn main() { match 1 { - self::X => { }, + self::X => {} //~^ ERROR expected unit struct, unit variant or constant, found static `self::X` - _ => { }, + _ => {} } } diff --git a/tests/ui/issues/issue-17933.stderr b/tests/ui/match/match-static-pattern.stderr similarity index 80% rename from tests/ui/issues/issue-17933.stderr rename to tests/ui/match/match-static-pattern.stderr index 42a7e04420735..1b111fbcc2dec 100644 --- a/tests/ui/issues/issue-17933.stderr +++ b/tests/ui/match/match-static-pattern.stderr @@ -1,7 +1,7 @@ error[E0532]: expected unit struct, unit variant or constant, found static `self::X` - --> $DIR/issue-17933.rs:5:9 + --> $DIR/match-static-pattern.rs:6:9 | -LL | self::X => { }, +LL | self::X => {} | ^^^^^^^ not a unit struct, unit variant or constant error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-16783.rs b/tests/ui/moves/array-copy-move.rs similarity index 56% rename from tests/ui/issues/issue-16783.rs rename to tests/ui/moves/array-copy-move.rs index 2ecc42b579d50..ea95bc06a3693 100644 --- a/tests/ui/issues/issue-16783.rs +++ b/tests/ui/moves/array-copy-move.rs @@ -1,3 +1,4 @@ +//! regression test for issue https://github.com/rust-lang/rust/issues/16783 //@ run-pass #![allow(unused_variables)] diff --git a/tests/ui/issues/issue-17373.rs b/tests/ui/never_type/never-deref.rs similarity index 51% rename from tests/ui/issues/issue-17373.rs rename to tests/ui/never_type/never-deref.rs index dc3be48a7ead7..6e4b89db04a54 100644 --- a/tests/ui/issues/issue-17373.rs +++ b/tests/ui/never_type/never-deref.rs @@ -1,3 +1,4 @@ +//! regression test for https://github.com/rust-lang/rust/issues/17373 fn main() { *return //~ ERROR type `!` cannot be dereferenced ; diff --git a/tests/ui/issues/issue-17373.stderr b/tests/ui/never_type/never-deref.stderr similarity index 87% rename from tests/ui/issues/issue-17373.stderr rename to tests/ui/never_type/never-deref.stderr index 0e16d08c87d34..76f31f3779878 100644 --- a/tests/ui/issues/issue-17373.stderr +++ b/tests/ui/never_type/never-deref.stderr @@ -1,5 +1,5 @@ error[E0614]: type `!` cannot be dereferenced - --> $DIR/issue-17373.rs:2:5 + --> $DIR/never-deref.rs:3:5 | LL | *return | ^^^^^^^ can't be dereferenced diff --git a/tests/ui/issues/issue-22644.rs b/tests/ui/parser/cast-angle-bracket-precedence.rs similarity index 92% rename from tests/ui/issues/issue-22644.rs rename to tests/ui/parser/cast-angle-bracket-precedence.rs index e3ada65049d56..65b598d03bdef 100644 --- a/tests/ui/issues/issue-22644.rs +++ b/tests/ui/parser/cast-angle-bracket-precedence.rs @@ -1,3 +1,5 @@ +//! regression test for https://github.com/rust-lang/rust/issues/22644 + fn main() { let a: usize = 0; let long_name: usize = 0; diff --git a/tests/ui/issues/issue-22644.stderr b/tests/ui/parser/cast-angle-bracket-precedence.stderr similarity index 89% rename from tests/ui/issues/issue-22644.stderr rename to tests/ui/parser/cast-angle-bracket-precedence.stderr index c6d41cc856dd4..975bfea9425aa 100644 --- a/tests/ui/issues/issue-22644.stderr +++ b/tests/ui/parser/cast-angle-bracket-precedence.stderr @@ -1,5 +1,5 @@ error: `<` is interpreted as a start of generic arguments for `usize`, not a comparison - --> $DIR/issue-22644.rs:6:31 + --> $DIR/cast-angle-bracket-precedence.rs:8:31 | LL | println!("{}", a as usize < long_name); | ^ --------- interpreted as generic arguments @@ -12,7 +12,7 @@ LL | println!("{}", (a as usize) < long_name); | + + error: `<` is interpreted as a start of generic arguments for `usize`, not a comparison - --> $DIR/issue-22644.rs:7:33 + --> $DIR/cast-angle-bracket-precedence.rs:9:33 | LL | println!("{}{}", a as usize < long_name, long_name); | ^ -------------------- interpreted as generic arguments @@ -25,7 +25,7 @@ LL | println!("{}{}", (a as usize) < long_name, long_name); | + + error: `<` is interpreted as a start of generic arguments for `usize`, not a comparison - --> $DIR/issue-22644.rs:9:31 + --> $DIR/cast-angle-bracket-precedence.rs:11:31 | LL | println!("{}", a as usize < 4); | ^ - interpreted as generic arguments @@ -38,7 +38,7 @@ LL | println!("{}", (a as usize) < 4); | + + error: `<` is interpreted as a start of generic arguments for `usize`, not a comparison - --> $DIR/issue-22644.rs:14:20 + --> $DIR/cast-angle-bracket-precedence.rs:16:20 | LL | < | ^ not interpreted as comparison @@ -53,7 +53,7 @@ LL ~ usize) | error: `<` is interpreted as a start of generic arguments for `usize`, not a comparison - --> $DIR/issue-22644.rs:23:20 + --> $DIR/cast-angle-bracket-precedence.rs:25:20 | LL | < | ^ not interpreted as comparison @@ -70,7 +70,7 @@ LL ~ usize) | error: `<<` is interpreted as a start of generic arguments for `usize`, not a shift - --> $DIR/issue-22644.rs:26:31 + --> $DIR/cast-angle-bracket-precedence.rs:28:31 | LL | println!("{}", a as usize << long_name); | ^^ --------- interpreted as generic arguments diff --git a/tests/ui/issues/issue-27033.rs b/tests/ui/pattern/match-at-pattern-shadows-name.rs similarity index 58% rename from tests/ui/issues/issue-27033.rs rename to tests/ui/pattern/match-at-pattern-shadows-name.rs index a23819a20f9aa..3cd2040c9fafa 100644 --- a/tests/ui/issues/issue-27033.rs +++ b/tests/ui/pattern/match-at-pattern-shadows-name.rs @@ -1,10 +1,12 @@ +//! regression test for https://github.com/rust-lang/rust/issues/27033 fn main() { match Some(1) { None @ _ => {} //~ ERROR match bindings cannot shadow unit variants }; const C: u8 = 1; match 1 { - C @ 2 => { //~ ERROR match bindings cannot shadow constant + C @ 2 => { + //~^ ERROR match bindings cannot shadow constant println!("{}", C); } _ => {} diff --git a/tests/ui/issues/issue-27033.stderr b/tests/ui/pattern/match-at-pattern-shadows-name.stderr similarity index 86% rename from tests/ui/issues/issue-27033.stderr rename to tests/ui/pattern/match-at-pattern-shadows-name.stderr index 129870f8c4098..6e2fbf546e82d 100644 --- a/tests/ui/issues/issue-27033.stderr +++ b/tests/ui/pattern/match-at-pattern-shadows-name.stderr @@ -1,5 +1,5 @@ error[E0530]: match bindings cannot shadow unit variants - --> $DIR/issue-27033.rs:3:9 + --> $DIR/match-at-pattern-shadows-name.rs:4:9 | LL | None @ _ => {} | ^^^^ cannot be named the same as a unit variant @@ -9,7 +9,7 @@ LL | None @ _ => {} = note: the unit variant `None` is defined here error[E0530]: match bindings cannot shadow constants - --> $DIR/issue-27033.rs:7:9 + --> $DIR/match-at-pattern-shadows-name.rs:8:9 | LL | const C: u8 = 1; | ---------------- the constant `C` is defined here diff --git a/tests/ui/repeat-expr/copy-check-deferred-after-fallback.rs b/tests/ui/repeat-expr/copy-check-deferred-after-fallback.rs index a6bd5b299c96a..02cd9f4a3b296 100644 --- a/tests/ui/repeat-expr/copy-check-deferred-after-fallback.rs +++ b/tests/ui/repeat-expr/copy-check-deferred-after-fallback.rs @@ -1,6 +1,6 @@ // Test when deferring repeat expr copy checks to end of typechecking whether they're // checked before integer fallback occurs or not. We accomplish this by having a repeat -// count that can only be inferred after integer fallback has occured. This test will +// count that can only be inferred after integer fallback has occurred. This test will // pass if we were to check repeat exprs after integer fallback. use std::marker::PhantomData; diff --git a/tests/ui/resolve/module-used-as-struct-constructor.rs b/tests/ui/resolve/module-used-as-struct-constructor.rs new file mode 100644 index 0000000000000..bdc7b2bf5841f --- /dev/null +++ b/tests/ui/resolve/module-used-as-struct-constructor.rs @@ -0,0 +1,6 @@ +//! regression test for https://github.com/rust-lang/rust/issues/17001, https://github.com/rust-lang/rust/issues/21449, https://github.com/rust-lang/rust/issues/23189 +mod foo {} + +fn main() { + let p = foo { x: () }; //~ ERROR expected struct, variant or union type, found module `foo` +} diff --git a/tests/ui/issues/issue-17001.stderr b/tests/ui/resolve/module-used-as-struct-constructor.stderr similarity index 83% rename from tests/ui/issues/issue-17001.stderr rename to tests/ui/resolve/module-used-as-struct-constructor.stderr index 6ea32e0a45c39..b94a28762a7f8 100644 --- a/tests/ui/issues/issue-17001.stderr +++ b/tests/ui/resolve/module-used-as-struct-constructor.stderr @@ -1,5 +1,5 @@ error[E0574]: expected struct, variant or union type, found module `foo` - --> $DIR/issue-17001.rs:4:13 + --> $DIR/module-used-as-struct-constructor.rs:5:13 | LL | let p = foo { x: () }; | ^^^ not a struct, variant or union type diff --git a/tests/ui/issues/issue-34047.rs b/tests/ui/shadowed/match-binding-shadows-const.rs similarity index 66% rename from tests/ui/issues/issue-34047.rs rename to tests/ui/shadowed/match-binding-shadows-const.rs index 55196177f6934..95f2e087b5e7f 100644 --- a/tests/ui/issues/issue-34047.rs +++ b/tests/ui/shadowed/match-binding-shadows-const.rs @@ -1,3 +1,4 @@ +//! regression test for https://github.com/rust-lang/rust/issues/34047 const C: u8 = 0; fn main() { diff --git a/tests/ui/issues/issue-34047.stderr b/tests/ui/shadowed/match-binding-shadows-const.stderr similarity index 87% rename from tests/ui/issues/issue-34047.stderr rename to tests/ui/shadowed/match-binding-shadows-const.stderr index 97b1230ce3509..345c67700e626 100644 --- a/tests/ui/issues/issue-34047.stderr +++ b/tests/ui/shadowed/match-binding-shadows-const.stderr @@ -1,5 +1,5 @@ error[E0530]: match bindings cannot shadow constants - --> $DIR/issue-34047.rs:5:13 + --> $DIR/match-binding-shadows-const.rs:6:13 | LL | const C: u8 = 0; | ---------------- the constant `C` is defined here diff --git a/tests/ui/span/issue-42234-unknown-receiver-type.stderr b/tests/ui/span/issue-42234-unknown-receiver-type.stderr index 10308ec07da5a..f16006a8e085b 100644 --- a/tests/ui/span/issue-42234-unknown-receiver-type.stderr +++ b/tests/ui/span/issue-42234-unknown-receiver-type.stderr @@ -16,7 +16,6 @@ error[E0282]: type annotations needed | LL | .sum::<_>() | ^^^ cannot infer type of the type parameter `S` declared on the method `sum` - | error: aborting due to 2 previous errors diff --git a/tests/ui/statics/static-mut-unsafe-init.rs b/tests/ui/statics/static-mut-unsafe-init.rs new file mode 100644 index 0000000000000..ee8472100a08e --- /dev/null +++ b/tests/ui/statics/static-mut-unsafe-init.rs @@ -0,0 +1,8 @@ +//! regression test for https://github.com/rust-lang/rust/issues/17450 +//@ build-pass +#![allow(dead_code)] + +static mut X: isize = 3; +static mut Y: isize = unsafe { X }; + +fn main() {} diff --git a/tests/ui/structs/ice-line-bounds-issue-148684.stderr b/tests/ui/structs/ice-line-bounds-issue-148684.stderr index f26d96cd1172b..71ed393bf0563 100644 --- a/tests/ui/structs/ice-line-bounds-issue-148684.stderr +++ b/tests/ui/structs/ice-line-bounds-issue-148684.stderr @@ -9,7 +9,6 @@ LL | | } ... LL | A(2, vec![]) | ^^^^^^^^^^^^ - | error: aborting due to 1 previous error diff --git a/tests/ui/threads-sendsync/thread-join-unwrap.rs b/tests/ui/threads-sendsync/thread-join-unwrap.rs new file mode 100644 index 0000000000000..6288e15b18741 --- /dev/null +++ b/tests/ui/threads-sendsync/thread-join-unwrap.rs @@ -0,0 +1,9 @@ +//! Regression test for unwrapping the result of `join`, issue https://github.com/rust-lang/rust/issues/21291 +//@ run-pass +//@ needs-threads + +use std::thread; + +fn main() { + thread::spawn(|| {}).join().unwrap() +} diff --git a/tests/ui/issues/issue-20162.rs b/tests/ui/trait-bounds/sort-missing-ord-bound.rs similarity index 50% rename from tests/ui/issues/issue-20162.rs rename to tests/ui/trait-bounds/sort-missing-ord-bound.rs index b491bc37f5153..8d4ea88150175 100644 --- a/tests/ui/issues/issue-20162.rs +++ b/tests/ui/trait-bounds/sort-missing-ord-bound.rs @@ -1,4 +1,7 @@ -struct X { x: i32 } +//! regression test for issue https://github.com/rust-lang/rust/issues/20162 +struct X { + x: i32, +} fn main() { let mut b: Vec = vec![]; diff --git a/tests/ui/issues/issue-20162.stderr b/tests/ui/trait-bounds/sort-missing-ord-bound.stderr similarity index 88% rename from tests/ui/issues/issue-20162.stderr rename to tests/ui/trait-bounds/sort-missing-ord-bound.stderr index 8f45f0d36c71e..c11781e5fff3f 100644 --- a/tests/ui/issues/issue-20162.stderr +++ b/tests/ui/trait-bounds/sort-missing-ord-bound.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `X: Ord` is not satisfied - --> $DIR/issue-20162.rs:5:7 + --> $DIR/sort-missing-ord-bound.rs:8:7 | LL | b.sort(); | ^^^^ the trait `Ord` is not implemented for `X` @@ -9,7 +9,7 @@ note: required by a bound in `slice::::sort` help: consider annotating `X` with `#[derive(Ord)]` | LL + #[derive(Ord)] -LL | struct X { x: i32 } +LL | struct X { | error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/call.rs b/tests/ui/traits/const-traits/call.rs index 360c08e1b7fe9..c36adc4248f03 100644 --- a/tests/ui/traits/const-traits/call.rs +++ b/tests/ui/traits/const-traits/call.rs @@ -6,6 +6,7 @@ const _: () = { assert!((const || true)()); //~^ ERROR }: [const] Fn()` is not satisfied + //~| ERROR }: [const] FnMut()` is not satisfied }; fn main() {} diff --git a/tests/ui/traits/const-traits/call.stderr b/tests/ui/traits/const-traits/call.stderr index 8e32cab6dfcfb..b688746e25068 100644 --- a/tests/ui/traits/const-traits/call.stderr +++ b/tests/ui/traits/const-traits/call.stderr @@ -4,6 +4,15 @@ error[E0277]: the trait bound `{closure@$DIR/call.rs:7:14: 7:22}: [const] Fn()` LL | assert!((const || true)()); | ^^^^^^^^^^^^^^^^^ -error: aborting due to 1 previous error +error[E0277]: the trait bound `{closure@$DIR/call.rs:7:14: 7:22}: [const] FnMut()` is not satisfied + --> $DIR/call.rs:7:13 + | +LL | assert!((const || true)()); + | ^^^^^^^^^^^^^^^^^ + | +note: required by a bound in `call` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.rs b/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.rs index 30002038f6891..e355ee724d1bd 100644 --- a/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.rs +++ b/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.rs @@ -13,6 +13,4 @@ impl Foo for () { fn main() { (const || (()).foo())(); - // ^ ERROR: cannot call non-const method `<() as Foo>::foo` in constant functions - // FIXME(const_trait_impl) this should probably say constant closures } diff --git a/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.stderr b/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.stderr index dab3f14161fac..90e87c724f54d 100644 --- a/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.stderr +++ b/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.stderr @@ -4,6 +4,15 @@ error[E0277]: the trait bound `{closure@$DIR/const_closure-const_trait_impl-ice- LL | (const || (()).foo())(); | ^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 1 previous error +error[E0277]: the trait bound `{closure@$DIR/const_closure-const_trait_impl-ice-113381.rs:15:6: 15:14}: [const] FnMut()` is not satisfied + --> $DIR/const_closure-const_trait_impl-ice-113381.rs:15:5 + | +LL | (const || (()).foo())(); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +note: required by a bound in `call` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.rs b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.rs index d0470fa345848..ee4ff02f4c7c2 100644 --- a/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.rs +++ b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.rs @@ -12,4 +12,5 @@ impl Foo for () { fn main() { (const || { (()).foo() })(); //~^ ERROR: }: [const] Fn()` is not satisfied + //~| ERROR: }: [const] FnMut()` is not satisfied } diff --git a/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr index dcf65ab694080..69d289537da1d 100644 --- a/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr +++ b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr @@ -4,6 +4,15 @@ error[E0277]: the trait bound `{closure@$DIR/non-const-op-const-closure-non-cons LL | (const || { (()).foo() })(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 1 previous error +error[E0277]: the trait bound `{closure@$DIR/non-const-op-const-closure-non-const-outer.rs:13:6: 13:14}: [const] FnMut()` is not satisfied + --> $DIR/non-const-op-const-closure-non-const-outer.rs:13:5 + | +LL | (const || { (()).foo() })(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: required by a bound in `call` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/solver-cycles/assoc-equality-cycle.rs b/tests/ui/traits/solver-cycles/assoc-equality-cycle.rs new file mode 100644 index 0000000000000..f82bffc598b8b --- /dev/null +++ b/tests/ui/traits/solver-cycles/assoc-equality-cycle.rs @@ -0,0 +1,10 @@ +//! regression test for https://github.com/rust-lang/rust/issues/21177 +trait Trait { + type A; + type B; +} + +fn foo>() {} +//~^ ERROR cycle detected + +fn main() {} diff --git a/tests/ui/issues/issue-21177.stderr b/tests/ui/traits/solver-cycles/assoc-equality-cycle.stderr similarity index 78% rename from tests/ui/issues/issue-21177.stderr rename to tests/ui/traits/solver-cycles/assoc-equality-cycle.stderr index 9f66f43a195a1..a8c0228601a26 100644 --- a/tests/ui/issues/issue-21177.stderr +++ b/tests/ui/traits/solver-cycles/assoc-equality-cycle.stderr @@ -1,14 +1,14 @@ error[E0391]: cycle detected when computing the bounds for type parameter `T` - --> $DIR/issue-21177.rs:6:21 + --> $DIR/assoc-equality-cycle.rs:7:21 | -LL | fn foo>() { } +LL | fn foo>() {} | ^^^^ | = note: ...which immediately requires computing the bounds for type parameter `T` again note: cycle used when computing explicit predicates of `foo` - --> $DIR/issue-21177.rs:6:21 + --> $DIR/assoc-equality-cycle.rs:7:21 | -LL | fn foo>() { } +LL | fn foo>() {} | ^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information diff --git a/tests/ui/traits/solver-cycles/self-item-cycle.rs b/tests/ui/traits/solver-cycles/self-item-cycle.rs new file mode 100644 index 0000000000000..b0b5ab4235beb --- /dev/null +++ b/tests/ui/traits/solver-cycles/self-item-cycle.rs @@ -0,0 +1,6 @@ +//! regression test for https://github.com/rust-lang/rust/issues/20772 +trait T: Iterator //~ ERROR cycle detected +{ +} + +fn main() {} diff --git a/tests/ui/issues/issue-20772.stderr b/tests/ui/traits/solver-cycles/self-item-cycle.stderr similarity index 69% rename from tests/ui/issues/issue-20772.stderr rename to tests/ui/traits/solver-cycles/self-item-cycle.stderr index 81f80aef59446..9ffb9955af8a5 100644 --- a/tests/ui/issues/issue-20772.stderr +++ b/tests/ui/traits/solver-cycles/self-item-cycle.stderr @@ -1,15 +1,15 @@ error[E0391]: cycle detected when computing the super traits of `T` with associated type name `Item` - --> $DIR/issue-20772.rs:1:1 + --> $DIR/self-item-cycle.rs:2:1 | -LL | trait T : Iterator - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | trait T: Iterator + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: ...which immediately requires computing the super traits of `T` with associated type name `Item` again note: cycle used when computing the super predicates of `T` - --> $DIR/issue-20772.rs:1:1 + --> $DIR/self-item-cycle.rs:2:1 | -LL | trait T : Iterator - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | trait T: Iterator + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error: aborting due to 1 previous error diff --git a/tests/ui/typeck/missing-type-annotation.rs b/tests/ui/typeck/missing-type-annotation.rs new file mode 100644 index 0000000000000..d13a7a8559e30 --- /dev/null +++ b/tests/ui/typeck/missing-type-annotation.rs @@ -0,0 +1,4 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/18159 +fn main() { + let x; //~ ERROR type annotations needed +} diff --git a/tests/ui/issues/issue-18159.stderr b/tests/ui/typeck/missing-type-annotation.stderr similarity index 87% rename from tests/ui/issues/issue-18159.stderr rename to tests/ui/typeck/missing-type-annotation.stderr index 5de13a5c314c5..88716e757a939 100644 --- a/tests/ui/issues/issue-18159.stderr +++ b/tests/ui/typeck/missing-type-annotation.stderr @@ -1,5 +1,5 @@ error[E0282]: type annotations needed - --> $DIR/issue-18159.rs:2:9 + --> $DIR/missing-type-annotation.rs:3:9 | LL | let x; | ^ diff --git a/tests/ui/issues/issue-49854.rs b/tests/ui/typeck/osstring-str-equality.rs similarity index 71% rename from tests/ui/issues/issue-49854.rs rename to tests/ui/typeck/osstring-str-equality.rs index b5a3f07dd4b85..47d3dd632bdc1 100644 --- a/tests/ui/issues/issue-49854.rs +++ b/tests/ui/typeck/osstring-str-equality.rs @@ -1,3 +1,4 @@ +//! regression test for https://github.com/rust-lang/rust/issues/49854 //@ run-pass use std::ffi::OsString; diff --git a/tests/ui/typeck/return-expression-invalid-callee.rs b/tests/ui/typeck/return-expression-invalid-callee.rs new file mode 100644 index 0000000000000..1416f3e9ddfe7 --- /dev/null +++ b/tests/ui/typeck/return-expression-invalid-callee.rs @@ -0,0 +1,8 @@ +//! regression test for issue https://github.com/rust-lang/rust/issues/18532 +//! Test that overloaded call parameter checking does not ICE +//! when a type error or unconstrained type variable propagates +//! into it. + +fn main() { + (return)((), ()); //~ ERROR expected function, found `!` +} diff --git a/tests/ui/issues/issue-18532.stderr b/tests/ui/typeck/return-expression-invalid-callee.stderr similarity index 67% rename from tests/ui/issues/issue-18532.stderr rename to tests/ui/typeck/return-expression-invalid-callee.stderr index 059c7f137819e..5a36602af8bb6 100644 --- a/tests/ui/issues/issue-18532.stderr +++ b/tests/ui/typeck/return-expression-invalid-callee.stderr @@ -1,8 +1,8 @@ error[E0618]: expected function, found `!` - --> $DIR/issue-18532.rs:6:5 + --> $DIR/return-expression-invalid-callee.rs:7:5 | -LL | (return)((),()); - | ^^^^^^^^------- +LL | (return)((), ()); + | ^^^^^^^^-------- | | | call expression requires function