diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 3ea7902d5712d..b056fdc73d40b 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -51,7 +51,7 @@ use rustc_data_structures::stable_hash::StableOrd; #[cfg(feature = "nightly")] use rustc_error_messages::{DiagArgValue, IntoDiagArg}; #[cfg(feature = "nightly")] -use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, msg}; +use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level, msg}; use rustc_hashes::Hash64; use rustc_index::{Idx, IndexSlice, IndexVec}; #[cfg(feature = "nightly")] @@ -399,7 +399,7 @@ pub enum TargetDataLayoutError<'a> { } #[cfg(feature = "nightly")] -impl Diagnostic<'_, G> for TargetDataLayoutError<'_> { +impl Diagnostic<'_, G> for TargetDataLayoutError<'_> { fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { match self { TargetDataLayoutError::InvalidAddressSpace { addr_space, err, cause } => { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index d987bb69b0c53..b8baf21898a96 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -800,9 +800,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_variant(&mut self, item_kind: &ItemKind, v: &Variant) -> hir::Variant<'hir> { if v.ident.name == kw::Underscore && self.tcx.features().unnamed_enum_variants() { // FIXME(#156628): lower unnamed enum variants to HIR. - self.dcx() - .struct_span_fatal(v.span, "unnamed enum variants are not yet implemented") - .emit() + self.dcx().span_fatal(v.span, "unnamed enum variants are not yet implemented"); } let hir_id = self.lower_node_id(v.id); self.lower_attrs(hir_id, &v.attrs, v.span, Target::Variant); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index aa58ac4a62eca..1a351cc1420f3 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1798,9 +1798,9 @@ impl<'hir> LoweringContext<'_, 'hir> { if expr::WillCreateDefIdsVisitor.visit_expr(expr).is_break() { // FIXME(mgca): make this non-fatal once we have a better way to handle // nested items in invalid `direct_const_arg!()` arguments. - self.dcx().struct_span_fatal(span, msg).emit() + self.dcx().span_fatal(span, msg) } else { - self.dcx().struct_span_err(span, msg).emit() + self.dcx().span_err(span, msg) } } @@ -2960,9 +2960,8 @@ impl<'hir> LoweringContext<'_, 'hir> { let literal = self.lower_lit(literal, span); let kind = if !matches!(literal.node, LitKind::Int(..)) { - let err = - self.dcx().struct_span_err(expr.span, "negated literal must be an integer"); - hir::ConstArgKind::Error(err.emit()) + let err = self.dcx().span_err(expr.span, "negated literal must be an integer"); + hir::ConstArgKind::Error(err) } else { hir::ConstArgKind::Literal { lit: literal.node, negated: true } }; @@ -3366,9 +3365,9 @@ impl UnrepresentableConstArgError { // FIXME(mgca): make this non-fatal once we have a better way to handle // nested items in const args // Issue: https://github.com/rust-lang/rust/issues/154539 - lowering_context.dcx().struct_span_fatal(self.span, msg).emit() + lowering_context.dcx().span_fatal(self.span, msg) } else { - lowering_context.dcx().struct_span_err(self.span, msg).emit() + lowering_context.dcx().span_err(self.span, msg) }; ConstArg { diff --git a/compiler/rustc_ast_passes/src/diagnostics.rs b/compiler/rustc_ast_passes/src/diagnostics.rs index 5ab905b5df52b..337ce7591900f 100644 --- a/compiler/rustc_ast_passes/src/diagnostics.rs +++ b/compiler/rustc_ast_passes/src/diagnostics.rs @@ -2,7 +2,7 @@ use rustc_abi::ExternAbi; use rustc_errors::codes::*; -use rustc_errors::{Applicability, Diag, EmissionGuarantee, Subdiagnostic}; +use rustc_errors::{Applicability, Diag, Subdiagnostic}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Ident, Span, Symbol}; @@ -663,7 +663,7 @@ pub(crate) struct EmptyLabelManySpans(pub Vec); // The derive for `Vec` does multiple calls to `span_label`, adding commas between each impl Subdiagnostic for EmptyLabelManySpans { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.span_labels(self.0, ""); } } diff --git a/compiler/rustc_attr_parsing/src/diagnostics.rs b/compiler/rustc_attr_parsing/src/diagnostics.rs index aeaada0e61409..e5f49690f71dc 100644 --- a/compiler/rustc_attr_parsing/src/diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/diagnostics.rs @@ -3,8 +3,7 @@ use std::num::IntErrorKind; use rustc_attr_ir::{AttrPath, MirDialect, MirPhase}; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, E0264, EmissionGuarantee, Level, - MultiSpan, + Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, E0264, Level, MultiSpan, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Ident, Span, Symbol}; @@ -1482,9 +1481,7 @@ impl<'a> AttributeParseError<'a> { diag: &mut Diag<'_, G>, possibilities: &[Symbol], strings: bool, - ) where - G: EmissionGuarantee, - { + ) { let quote = if strings { '"' } else { '`' }; match possibilities { &[] => {} @@ -1517,9 +1514,7 @@ impl<'a> AttributeParseError<'a> { diag: &mut Diag<'_, G>, possibilities: &[Symbol], strings: bool, - ) where - G: EmissionGuarantee, - { + ) { let description = self.description(); let quote = if strings { '"' } else { '`' }; @@ -1548,10 +1543,7 @@ impl<'a> AttributeParseError<'a> { } } - fn render_suggestions(&self, diag: &mut Diag<'_, G>) - where - G: EmissionGuarantee, - { + fn render_suggestions(&self, diag: &mut Diag<'_, G>) { let description = self.description(); match &self.suggestions { @@ -1600,7 +1592,7 @@ impl AttributeParseErrorSuggestions { } } -impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> { +impl<'a, G> Diagnostic<'a, G> for AttributeParseError<'_> { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let name = self.path.to_string(); diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 1b633aefc22f8..429eb85ed9e11 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -2,7 +2,7 @@ use std::assert_matches; -use rustc_errors::{Applicability, Diag, EmissionGuarantee}; +use rustc_errors::{Applicability, Diag}; use rustc_hir as hir; use rustc_hir::intravisit::Visitor; use rustc_infer::infer::NllRegionVariableOrigin; @@ -55,7 +55,7 @@ impl<'tcx> BorrowExplanation<'tcx> { pub(crate) fn is_explained(&self) -> bool { !matches!(self, BorrowExplanation::Unexplained) } - pub(crate) fn add_explanation_to_diagnostic( + pub(crate) fn add_explanation_to_diagnostic( &self, cx: &MirBorrowckCtxt<'_, '_, 'tcx>, err: &mut Diag<'_, G>, @@ -437,7 +437,7 @@ impl<'tcx> BorrowExplanation<'tcx> { } } - fn add_object_lifetime_default_note( + fn add_object_lifetime_default_note( &self, tcx: TyCtxt<'tcx>, err: &mut Diag<'_, G>, @@ -494,7 +494,7 @@ impl<'tcx> BorrowExplanation<'tcx> { } } - fn add_lifetime_bound_suggestion_to_diagnostic( + fn add_lifetime_bound_suggestion_to_diagnostic( &self, err: &mut Diag<'_, G>, category: &ConstraintCategory<'tcx>, @@ -523,7 +523,7 @@ impl<'tcx> BorrowExplanation<'tcx> { } } -fn suggest_rewrite_if_let( +fn suggest_rewrite_if_let( tcx: TyCtxt<'_>, expr: &hir::Expr<'_>, pat: &str, diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 0e5ab5c00bd76..c5cf8d36abf1f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -5,7 +5,7 @@ use std::collections::BTreeMap; use rustc_abi::{FieldIdx, VariantIdx}; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::formatting::DiagMessageAddArg; -use rustc_errors::{Applicability, Diag, DiagMessage, EmissionGuarantee, MultiSpan, listify, msg}; +use rustc_errors::{Applicability, Diag, DiagMessage, MultiSpan, listify, msg}; use rustc_hir::attrs::lang_items::LangItem; use rustc_hir::def::{CtorKind, Namespace}; use rustc_hir::{ @@ -669,7 +669,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { /// /// This is very similar to `fn suggest_static_lifetime_for_gat_from_hrtb` which handles this /// note for failed type tests instead of outlives errors. - fn add_placeholder_from_predicate_note( + fn add_placeholder_from_predicate_note( &self, diag: &mut Diag<'_, G>, path: &[OutlivesConstraint<'tcx>], @@ -731,7 +731,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { /// Add a label to region errors and borrow explanations when outlives constraints arise from /// proving a type implements `Sized` or `Copy`. - fn add_sized_or_copy_bound_info( + fn add_sized_or_copy_bound_info( &self, err: &mut Diag<'_, G>, blamed_category: ConstraintCategory<'tcx>, diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 4e8237178d0fc..3b457d10f51bd 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -2,7 +2,7 @@ use std::fmt::{self, Display}; use std::iter; use rustc_data_structures::fx::IndexEntry; -use rustc_errors::{Diag, EmissionGuarantee}; +use rustc_errors::Diag; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_middle::ty::print::RegionHighlightMode; @@ -105,7 +105,7 @@ impl RegionName { } } - pub(crate) fn highlight_region_name(&self, diag: &mut Diag<'_, G>) { + pub(crate) fn highlight_region_name(&self, diag: &mut Diag<'_, G>) { match &self.source { RegionNameSource::NamedLateParamRegion(span) | RegionNameSource::NamedEarlyParamRegion(span) => { diff --git a/compiler/rustc_builtin_macros/src/diagnostics.rs b/compiler/rustc_builtin_macros/src/diagnostics.rs index 4ebc39f1976fb..604341c3e7bbf 100644 --- a/compiler/rustc_builtin_macros/src/diagnostics.rs +++ b/compiler/rustc_builtin_macros/src/diagnostics.rs @@ -1,8 +1,7 @@ use rustc_errors::codes::*; use rustc_errors::formatting::DiagMessageAddArg; use rustc_errors::{ - Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, MultiSpan, SingleLabelManySpans, - Subdiagnostic, msg, + Diag, DiagCtxtHandle, Diagnostic, Level, MultiSpan, SingleLabelManySpans, Subdiagnostic, msg, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Ident, Span, Symbol}; @@ -543,7 +542,7 @@ pub(crate) struct EnvNotDefinedWithUserMessage { } // Hand-written implementation to support custom user messages. -impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for EnvNotDefinedWithUserMessage { +impl<'a, G> Diagnostic<'a, G> for EnvNotDefinedWithUserMessage { #[track_caller] fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let mut diag = Diag::new(dcx, level, self.msg_from_user.to_string()); @@ -774,7 +773,7 @@ pub(crate) struct FormatUnusedArg { // Allow the singular form to be a subdiagnostic of the multiple-unused // form of diagnostic. impl Subdiagnostic for FormatUnusedArg { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.span_label( self.span, msg!( @@ -958,7 +957,7 @@ pub(crate) struct AsmClobberNoReg { pub(crate) clobbers: Vec, } -impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AsmClobberNoReg { +impl<'a, G> Diagnostic<'a, G> for AsmClobberNoReg { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { Diag::new( dcx, diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index a8a426d759057..857d0b774879d 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -3,7 +3,7 @@ use std::{assert_matches, iter}; -use rustc_ast::{self as ast, GenericParamKind, attr, join_path_idents}; +use rustc_ast::{self as ast, GenericParamKind, Mutability, Safety, attr, join_path_idents}; use rustc_ast_pretty::pprust; use rustc_attr_ir::{Attribute, AttributeKind}; use rustc_attr_parsing::AttributeParser; @@ -274,16 +274,21 @@ pub(crate) fn expand_test_or_bench( // #[doc(hidden)] cx.attr_nested_word(sym::doc, sym::hidden, attr_sp), ], - // const $ident: test::TestDescAndFn = - ast::ItemKind::Const( - ast::ConstItem { - defaultness: ast::Defaultness::Implicit, + // static $ident: test::TestDescAndFn = + // We use a static because these things only exist to have references taken + // to them for the test case array. No reason to introduce tons of promoteds for that. + // Promoteds have the advantage that they can be merged to save space, but every one + // of these points to a different function so that will not happen. + ast::ItemKind::Static( + ast::StaticItem { ident: Ident::new(fn_.ident.name, sp), - generics: ast::Generics::default(), ty: cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))), + safety: Safety::Default, + mutability: Mutability::Not, define_opaque: None, + eii_impl: None, // test::TestDescAndFn { - body: Some( + expr: Some( cx.expr_struct( sp, test_path("TestDescAndFn"), diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index 1df2ac9761420..99b0adb6f336a 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -266,7 +266,7 @@ fn generate_test_harness( /// #[rustc_main] /// pub fn main() { /// extern crate test; -/// test::test_main_static(&[ +/// test::test_main_env_args(&[ /// &test_const1, /// &test_const2, /// &test_const3, @@ -286,16 +286,16 @@ fn generate_test_harness( /// /// [`TestCtxt::reexport_test_harness_main`] provides a different name for the `main` /// function and [`TestCtxt::test_runner`] provides a path that replaces -/// `test::test_main_static`. +/// `test::test_main_env_args`. fn mk_main(cx: &mut TestCtxt<'_>) -> Box { let sp = cx.def_site; let ecx = &cx.ext_cx; let test_ident = Ident::new(sym::test, sp); let runner_name = - if cx.panic_strategy.unwinds() { "test_main_static" } else { "test_main_static_abort" }; + if cx.panic_strategy.unwinds() { "test_main_env_args" } else { "test_main_env_args_abort" }; - // test::test_main_static(...) + // test::test_main_env_args(...) let mut test_runner = cx.test_runner.clone().unwrap_or_else(|| { ecx.path(sp, vec![test_ident, Ident::from_str_and_span(runner_name, sp)]) }); diff --git a/compiler/rustc_codegen_llvm/src/back/mod.rs b/compiler/rustc_codegen_llvm/src/back/mod.rs index 6cb89f80ab89a..de6007c17bfff 100644 --- a/compiler/rustc_codegen_llvm/src/back/mod.rs +++ b/compiler/rustc_codegen_llvm/src/back/mod.rs @@ -1,5 +1,6 @@ pub(crate) mod archive; pub(crate) mod lto; +pub(crate) mod owned_mc_subtarget_info; pub(crate) mod owned_target_machine; mod profiling; pub(crate) mod write; diff --git a/compiler/rustc_codegen_llvm/src/back/owned_mc_subtarget_info.rs b/compiler/rustc_codegen_llvm/src/back/owned_mc_subtarget_info.rs new file mode 100644 index 0000000000000..f57368e755add --- /dev/null +++ b/compiler/rustc_codegen_llvm/src/back/owned_mc_subtarget_info.rs @@ -0,0 +1,49 @@ +use std::ffi::CStr; +use std::ptr::NonNull; + +use rustc_data_structures::small_c_str::SmallCStr; + +use crate::diagnostics::LlvmError; +use crate::llvm; + +/// Responsible for safely creating and disposing llvm::MCSubtargetInfo via ffi functions. +/// Not cloneable as there is no clone function for llvm::MCSubtargetInfo. +pub(crate) struct OwnedMCSubtargetInfo { + info_unique: NonNull, +} + +impl OwnedMCSubtargetInfo { + pub(crate) fn new( + triple: &CStr, + cpu: &CStr, + features: &CStr, + ) -> Result> { + // SAFETY: llvm::LLVMRustCreateMCSubtargetInfo copies pointed-to data. + let info_ptr = unsafe { + llvm::LLVMRustCreateMCSubtargetInfo(triple.as_ptr(), cpu.as_ptr(), features.as_ptr()) + }; + + NonNull::new(info_ptr) + .map(|info_unique| Self { info_unique }) + .ok_or_else(|| LlvmError::CreateMCSubtargetInfo { triple: SmallCStr::from(triple) }) + } + + pub(crate) fn has_feature(&self, feature: &CStr) -> bool { + // SAFETY: `new` ensures we have a valid pointer created by + // `llvm::LLVMRustCreateMCSubtargetInfo`. + unsafe { + llvm::LLVMRustMCSubtargetInfoHasFeature(self.info_unique.as_ref(), feature.as_ptr()) + } + } +} + +impl Drop for OwnedMCSubtargetInfo { + fn drop(&mut self) { + // SAFETY: `new` ensures we have a valid pointer created by + // `llvm::LLVMRustCreateMCSubtargetInfo` and `OwnedMCSubtargetInfo` is not copyable so + // there is no double free or use after free. + unsafe { + llvm::LLVMRustDisposeMCSubtargetInfo(self.info_unique); + } + } +} diff --git a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs index 350d4ce9ee331..5a1dc8080c2c1 100644 --- a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs +++ b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs @@ -1,5 +1,4 @@ use std::ffi::CStr; -use std::marker::PhantomData; use std::ptr::NonNull; use rustc_data_structures::small_c_str::SmallCStr; @@ -9,10 +8,8 @@ use crate::llvm; /// Responsible for safely creating and disposing llvm::TargetMachine via ffi functions. /// Not cloneable as there is no clone function for llvm::TargetMachine. -#[repr(transparent)] pub struct OwnedTargetMachine { tm_unique: NonNull, - phantom: PhantomData, } impl OwnedTargetMachine { @@ -41,7 +38,7 @@ impl OwnedTargetMachine { use_wasm_eh: bool, large_data_threshold: u64, ) -> Result> { - // SAFETY: llvm::LLVMRustCreateTargetMachine copies pointed to data + // SAFETY: llvm::LLVMRustCreateTargetMachine copies pointed-to data. let tm_ptr = unsafe { llvm::LLVMRustCreateTargetMachine( triple.as_ptr(), @@ -71,7 +68,7 @@ impl OwnedTargetMachine { }; NonNull::new(tm_ptr) - .map(|tm_unique| Self { tm_unique, phantom: PhantomData }) + .map(|tm_unique| Self { tm_unique }) .ok_or_else(|| LlvmError::CreateTargetMachine { triple: SmallCStr::from(triple) }) } diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 90b2cab5b63e2..bdf1bb2f24f6d 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -100,17 +100,12 @@ fn write_output_file<'ll>( result.into_result().unwrap_or_else(|()| llvm_err(dcx, LlvmError::WriteOutput { path: output })) } -/// If `for_cfg` is `true` then we are creating this machine for the purpose of populating -/// [`rustc_codegen_ssa::TargetConfig`] based on what LLVM actually enables in this configuration. -/// `-Ctarget-feature` should be ignored in that case since it is already processed separately. -pub(crate) fn create_informational_target_machine( - sess: &Session, - for_cfg: bool, -) -> OwnedTargetMachine { +pub(crate) fn create_informational_target_machine(sess: &Session) -> OwnedTargetMachine { let config = TargetMachineFactoryConfig { split_dwarf_file: None, output_obj_file: None }; // Can't use query system here quite yet because this function is invoked before the query // system/tcx is set up. - let features = llvm_util::global_llvm_features(sess, for_cfg); + let features = llvm_util::global_llvm_features(sess, /* for_cfg */ false); + target_machine_factory(sess, config::OptLevel::No, &features)(sess.dcx(), config) } @@ -212,7 +207,6 @@ pub(crate) fn target_machine_factory( let code_model = to_llvm_code_model(sess.code_model()); - // This is used to set cfg_has_threads, so all logic must be in this method. let singlethread = sess.target.singlethread(&sess.internal_target_features); let triple = SmallCStr::new(&versioned_llvm_target(sess)); diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 3b58a7f00146b..d4d1c950ec3f8 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -232,7 +232,7 @@ pub(crate) unsafe fn create_module<'ll>( // Ensure the data-layout values hardcoded remain the defaults. { - let tm = crate::back::write::create_informational_target_machine(sess, false); + let tm = crate::back::write::create_informational_target_machine(sess); unsafe { llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, tm.raw()); } diff --git a/compiler/rustc_codegen_llvm/src/diagnostics.rs b/compiler/rustc_codegen_llvm/src/diagnostics.rs index 70a14288aec0c..78e502f13af75 100644 --- a/compiler/rustc_codegen_llvm/src/diagnostics.rs +++ b/compiler/rustc_codegen_llvm/src/diagnostics.rs @@ -2,9 +2,7 @@ use std::ffi::{CString, c_uint}; use std::path::Path; use rustc_data_structures::small_c_str::SmallCStr; -use rustc_errors::{ - Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, format_diag_message, msg, -}; +use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level, format_diag_message, msg}; use rustc_macros::Diagnostic; use rustc_span::Span; @@ -22,7 +20,7 @@ pub(crate) struct SanitizerMemtagRequiresMte; pub(crate) struct ParseTargetMachineConfig<'a>(pub LlvmError<'a>); -impl Diagnostic<'_, G> for ParseTargetMachineConfig<'_> { +impl Diagnostic<'_, G> for ParseTargetMachineConfig<'_> { fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { // Reuse the formatted primary message from `LlvmError` without emitting it. let diag: Diag<'_, ()> = self.0.into_diag(dcx, level); @@ -123,6 +121,8 @@ pub(crate) enum LlvmError<'a> { WriteOutput { path: &'a Path }, #[diag("could not create LLVM TargetMachine for triple: {$triple}")] CreateTargetMachine { triple: SmallCStr }, + #[diag("could not create LLVM MCSubtargetInfo for triple: {$triple}")] + CreateMCSubtargetInfo { triple: SmallCStr }, #[diag("failed to run LLVM passes")] RunLlvmPasses, #[diag("failed to write LLVM IR to {$path}")] @@ -141,7 +141,7 @@ pub(crate) enum LlvmError<'a> { pub(crate) struct WithLlvmError<'a>(pub LlvmError<'a>, pub String); -impl Diagnostic<'_, G> for WithLlvmError<'_> { +impl Diagnostic<'_, G> for WithLlvmError<'_> { fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { use LlvmError::*; let msg_with_llvm_err = match &self.0 { @@ -149,6 +149,9 @@ impl Diagnostic<'_, G> for WithLlvmError<'_> { CreateTargetMachine { .. } => { msg!("could not create LLVM TargetMachine for triple: {$triple}: {$llvm_err}") } + CreateMCSubtargetInfo { .. } => { + msg!("could not create LLVM MCSubtargetInfo for triple: {$triple}: {$llvm_err}") + } RunLlvmPasses => msg!("failed to run LLVM passes: {$llvm_err}"), WriteIr { .. } => msg!("failed to write LLVM IR to {$path}: {$llvm_err}"), PrepareThinLtoContext => { diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index ca16d33b90256..ddc5db619ea5f 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -248,7 +248,7 @@ impl CodegenBackend for LlvmCodegenBackend { fn provide(&self, providers: &mut Providers) { providers.queries.global_backend_features = - |tcx, ()| llvm_util::global_llvm_features(tcx.sess, false) + |tcx, ()| llvm_util::global_llvm_features(tcx.sess, /* for_cfg */ false) } fn print(&self, req: &PrintRequest, out: &mut String, sess: &Session) { @@ -496,7 +496,7 @@ impl ModuleLlvm { ModuleLlvm { llmod_raw, llcx, - tm: ManuallyDrop::new(create_informational_target_machine(tcx.sess, false)), + tm: ManuallyDrop::new(create_informational_target_machine(tcx.sess)), } } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index abacef3710f4e..d1cdf7bada0b1 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -720,6 +720,7 @@ unsafe extern "C" { pub type TargetMachine; } unsafe extern "C" { + pub(crate) type MCSubtargetInfo; pub(crate) type Twine; pub(crate) type DiagnosticInfo; pub(crate) type SMDiagnostic; @@ -2372,7 +2373,6 @@ unsafe extern "C" { pub(crate) fn LLVMRustWriteTypeToString(Type: &Type, s: &RustString); pub(crate) fn LLVMRustWriteValueToString(value_ref: &Value, s: &RustString); - pub(crate) fn LLVMRustHasFeature(T: &TargetMachine, s: *const c_char) -> bool; pub(crate) fn LLVMRustTargetHasMnemonic(T: &TargetMachine, s: *const c_char) -> bool; pub(crate) fn LLVMRustPrintTargetCPUs(TM: &TargetMachine, OutStr: &RustString); @@ -2414,6 +2414,19 @@ unsafe extern "C" { LargeDataThreshold: u64, ) -> *mut TargetMachine; + pub(crate) fn LLVMRustCreateMCSubtargetInfo( + TripleStr: *const c_char, + CPU: *const c_char, + Features: *const c_char, + ) -> *mut MCSubtargetInfo; + + pub(crate) fn LLVMRustMCSubtargetInfoHasFeature( + MCInfo: &MCSubtargetInfo, + Feature: *const c_char, + ) -> bool; + + pub(crate) fn LLVMRustDisposeMCSubtargetInfo(MCInfo: ptr::NonNull); + pub(crate) fn LLVMRustAddLibraryInfo<'a>( T: &TargetMachine, PM: &PassManager<'a>, diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 223cbf2aae31f..677058ff80d67 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -6,6 +6,7 @@ use std::sync::Once; use std::{ptr, slice, str}; use libc::c_int; +use rustc_codegen_ssa::back::versioned_llvm_target; use rustc_codegen_ssa::base::wants_wasm_eh; use rustc_codegen_ssa::target_features::internal_target_features; use rustc_codegen_ssa::{TargetConfig, target_features}; @@ -20,7 +21,8 @@ use rustc_target::spec::{ }; use smallvec::{SmallVec, smallvec}; -use crate::back::write::create_informational_target_machine; +use crate::back::owned_mc_subtarget_info::OwnedMCSubtargetInfo; +use crate::back::write::{create_informational_target_machine, llvm_err}; use crate::{diagnostics, llvm}; static INIT: Once = Once::new(); @@ -337,7 +339,14 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option TargetConfig { - let target_machine = create_informational_target_machine(sess, true); + require_inited(); + let target_features = global_llvm_features(sess, /* for_cfg */ true); + + let triple = SmallCStr::new(&versioned_llvm_target(sess)); + let cpu = SmallCStr::new(target_cpu(sess)); + let features = CString::new(target_features.join(",")).unwrap(); + let mc_subtarget_info = OwnedMCSubtargetInfo::new(&triple, &cpu, &features) + .unwrap_or_else(|err| llvm_err(sess.dcx(), err)); let internal_target_features = internal_target_features( sess, @@ -348,16 +357,17 @@ pub(crate) fn target_config(sess: &Session) -> TargetConfig { }, |feature| { // This closure determines whether the target CPU has the feature according to LLVM. We - // do *not* consider the `-Ctarget-feature`s here, as that will be handled later in + // do *not* consider the `-Ctarget-feature`s here (that's why we passed `for_cfg: true` + // to `global_llvm_features` above) because that will be handled later in // `internal_target_features`. if let Some(feat) = to_llvm_features(sess, feature) { // All the LLVM features this expands to must be enabled. for llvm_feature in feat { let cstr = SmallCStr::new(llvm_feature); - // `LLVMRustHasFeature` is moderately expensive. On targets with many + // `has_feature` is moderately expensive. On targets with many // features (e.g. x86) these calls take a non-trivial fraction of runtime // when compiling very small programs. - if !unsafe { llvm::LLVMRustHasFeature(target_machine.raw(), cstr.as_ptr()) } { + if !mc_subtarget_info.has_feature(&cstr) { return false; } } @@ -500,7 +510,7 @@ fn llvm_target_features(tm: &llvm::TargetMachine) -> Vec<(&str, &str)> { pub(crate) fn print(req: &PrintRequest, out: &mut String, sess: &Session) { require_inited(); - let tm = create_informational_target_machine(sess, false); + let tm = create_informational_target_machine(sess); match req.kind { PrintKind::TargetCPUs => print_target_cpus(sess, tm.raw(), out), PrintKind::TargetFeatures => print_target_features(sess, tm.raw(), out), @@ -518,10 +528,11 @@ fn print_target_cpus(sess: &Session, tm: &llvm::TargetMachine, out: &mut String) cpu_name: &'a str, remark: String, } - // Compare CPU against current target to label the default. + // Compare CPU against current target to label the default. Do not print it if + // `need_explicit_cpu` is set, because in that case the concept of default makes less sense. let target_cpu = handle_native(&sess.target.cpu); let make_remark = |cpu_name| { - if cpu_name == target_cpu { + if cpu_name == target_cpu && !sess.target.need_explicit_cpu { // FIXME(#132514): This prints the LLVM target string, which can be // different from the Rust target string. Is that intended? let target = &sess.target.llvm_target; @@ -797,7 +808,7 @@ pub(crate) fn tune_cpu(sess: &Session) -> Option<&str> { pub(crate) fn target_has_mnemonic(sess: &Session, mnemonic: &str) -> bool { require_inited(); - let tm = create_informational_target_machine(sess, false); + let tm = create_informational_target_machine(sess); let cstr = SmallCStr::new(mnemonic); unsafe { llvm::LLVMRustTargetHasMnemonic(tm.raw(), cstr.as_ptr()) } } diff --git a/compiler/rustc_codegen_ssa/src/diagnostics.rs b/compiler/rustc_codegen_ssa/src/diagnostics.rs index 4c9c78f909230..8aa2da904bd07 100644 --- a/compiler/rustc_codegen_ssa/src/diagnostics.rs +++ b/compiler/rustc_codegen_ssa/src/diagnostics.rs @@ -9,8 +9,7 @@ use std::process::ExitStatus; use rustc_abi::NumScalableVectors; use rustc_errors::codes::*; use rustc_errors::{ - Diag, DiagArgValue, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, IntoDiagArg, - Level, msg, + Diag, DiagArgValue, DiagCtxtHandle, DiagSymbolList, Diagnostic, IntoDiagArg, Level, msg, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::ty::Ty; @@ -203,7 +202,7 @@ pub enum LinkRlibError { pub(crate) struct ThorinErrorWrapper(pub thorin::Error); -impl Diagnostic<'_, G> for ThorinErrorWrapper { +impl Diagnostic<'_, G> for ThorinErrorWrapper { fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let build = |msg| Diag::new(dcx, level, msg); match self.0 { @@ -335,7 +334,7 @@ pub(crate) struct LinkingFailed<'a> { pub sysroot_dir: PathBuf, } -impl Diagnostic<'_, G> for LinkingFailed<'_> { +impl Diagnostic<'_, G> for LinkingFailed<'_> { fn into_diag(mut self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new(dcx, level, msg!("linking with `{$linker_path}` failed: {$exit_status}")); @@ -464,7 +463,7 @@ pub(crate) struct LinkExeUnexpectedError; pub(crate) struct LinkExeStatusStackBufferOverrun; -impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for LinkExeStatusStackBufferOverrun { +impl<'a, G> Diagnostic<'a, G> for LinkExeStatusStackBufferOverrun { fn into_diag(self, dcx: rustc_errors::DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let mut diag = Diag::new(dcx, level, msg!("0xc0000409 is `STATUS_STACK_BUFFER_OVERRUN`")); diag.note(msg!( @@ -1266,7 +1265,7 @@ pub(crate) struct TargetFeatureDisableOrEnable<'a> { #[help("add the missing features in a `target_feature` attribute")] pub(crate) struct MissingFeatures; -impl Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_> { +impl Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_> { fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new( dcx, diff --git a/compiler/rustc_const_eval/src/diagnostics.rs b/compiler/rustc_const_eval/src/diagnostics.rs index 9faf9a59fc22a..b4dd468d7c9ee 100644 --- a/compiler/rustc_const_eval/src/diagnostics.rs +++ b/compiler/rustc_const_eval/src/diagnostics.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; use rustc_errors::codes::*; use rustc_errors::formatting::DiagMessageAddArg; -use rustc_errors::{Diag, DiagArgValue, EmissionGuarantee, MultiSpan, Subdiagnostic, msg}; +use rustc_errors::{Diag, DiagArgValue, MultiSpan, Subdiagnostic, msg}; use rustc_hir::ConstContext; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::ty::{Mutability, Ty}; @@ -317,7 +317,7 @@ pub(crate) struct FrameNote { } impl Subdiagnostic for FrameNote { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut span: MultiSpan = self.span.into(); if self.has_label && !self.span.is_dummy() { span.push_span_label(self.span, msg!("the failure occurred here")); diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index d935299769871..ae4bd0426545d 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -20,67 +20,23 @@ use crate::{ Suggestions, }; -/// Trait for types that `Diag::emit` can return as a "guarantee" (or "proof") -/// token that the emission happened. -pub trait EmissionGuarantee: Sized { - /// This exists so that bugs and fatal errors can both result in `!` (an - /// abort) when emitted, but have different aborting behaviour. - type EmitResult = Self; - - /// Implementation of `Diag::emit`, fully controlled by each `impl` of - /// `EmissionGuarantee`, to make it impossible to create a value of - /// `Self::EmitResult` without actually performing the emission. - #[track_caller] - fn emit_producing_guarantee(diag: Diag<'_, Self>) -> Self::EmitResult; -} - -impl EmissionGuarantee for ErrorGuaranteed { - fn emit_producing_guarantee(diag: Diag<'_, Self>) -> Self::EmitResult { - diag.emit_producing_error_guaranteed() - } -} - -impl EmissionGuarantee for () { - fn emit_producing_guarantee(diag: Diag<'_, Self>) -> Self::EmitResult { - diag.emit_producing_nothing(); - } -} - /// Marker type which enables implementation of `create_bug` and `emit_bug` functions for /// bug diagnostics. #[derive(Copy, Clone)] pub struct BugAbort; -impl EmissionGuarantee for BugAbort { - type EmitResult = !; - - fn emit_producing_guarantee(diag: Diag<'_, Self>) -> Self::EmitResult { - diag.emit_producing_nothing(); - panic::panic_any(ExplicitBug); - } -} - /// Marker type which enables implementation of `create_fatal` and `emit_fatal` functions for /// fatal diagnostics. #[derive(Copy, Clone)] pub struct FatalAbort; -impl EmissionGuarantee for FatalAbort { - type EmitResult = !; - - fn emit_producing_guarantee(diag: Diag<'_, Self>) -> Self::EmitResult { - diag.emit_producing_nothing(); - crate::FatalError.raise() - } -} - /// Trait implemented by error types. This is rarely implemented manually. Instead, use /// `#[derive(Diagnostic)]` -- see [rustc_macros::Diagnostic]. /// /// When implemented manually, it should be generic over the emission /// guarantee, i.e.: /// ```ignore (fragment) -/// impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for Foo { ... } +/// impl<'a, G> Diagnostic<'a, G> for Foo { ... } /// ``` /// rather than being specific: /// ```ignore (fragment) @@ -95,7 +51,7 @@ impl EmissionGuarantee for FatalAbort { /// rather than the `Diagnostic` impl. /// - Derived impls are always generic, and it's good for the hand-written /// impls to be consistent with them. -pub trait Diagnostic<'a, G: EmissionGuarantee = ErrorGuaranteed> { +pub trait Diagnostic<'a, G = ErrorGuaranteed> { /// Write out as a diagnostic out of `DiagCtxt`. #[must_use] #[track_caller] @@ -105,7 +61,6 @@ pub trait Diagnostic<'a, G: EmissionGuarantee = ErrorGuaranteed> { impl<'a, T, G> Diagnostic<'a, G> for Spanned where T: Diagnostic<'a, G>, - G: EmissionGuarantee, { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { self.node.into_diag(dcx, level).with_span(self.span) @@ -127,7 +82,7 @@ impl<'a, F: FnOnce(&mut Diag<'_, ()>)> Diagnostic<'a, ()> for DiagDecorator { /// `#[derive(Subdiagnostic)]` -- see [rustc_macros::Subdiagnostic]. pub trait Subdiagnostic { /// Add a subdiagnostic to an existing diagnostic. - fn add_to_diag(self, diag: &mut Diag<'_, G>); + fn add_to_diag(self, diag: &mut Diag<'_, G>); } #[derive(Clone, Debug, Encodable, Decodable)] @@ -433,16 +388,16 @@ pub struct Subdiag { /// Wraps a `DiagInner`, adding some useful things. /// - The `dcx` field, allowing it to (a) emit itself, and (b) do a drop check /// that it has been emitted or cancelled. -/// - The `EmissionGuarantee`, which determines the type returned from `emit`. +/// - `G`, which determines the type returned from `emit`. /// /// Each constructed `Diag` must be consumed by a function such as `emit`, -/// `cancel`, `delay_as_bug`, or `into_diag`. A panic occurs if a `Diag` -/// is dropped without being consumed by one of these functions. +/// `cancel`, or `delay_as_bug`. A panic occurs if a `Diag` is dropped without +/// being consumed by one of these functions. /// /// If there is some state in a downstream crate you would like to access in /// the methods of `Diag` here, consider extending `DiagCtxtFlags`. #[must_use] -pub struct Diag<'a, G: EmissionGuarantee = ErrorGuaranteed> { +pub struct Diag<'a, G = ErrorGuaranteed> { pub dcx: DiagCtxtHandle<'a>, /// Why the `Option`? It is always `Some` until the `Diag` is consumed via @@ -465,7 +420,7 @@ impl !Clone for Diag<'_, G> {} rustc_data_structures::static_assert_size!(Diag<'_, ()>, 3 * size_of::()); -impl Deref for Diag<'_, G> { +impl Deref for Diag<'_, G> { type Target = DiagInner; fn deref(&self) -> &DiagInner { @@ -473,18 +428,80 @@ impl Deref for Diag<'_, G> { } } -impl DerefMut for Diag<'_, G> { +impl DerefMut for Diag<'_, G> { fn deref_mut(&mut self) -> &mut DiagInner { self.diag.as_mut().unwrap() } } -impl Debug for Diag<'_, G> { +impl Debug for Diag<'_, G> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.diag.fmt(f) } } +impl Diag<'_, BugAbort> { + #[track_caller] + pub fn emit(self) -> ! { + assert_eq!(self.level, Level::Bug); + self.emit_producing_nothing(); + panic::panic_any(ExplicitBug); + } +} + +impl Diag<'_, FatalAbort> { + #[track_caller] + pub fn emit(self) -> ! { + assert_eq!(self.level, Level::Fatal); + self.emit_producing_nothing(); + crate::FatalError.raise() + } +} + +impl Diag<'_, ErrorGuaranteed> { + #[track_caller] + pub fn emit(self) -> ErrorGuaranteed { + self.emit_producing_error_guaranteed() + } + + /// Emit the diagnostic unless `delay` is true, + /// in which case the emission will be delayed as a bug. + /// + /// See `emit` and `delay_as_bug` for details. + #[track_caller] + pub fn emit_unless_delay(mut self, delay: bool) -> ErrorGuaranteed { + if delay { + self.downgrade_to_delayed_bug(); + } + self.emit() + } + + /// Delay emission of this diagnostic as a bug. + /// + /// This can be useful in contexts where an error indicates a bug but + /// typically this only happens when other compilation errors have already + /// happened. In those cases this can be used to defer emission of this + /// diagnostic as a bug in the compiler only if no other errors have been + /// emitted. + /// + /// In the meantime, though, callsites are required to deal with the "bug" + /// locally in whichever way makes the most sense. + #[track_caller] + pub fn delay_as_bug(mut self) -> ErrorGuaranteed { + self.downgrade_to_delayed_bug(); + self.emit() + } +} + +impl Diag<'_, ()> { + #[track_caller] + pub fn emit(self) { + assert_ne!(self.level, Level::Bug); + assert_ne!(self.level, Level::Fatal); + self.emit_producing_nothing(); + } +} + /// `Diag` impls many `&mut self -> &mut Self` methods. Each one modifies an /// existing diagnostic, either in a standalone fashion, e.g. /// `err.code(code);`, or in a chained fashion to make multiple modifications, @@ -528,7 +545,7 @@ macro_rules! with_fn { }; } -impl<'a, G: EmissionGuarantee> Diag<'a, G> { +impl<'a, G> Diag<'a, G> { #[track_caller] pub fn new(dcx: DiagCtxtHandle<'a>, level: Level, message: impl Into) -> Self { Self::new_diagnostic(dcx, DiagInner::new(level, message)) @@ -566,13 +583,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { self.level = Level::DelayedBug; } - /// Make emitting this diagnostic fatal - /// - /// Changes the level of this diagnostic to Fatal, and importantly also changes the emission guarantee. - /// This is sound for errors that would otherwise be printed, but now simply exit the process instead. - /// This function still gives an emission guarantee, the guarantee is now just that it exits fatally. - /// For delayed bugs this is different, since those are buffered. If we upgrade one to fatal, another - /// might now be ignored. + /// Make emitting this diagnostic fatal. #[track_caller] pub fn upgrade_to_fatal(mut self) -> Diag<'a, FatalAbort> { assert!( @@ -1282,13 +1293,13 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { self } - /// Most `emit_producing_guarantee` functions use this as a starting point. + /// Most `emit` methods use this as a starting point. fn emit_producing_nothing(mut self) { let diag = self.take_diag(); self.dcx.emit_diagnostic(diag); } - /// `ErrorGuaranteed::emit_producing_guarantee` uses this. + /// `Diag<'_, ErrorGuaranteed>::emit` uses this. fn emit_producing_error_guaranteed(mut self) -> ErrorGuaranteed { let diag = self.take_diag(); @@ -1310,24 +1321,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { guar.unwrap() } - /// Emit and consume the diagnostic. - #[track_caller] - pub fn emit(self) -> G::EmitResult { - G::emit_producing_guarantee(self) - } - - /// Emit the diagnostic unless `delay` is true, - /// in which case the emission will be delayed as a bug. - /// - /// See `emit` and `delay_as_bug` for details. - #[track_caller] - pub fn emit_unless_delay(mut self, delay: bool) -> G::EmitResult { - if delay { - self.downgrade_to_delayed_bug(); - } - self.emit() - } - /// Cancel and consume the diagnostic. (A diagnostic must either be emitted or /// cancelled or it will panic when dropped). pub fn cancel(mut self) { @@ -1347,27 +1340,11 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { let diag = self.take_diag(); self.dcx.stash_diagnostic(span, key, diag) } - - /// Delay emission of this diagnostic as a bug. - /// - /// This can be useful in contexts where an error indicates a bug but - /// typically this only happens when other compilation errors have already - /// happened. In those cases this can be used to defer emission of this - /// diagnostic as a bug in the compiler only if no other errors have been - /// emitted. - /// - /// In the meantime, though, callsites are required to deal with the "bug" - /// locally in whichever way makes the most sense. - #[track_caller] - pub fn delay_as_bug(mut self) -> G::EmitResult { - self.downgrade_to_delayed_bug(); - self.emit() - } } /// Destructor bomb: every `Diag` must be consumed (emitted, cancelled, etc.) /// or we emit a bug. -impl Drop for Diag<'_, G> { +impl Drop for Diag<'_, G> { fn drop(&mut self) { match self.diag.take() { Some(diag) if !panicking() => { diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index ba7569c51a07b..b002b8932a239 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -5,7 +5,7 @@ use rustc_macros::Subdiagnostic; use rustc_span::{Span, Symbol}; use crate::diagnostic::DiagLocation; -use crate::{Diag, EmissionGuarantee, Subdiagnostic}; +use crate::{Diag, Subdiagnostic}; impl IntoDiagArg for DiagLocation { fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { @@ -42,7 +42,7 @@ pub struct SingleLabelManySpans { pub label: &'static str, } impl Subdiagnostic for SingleLabelManySpans { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.span_labels(self.spans, self.label); } } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 3374d71461cfa..9ca0344058d7f 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -3,8 +3,6 @@ //! This module contains the code for creating and emitting diagnostics. // tidy-alphabetical-start -#![cfg_attr(bootstrap, feature(never_type))] -#![feature(associated_type_defaults)] #![feature(default_field_values)] #![feature(macro_metavar_expr_concat)] #![feature(negative_impls)] @@ -35,7 +33,7 @@ pub use codes::*; pub use decorate_diag::{BufferedEarlyLint, DecorateDiagCompat, LintBuffer}; pub use diagnostic::{ BugAbort, Diag, DiagDecorator, DiagInner, DiagLocation, DiagStyledString, Diagnostic, - EmissionGuarantee, FatalAbort, StringPart, Subdiag, Subdiagnostic, + FatalAbort, StringPart, Subdiag, Subdiagnostic, }; pub use diagnostic_impls::{ DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter, @@ -1565,19 +1563,19 @@ impl DelayedDiagInner { } } -/// | Level | is_error | EmissionGuarantee | Top-level | Used in lints? -/// | ----- | -------- | ----------------- | --------- | -------------- -/// | Bug | yes | BugAbort | yes | - -/// | Fatal | yes | FatalAbort | yes | - -/// | Error | yes | ErrorGuaranteed | yes | yes -/// | DelayedBug | yes | ErrorGuaranteed | yes | - -/// | ForceWarning | - | () | yes | lint-only -/// | Warning | - | () | yes | yes -/// | Note | - | () | rare | - -/// | Help | - | () | rare | - -/// | FailureNote | - | () | rare | - -/// | Allow | - | () | yes | lint-only -/// | Expect | - | () | yes | lint-only +/// | Level | is_error | emit return type | Top-level | Used in lints? +/// | ----- | -------- | ---------------- | --------- | -------------- +/// | Bug | yes | BugAbort | yes | - +/// | Fatal | yes | FatalAbort | yes | - +/// | Error | yes | ErrorGuaranteed | yes | yes +/// | DelayedBug | yes | ErrorGuaranteed | yes | - +/// | ForceWarning | - | () | yes | lint-only +/// | Warning | - | () | yes | yes +/// | Note | - | () | rare | - +/// | Help | - | () | rare | - +/// | FailureNote | - | () | rare | - +/// | Allow | - | () | yes | lint-only +/// | Expect | - | () | yes | lint-only /// #[derive(Copy, PartialEq, Eq, Clone, Hash, Debug, Encodable, Decodable)] pub enum Level { diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index fef10d297236f..c3c644d353369 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -4,7 +4,7 @@ use std::ops::ControlFlow; use rustc_abi::{ExternAbi, FieldIdx, MAX_SIMD_LANES, ScalableElt}; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::codes::*; -use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, MultiSpan}; +use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level, MultiSpan}; use rustc_hir as hir; use rustc_hir::attrs::ReprAttr::ReprPacked; use rustc_hir::attrs::lang_items::LangItem; @@ -41,7 +41,7 @@ use crate::check::wfcheck::{ use crate::collect::ItemCtxt; use crate::diagnostics; -fn add_abi_diag_help(abi: ExternAbi, diag: &mut Diag<'_, T>) { +fn add_abi_diag_help(abi: ExternAbi, diag: &mut Diag<'_, G>) { if let ExternAbi::Cdecl { unwind } = abi { let c_abi = ExternAbi::C { unwind }; diag.help(format!("use `extern {c_abi}` instead",)); @@ -1560,7 +1560,7 @@ fn check_scalable_vector(tcx: TyCtxt<'_>, span: Span, def_id: LocalDefId, scalab return; } ScalableElt::ElementCount(..) if fields.len() >= 2 => { - tcx.dcx().struct_span_err(span, "scalable vectors cannot have multiple fields").emit(); + tcx.dcx().span_err(span, "scalable vectors cannot have multiple fields"); return; } ScalableElt::Container if fields.is_empty() => { diff --git a/compiler/rustc_hir_analysis/src/diagnostics.rs b/compiler/rustc_hir_analysis/src/diagnostics.rs index a50aefd016059..1f0c493b881f1 100644 --- a/compiler/rustc_hir_analysis/src/diagnostics.rs +++ b/compiler/rustc_hir_analysis/src/diagnostics.rs @@ -3,8 +3,7 @@ use rustc_abi::ExternAbi; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, Level, - MultiSpan, listify, msg, + Applicability, Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, Level, MultiSpan, listify, msg, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::ty::{self, Ty}; @@ -468,7 +467,7 @@ pub(crate) struct MissingGenericParams { } // FIXME: This doesn't need to be a manual impl! -impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for MissingGenericParams { +impl<'a, G> Diagnostic<'a, G> for MissingGenericParams { #[track_caller] fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let mut err = Diag::new( @@ -2070,7 +2069,7 @@ pub(crate) struct UncoveredTyParam<'tcx> { pub(crate) local_ty: Option>, } -impl Diagnostic<'_, G> for UncoveredTyParam<'_> { +impl Diagnostic<'_, G> for UncoveredTyParam<'_> { fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let Self { param, local_ty } = self; diff --git a/compiler/rustc_hir_analysis/src/diagnostics/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/diagnostics/wrong_number_of_generic_args.rs index 8a38207884184..e995d4fdf697b 100644 --- a/compiler/rustc_hir_analysis/src/diagnostics/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/diagnostics/wrong_number_of_generic_args.rs @@ -1,6 +1,6 @@ use GenericArgsInfo::*; use rustc_errors::codes::*; -use rustc_errors::{Applicability, Diag, Diagnostic, EmissionGuarantee, MultiSpan, pluralize}; +use rustc_errors::{Applicability, Diag, Diagnostic, MultiSpan, pluralize}; use rustc_hir as hir; use rustc_middle::ty::{self as ty, AssocItem, AssocItems, TyCtxt}; use rustc_span::def_id::DefId; @@ -543,7 +543,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } /// Builds the `expected 1 type argument / supplied 2 type arguments` message. - fn notify(&self, err: &mut Diag<'_, impl EmissionGuarantee>) { + fn notify(&self, err: &mut Diag<'_, G>) { let (quantifier, bound) = self.get_quantifier_and_bound(); let provided_args = self.num_provided_args(); @@ -595,7 +595,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } } - fn suggest(&self, err: &mut Diag<'_, impl EmissionGuarantee>) { + fn suggest(&self, err: &mut Diag<'_, G>) { debug!( "suggest(self.provided {:?}, self.gen_args.span(): {:?})", self.num_provided_args(), @@ -623,7 +623,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { /// ```text /// type Map = HashMap; /// ``` - fn suggest_adding_args(&self, err: &mut Diag<'_, impl EmissionGuarantee>) { + fn suggest_adding_args(&self, err: &mut Diag<'_, G>) { if self.gen_args.parenthesized != hir::GenericArgsParentheses::No { return; } @@ -650,7 +650,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } } - fn suggest_adding_lifetime_args(&self, err: &mut Diag<'_, impl EmissionGuarantee>) { + fn suggest_adding_lifetime_args(&self, err: &mut Diag<'_, G>) { debug!("suggest_adding_lifetime_args(path_segment: {:?})", self.path_segment); let num_missing_args = self.num_missing_lifetime_args(); let num_params_to_take = num_missing_args; @@ -704,7 +704,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } } - fn suggest_adding_type_and_const_args(&self, err: &mut Diag<'_, impl EmissionGuarantee>) { + fn suggest_adding_type_and_const_args(&self, err: &mut Diag<'_, G>) { let num_missing_args = self.num_missing_type_or_const_args(); let msg = format!("add missing {} argument{}", self.kind(), pluralize!(num_missing_args)); @@ -764,10 +764,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { /// ```compile_fail /// Into::into::>(42) // suggests considering `Into::>::into(42)` /// ``` - fn suggest_moving_args_from_assoc_fn_to_trait( - &self, - err: &mut Diag<'_, impl EmissionGuarantee>, - ) { + fn suggest_moving_args_from_assoc_fn_to_trait(&self, err: &mut Diag<'_, G>) { let Some(trait_) = self.tcx.trait_of_assoc(self.def_id) else { return; }; @@ -820,9 +817,9 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } } - fn suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path( + fn suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path( &self, - err: &mut Diag<'_, impl EmissionGuarantee>, + err: &mut Diag<'_, G>, qpath: &'tcx hir::QPath<'tcx>, msg: String, num_assoc_fn_excess_args: usize, @@ -851,9 +848,9 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } } - fn suggest_moving_args_from_assoc_fn_to_trait_for_method_call( + fn suggest_moving_args_from_assoc_fn_to_trait_for_method_call( &self, - err: &mut Diag<'_, impl EmissionGuarantee>, + err: &mut Diag<'_, G>, trait_def_id: DefId, expr: &'tcx hir::Expr<'tcx>, msg: String, @@ -907,7 +904,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { /// ```text /// type Map = HashMap; /// ``` - fn suggest_removing_args_or_generics(&self, err: &mut Diag<'_, impl EmissionGuarantee>) { + fn suggest_removing_args_or_generics(&self, err: &mut Diag<'_, G>) { let num_provided_lt_args = self.num_provided_lifetime_args(); let num_provided_type_const_args = self.num_provided_type_or_const_args(); let unbound_assoc_items = self.get_unbound_associated_item(); @@ -1099,7 +1096,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } /// Builds the `type defined here` message. - fn show_definition(&self, err: &mut Diag<'_, impl EmissionGuarantee>) { + fn show_definition(&self, err: &mut Diag<'_, G>) { let Some(def_span) = self.tcx.def_ident_span(self.def_id) else { return }; if !self.tcx.sess.source_map().is_span_accessible(def_span) { return; @@ -1146,7 +1143,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } /// Add note if `impl Trait` is explicitly specified. - fn note_synth_provided(&self, err: &mut Diag<'_, impl EmissionGuarantee>) { + fn note_synth_provided(&self, err: &mut Diag<'_, G>) { if !self.is_synth_provided() { return; } @@ -1155,7 +1152,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } } -impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for WrongNumberOfGenericArgs<'_, '_> { +impl<'a, G> Diagnostic<'a, G> for WrongNumberOfGenericArgs<'_, '_> { fn into_diag( self, dcx: rustc_errors::DiagCtxtHandle<'a>, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs index 102a3013b38ad..beacb3f188cd9 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs @@ -2,8 +2,8 @@ use rustc_ast::TraitObjectSyntax; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, StashKey, - Suggestions, struct_span_code_err, + Applicability, Diag, DiagCtxtHandle, Diagnostic, Level, StashKey, Suggestions, + struct_span_code_err, }; use rustc_hir::attrs::lang_items::LangItem; use rustc_hir::def::{DefKind, Res}; @@ -739,7 +739,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } /// Make sure that we are in the condition to suggest the blanket implementation. - fn maybe_suggest_blanket_trait_impl( + fn maybe_suggest_blanket_trait_impl( &self, span: Span, hir_id: hir::HirId, diff --git a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs index 131812a364ebd..ca7e246a9e05b 100644 --- a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs +++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs @@ -97,12 +97,10 @@ pub(super) fn infer_clauses( } else { "overflow computing implied lifetime bounds".to_string() }; - tcx.dcx() - .struct_span_fatal( - clauses_added.iter().map(|id| tcx.def_span(*id)).collect::>(), - msg, - ) - .emit(); + tcx.dcx().span_fatal( + clauses_added.iter().map(|id| tcx.def_span(*id)).collect::>(), + msg, + ); } } diff --git a/compiler/rustc_hir_typeck/src/diagnostics.rs b/compiler/rustc_hir_typeck/src/diagnostics.rs index 2d4cf3d9b400d..3b7de7790ac02 100644 --- a/compiler/rustc_hir_typeck/src/diagnostics.rs +++ b/compiler/rustc_hir_typeck/src/diagnostics.rs @@ -6,8 +6,8 @@ use rustc_abi::ExternAbi; use rustc_ast::{AssignOpKind, Label}; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, DiagArgValue, DiagCtxtHandle, DiagSymbolList, Diagnostic, - EmissionGuarantee, IntoDiagArg, Level, MultiSpan, Subdiagnostic, msg, + Applicability, Diag, DiagArgValue, DiagCtxtHandle, DiagSymbolList, Diagnostic, IntoDiagArg, + Level, MultiSpan, Subdiagnostic, msg, }; use rustc_hir as hir; use rustc_hir::ExprKind; @@ -275,7 +275,7 @@ pub(crate) struct SuggestAnnotations { pub suggestions: Vec, } impl Subdiagnostic for SuggestAnnotations { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { if self.suggestions.is_empty() { return; } @@ -338,7 +338,7 @@ pub(crate) struct TypeMismatchFruTypo { } impl Subdiagnostic for TypeMismatchFruTypo { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.arg("expr", self.expr.as_deref().unwrap_or("NONE")); // Only explain that `a ..b` is a range if it's split up @@ -561,7 +561,7 @@ pub(crate) struct RemoveSemiForCoerce { } impl Subdiagnostic for RemoveSemiForCoerce { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut multispan: MultiSpan = self.semi.into(); multispan.push_span_label( self.expr, @@ -704,7 +704,7 @@ pub(crate) struct BreakNonLoop<'a> { pub break_expr_span: Span, } -impl<'a, G: EmissionGuarantee> Diagnostic<'_, G> for BreakNonLoop<'a> { +impl<'a, G> Diagnostic<'_, G> for BreakNonLoop<'a> { #[track_caller] fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new(dcx, level, msg!("`break` with value from a `{$kind}` loop")); @@ -906,7 +906,7 @@ pub(crate) enum CastUnknownPointerSub { } impl rustc_errors::Subdiagnostic for CastUnknownPointerSub { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { match self { CastUnknownPointerSub::To(span) => { let msg = msg!("needs more type information"); @@ -1202,7 +1202,7 @@ pub(crate) struct NakedFunctionsAsmBlock { pub non_asms: Vec, } -impl Diagnostic<'_, G> for NakedFunctionsAsmBlock { +impl Diagnostic<'_, G> for NakedFunctionsAsmBlock { #[track_caller] fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new( diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs index d63bffab88221..989c63ac2f34b 100644 --- a/compiler/rustc_hir_typeck/src/intrinsicck.rs +++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs @@ -78,7 +78,7 @@ fn check_transmute<'tcx>( let normalize = |ty: Unnormalized<'tcx, Ty<'tcx>>| -> Result, ErrorGuaranteed> { tcx.try_normalize_erasing_regions(typing_env, ty).map_err(|err| { let err = LayoutError::NormalizationFailure(ty.skip_normalization(), err); - tcx.dcx().struct_span_err(span, err.to_string()).emit() + tcx.dcx().span_err(span, err.to_string()) }) }; diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index de543ef0c53bc..5254123b1ca11 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -702,29 +702,6 @@ pub(crate) fn garbage_collect_session_directories( lock_file_to_session_dir.items().filter_map(|(lock_file_name, directory_name)| { debug!("garbage_collect_session_directories() - inspecting: {}", directory_name); - if directory_name.as_str() == current_session_directory_name { - // Skipping our own directory is, unfortunately, important for correctness. - // - // To summarize #147821: we will try to lock directories before deciding they can be - // garbage collected, but the ability of `flock::Lock` to detect a lock held *by the - // same process* varies across file locking APIs. Then, if our own session directory - // has become old enough to be eligible for GC, we are beholden to platform-specific - // details about detecting the our own lock on the session directory. - // - // POSIX `fcntl(F_SETLK)`-style file locks are maintained across a process. On - // systems where this is the mechanism for `flock::Lock`, there is no way to - // discover if an `flock::Lock` has been created in the same process on the same - // file. Attempting to set a lock on the lockfile again will succeed, even if the - // lock was set by another thread, on another file descriptor. Then we would - // garbage collect our own live directory, unable to tell it was locked perhaps by - // this same thread. - // - // It's not clear that `flock::Lock` can be fixed for this in general, and our own - // incremental session directory is the only one which this process may own, so skip - // it here and avoid the problem. We know it's not garbage anyway: we're using it. - return None; - } - let Ok(timestamp) = extract_timestamp_from_session_dir(directory_name) else { debug!( "found session-dir with malformed timestamp: {}", @@ -768,6 +745,31 @@ pub(crate) fn garbage_collect_session_directories( } } } else if is_old_enough_to_be_collected(timestamp) { + if directory_name.as_str() == current_session_directory_name { + // Skipping our own active directory is important for correctness. + // + // To summarize #147821: we will try to lock directories before deciding they can be + // garbage collected, but the ability of `flock::Lock` to detect a lock held *by the + // same process* varies across file locking APIs. Then, if our own session directory + // has become old enough to be eligible for GC, we are beholden to platform-specific + // details about detecting the our own lock on the session directory. + // + // POSIX `fcntl(F_SETLK)`-style file locks are maintained across a process. On + // systems where this is the mechanism for `flock::Lock`, there is no way to + // discover if an `flock::Lock` has been created in the same process on the same + // file. Attempting to set a lock on the lockfile again will succeed, even if the + // lock was set by another thread, on another file descriptor. Then we would + // garbage collect our own live directory, unable to tell it was locked perhaps by + // this same thread. + // + // It's not clear that `flock::Lock` can be fixed for this in general, and our own + // incremental session directory is the only one which this process may own, so skip + // it here and avoid the problem. We know it's not garbage anyway: we're using it. + // Once finalized, its lock is released. Include it in collection so we keep + // the newest completed session. + return None; + } + // When cleaning out "-working" session directories, i.e. // session directories that might still be in use by another // compiler instance, we only look a directories that are @@ -818,6 +820,10 @@ pub(crate) fn garbage_collect_session_directories( // Delete all but the most recent of the candidates all_except_most_recent(deletion_candidates).into_items().all(|(path, lock)| { + if path.file_name() == Some(current_session_directory_name) { + return true; + } + debug!("garbage_collect_session_directories() - deleting `{}`", path.display()); if let Err(err) = std_fs::remove_dir_all(&path) { diff --git a/compiler/rustc_lint/src/diagnostics.rs b/compiler/rustc_lint/src/diagnostics.rs index cfae7afd8f4f3..d96cadaca87eb 100644 --- a/compiler/rustc_lint/src/diagnostics.rs +++ b/compiler/rustc_lint/src/diagnostics.rs @@ -5,8 +5,8 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_errors::codes::*; use rustc_errors::formatting::DiagMessageAddArg; use rustc_errors::{ - Applicability, Diag, DiagCtxtHandle, DiagMessage, DiagStyledString, Diagnostic, - EmissionGuarantee, Level, Subdiagnostic, SuggestionStyle, msg, + Applicability, Diag, DiagCtxtHandle, DiagMessage, DiagStyledString, Diagnostic, Level, + Subdiagnostic, SuggestionStyle, msg, }; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -42,7 +42,7 @@ pub(crate) enum OverruledAttributeSub { } impl Subdiagnostic for OverruledAttributeSub { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { match self { OverruledAttributeSub::DefaultSource { id } => { diag.note(msg!("`forbid` lint level is the default for {$id}")); @@ -638,7 +638,7 @@ pub(crate) struct BuiltinUnpermittedTypeInitSub { } impl Subdiagnostic for BuiltinUnpermittedTypeInitSub { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut err = self.err; loop { if let Some(span) = err.span { @@ -689,7 +689,7 @@ pub(crate) struct BuiltinClashingExternSub<'a> { } impl Subdiagnostic for BuiltinClashingExternSub<'_> { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut expected_str = DiagStyledString::new(); expected_str.push(self.expected.fn_sig(self.tcx).to_string(), false); let mut found_str = DiagStyledString::new(); @@ -1363,7 +1363,7 @@ pub(crate) struct NonBindingLetSub { } impl Subdiagnostic for NonBindingLetSub { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let can_suggest_binding = self.drop_fn_start_end.is_some() || !self.is_assign_desugar; if can_suggest_binding { @@ -1740,7 +1740,7 @@ pub(crate) enum NonSnakeCaseDiagSub { } impl Subdiagnostic for NonSnakeCaseDiagSub { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { match self { NonSnakeCaseDiagSub::Label { span } => { diag.span_label(span, msg!("should have a snake_case name")); @@ -2924,7 +2924,7 @@ pub(crate) struct MismatchedLifetimeSyntaxes { pub suggestions: Vec, } -impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for MismatchedLifetimeSyntaxes { +impl<'a, G> Diagnostic<'a, G> for MismatchedLifetimeSyntaxes { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let counts = self.inputs.len() + self.outputs.len(); let message = match counts { @@ -3037,7 +3037,7 @@ impl MismatchedLifetimeSyntaxesSuggestion { } impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { use MismatchedLifetimeSyntaxesSuggestion::*; let style = |optional_alternative| { diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs index 47a3f528b9854..1cd701db7d10e 100644 --- a/compiler/rustc_lint/src/if_let_rescope.rs +++ b/compiler/rustc_lint/src/if_let_rescope.rs @@ -3,7 +3,7 @@ use std::ops::ControlFlow; use hir::intravisit::{self, Visitor}; use rustc_ast::Recovered; -use rustc_errors::{Applicability, Diag, EmissionGuarantee, Subdiagnostic, SuggestionStyle, msg}; +use rustc_errors::{Applicability, Diag, Subdiagnostic, SuggestionStyle, msg}; use rustc_hir::{self as hir, HirIdSet}; use rustc_lint_defs::{LintId, declare_lint, fcw, impl_lint_pass}; use rustc_macros::{Diagnostic, Subdiagnostic}; @@ -324,7 +324,7 @@ struct IfLetRescopeRewrite { } impl Subdiagnostic for IfLetRescopeRewrite { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut suggestions = vec![]; for match_head in self.match_heads { match match_head { diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 1bd5094c38f02..d181891cdfa54 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -89,15 +89,31 @@ extern "C" void LLVMRustTimeTraceProfilerFinish(const char *FileName) { timeTraceProfilerCleanup(); } -extern "C" bool LLVMRustHasFeature(LLVMTargetMachineRef TM, - const char *Feature) { - TargetMachine *Target = unwrap(TM); -#if LLVM_VERSION_GE(23, 0) - const MCSubtargetInfo &MCInfo = Target->getMCSubtargetInfo(); +extern "C" MCSubtargetInfo * +LLVMRustCreateMCSubtargetInfo(const char *TripleStr, const char *CPU, + const char *Features) { + std::string Error; + auto Trip = Triple(Triple::normalize(TripleStr)); + const llvm::Target *TheTarget = TargetRegistry::lookupTarget(Trip, Error); + if (TheTarget == nullptr) { + LLVMRustSetLastError(Error.c_str()); + return nullptr; + } + +#if LLVM_VERSION_GE(22, 0) + return TheTarget->createMCSubtargetInfo(Trip, CPU, Features); #else - const MCSubtargetInfo &MCInfo = *Target->getMCSubtargetInfo(); + return TheTarget->createMCSubtargetInfo(Trip.str(), CPU, Features); #endif - return MCInfo.checkFeatures(std::string("+") + Feature); +} + +extern "C" bool LLVMRustMCSubtargetInfoHasFeature(MCSubtargetInfo *MCInfo, + const char *Feature) { + return MCInfo->checkFeatures(std::string("+") + Feature); +} + +extern "C" void LLVMRustDisposeMCSubtargetInfo(MCSubtargetInfo *MCInfo) { + delete MCInfo; } /// Check whether the target has a specific assembly mnemonic like `ret` or diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs index ac777b37a4303..72e7423fc2d88 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs @@ -48,9 +48,7 @@ impl<'a> DiagnosticDerive<'a> { // A lifetime of `'a` causes conflicts, but `_sess` is fine. structure.gen_impl(quote! { - gen impl<'_sess, G> rustc_errors::Diagnostic<'_sess, G> for @Self - where G: rustc_errors::EmissionGuarantee - { + gen impl<'_sess, G> rustc_errors::Diagnostic<'_sess, G> for @Self { #[track_caller] fn into_diag( self, diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs index c99575ff7431d..d6b101ca0addf 100644 --- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs @@ -97,9 +97,7 @@ impl SubdiagnosticDerive { fn add_to_diag<__G>( self, #diag: &mut rustc_errors::Diag<'_, __G>, - ) where - __G: rustc_errors::EmissionGuarantee, - { + ) { #implementation } } diff --git a/compiler/rustc_metadata/src/diagnostics.rs b/compiler/rustc_metadata/src/diagnostics.rs index b98a0ce25af37..a093e7990ea28 100644 --- a/compiler/rustc_metadata/src/diagnostics.rs +++ b/compiler/rustc_metadata/src/diagnostics.rs @@ -2,7 +2,7 @@ use std::io::Error; use std::path::{Path, PathBuf}; use rustc_errors::codes::*; -use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, msg}; +use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level, msg}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol, sym}; use rustc_target::spec::{PanicStrategy, TargetTuple}; @@ -305,7 +305,7 @@ pub(crate) struct MultipleCandidates { pub candidates: Vec, } -impl Diagnostic<'_, G> for MultipleCandidates { +impl Diagnostic<'_, G> for MultipleCandidates { fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new( dcx, @@ -418,7 +418,7 @@ pub(crate) struct InvalidMetadataFiles { pub crate_rejections: Vec, } -impl Diagnostic<'_, G> for InvalidMetadataFiles { +impl Diagnostic<'_, G> for InvalidMetadataFiles { #[track_caller] fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new( @@ -450,7 +450,7 @@ pub(crate) struct CannotFindCrate { pub is_tier_3: bool, } -impl Diagnostic<'_, G> for CannotFindCrate { +impl Diagnostic<'_, G> for CannotFindCrate { #[track_caller] fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 8dafdc9cc7d33..2ad73c8894da5 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -7,7 +7,7 @@ use rustc_ast::NodeId; use rustc_attr_ir::{ ConstStability, DefaultBodyStability, DeprecatedSince, Deprecation, Stability, StabilityLevel, }; -use rustc_errors::{Applicability, Diag, Diagnostic, EmissionGuarantee, LintBuffer, msg}; +use rustc_errors::{Applicability, Diag, Diagnostic, LintBuffer, msg}; use rustc_feature::GateIssue; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, HirId}; @@ -114,7 +114,7 @@ pub(crate) struct Deprecated { pub since_kind: DeprecatedSinceKind, } -impl<'a, G: EmissionGuarantee> rustc_errors::Diagnostic<'a, G> for Deprecated { +impl<'a, G> rustc_errors::Diagnostic<'a, G> for Deprecated { fn into_diag( self, dcx: rustc_errors::DiagCtxtHandle<'a>, diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 01614692c9ed2..f88b7ff0f8a85 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -13,7 +13,7 @@ use std::borrow::Cow; use std::hash::{Hash, Hasher}; use std::sync::Arc; -use rustc_errors::{Applicability, Diag, EmissionGuarantee, ErrorGuaranteed}; +use rustc_errors::{Applicability, Diag, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::HirId; use rustc_hir::def_id::DefId; @@ -914,7 +914,7 @@ pub enum DynCompatibilityViolationSolution { } impl DynCompatibilityViolationSolution { - pub fn add_to(self, err: &mut Diag<'_, G>) { + pub fn add_to(self, err: &mut Diag<'_, G>) { match self { DynCompatibilityViolationSolution::None => {} DynCompatibilityViolationSolution::AddSelfOrMakeSized { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 9242d7101e916..71fb96ac43575 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2622,9 +2622,9 @@ impl<'tcx> TyCtxt<'tcx> { m.spans.inject_use_span.shrink_to_lo() } - pub fn disabled_nightly_features( + pub fn disabled_nightly_features( self, - diag: &mut Diag<'_, E>, + diag: &mut Diag<'_, G>, features: impl IntoIterator, ) { if !self.sess.is_nightly_build() { diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 85e1df8b057a0..7006568a2ef33 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -6,9 +6,7 @@ use rustc_abi::{ PointerKind, Primitive, ReprFlags, ReprOptions, Scalar, Size, TagEncoding, TargetDataLayout, TyAbiInterface, VariantIdx, Variants, }; -use rustc_errors::{ - Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level, -}; +use rustc_errors::{Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, IntoDiagArg, Level}; use rustc_hir as hir; use rustc_hir::attrs::lang_items::LangItem; use rustc_hir::def_id::DefId; @@ -1344,7 +1342,7 @@ pub enum FnAbiError<'tcx> { Layout(LayoutError<'tcx>), } -impl<'a, 'b, G: EmissionGuarantee> Diagnostic<'a, G> for FnAbiError<'b> { +impl<'a, 'b, G> Diagnostic<'a, G> for FnAbiError<'b> { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { match self { Self::Layout(e) => Diag::new(dcx, level, e.to_string()), diff --git a/compiler/rustc_mir_build/src/diagnostics.rs b/compiler/rustc_mir_build/src/diagnostics.rs index 154edfdf4a577..83bfd322d6444 100644 --- a/compiler/rustc_mir_build/src/diagnostics.rs +++ b/compiler/rustc_mir_build/src/diagnostics.rs @@ -1,7 +1,7 @@ use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, - MultiSpan, Subdiagnostic, msg, + Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, Level, MultiSpan, Subdiagnostic, + msg, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::ty::{self, Ty}; @@ -585,7 +585,7 @@ pub(crate) struct UnsafeNotInheritedLintNote { } impl Subdiagnostic for UnsafeNotInheritedLintNote { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.span_note( self.signature_span, msg!("an unsafe function restricts its caller, but its body is safe by default"), @@ -625,7 +625,7 @@ pub(crate) struct NonExhaustivePatternsTypeNotEmpty<'a, 'tcx> { pub(crate) ty: Ty<'tcx>, } -impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for NonExhaustivePatternsTypeNotEmpty<'_, '_> { +impl<'a, G> Diagnostic<'a, G> for NonExhaustivePatternsTypeNotEmpty<'_, '_> { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let mut diag = Diag::new(dcx, level, msg!("non-exhaustive patterns: type `{$ty}` is non-empty")); @@ -730,7 +730,7 @@ pub(crate) struct UnreachablePattern<'tcx> { pub(crate) inner: UnreachablePatternInner<'tcx>, } -impl<'a, 'tcx, G: EmissionGuarantee> Diagnostic<'a, G> for UnreachablePattern<'tcx> { +impl<'a, 'tcx, G> Diagnostic<'a, G> for UnreachablePattern<'tcx> { #[track_caller] fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let mut diag = self.inner.into_diag(dcx, level); @@ -1260,7 +1260,7 @@ pub(crate) struct Variant { } impl<'tcx> Subdiagnostic for AdtDefinedHere<'tcx> { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.arg("ty", self.ty); let mut spans = MultiSpan::from(self.adt_def_span); diff --git a/compiler/rustc_mir_build/src/thir/pattern/migration.rs b/compiler/rustc_mir_build/src/thir/pattern/migration.rs index 75e23c3a2ff16..e6db030557703 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/migration.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/migration.rs @@ -1,7 +1,7 @@ //! Automatic migration of Rust 2021 patterns to a form valid in both Editions 2021 and 2024. use rustc_data_structures::fx::FxIndexMap; -use rustc_errors::{Applicability, Diag, EmissionGuarantee, MultiSpan, pluralize}; +use rustc_errors::{Applicability, Diag, MultiSpan, pluralize}; use rustc_hir::{BindingMode, ByRef, HirId, Mutability}; use rustc_lint_defs::builtin::RUST_2024_INCOMPATIBLE_PAT; use rustc_middle::ty::{self, Rust2024IncompatiblePatInfo, TyCtxt}; @@ -90,7 +90,7 @@ impl<'a> PatMigration<'a> { format!("cannot {verb1}{or_verb2} within an implicitly-borrowing pattern{in_rust_2024}") } - fn format_subdiagnostics(self, diag: &mut Diag<'_, impl EmissionGuarantee>) { + fn format_subdiagnostics(self, diag: &mut Diag<'_, G>) { // Format and emit explanatory notes about default binding modes. Reversing the spans' order // means if we have nested spans, the innermost ones will be visited first. for (span, def_br_mutbl) in self.default_mode_labels.into_iter().rev() { diff --git a/compiler/rustc_mir_transform/src/diagnostics.rs b/compiler/rustc_mir_transform/src/diagnostics.rs index e9150049c6741..c851b55f9623a 100644 --- a/compiler/rustc_mir_transform/src/diagnostics.rs +++ b/compiler/rustc_mir_transform/src/diagnostics.rs @@ -1,7 +1,6 @@ use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, Level, - Subdiagnostic, msg, + Applicability, Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, Level, Subdiagnostic, msg, }; use rustc_lint_defs::Lint; use rustc_lint_defs::builtin::{ARITHMETIC_OVERFLOW, UNCONDITIONAL_PANIC}; @@ -219,7 +218,7 @@ pub(crate) struct UnusedAssignOverwrite { } impl Subdiagnostic for UnusedAssignOverwrite { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.span_label(self.assigned_span, "this value is reassigned later and never used"); diag.span_label( self.overwrite_span, @@ -298,7 +297,7 @@ pub(crate) struct UnusedVariableStringInterp { } impl Subdiagnostic for UnusedVariableStringInterp { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.span_label( self.lit, msg!("you might have meant to use string interpolation in this string literal"), diff --git a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs index eb6921e438528..0b8cdbb2d2696 100644 --- a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs +++ b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs @@ -524,7 +524,7 @@ struct LocalLabel<'a> { /// A custom `Subdiagnostic` implementation so that the notes are delivered in a specific order impl Subdiagnostic for LocalLabel<'_> { - fn add_to_diag(self, diag: &mut rustc_errors::Diag<'_, G>) { + fn add_to_diag(self, diag: &mut rustc_errors::Diag<'_, G>) { diag.span_label( self.span, msg!( diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index c5665246710a3..3a4875c1d0951 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -1614,74 +1614,7 @@ where r.retain(|(outlives, _)| !outlives.is_trivial() && unique.insert(*outlives)); } - #[derive(Default)] - struct NonTrivialVars { - vars: HashSet, - } - impl TypeVisitor for NonTrivialVars - where - I: Interner, - { - type Result = (); - fn visit_ty(&mut self, t: I::Ty) { - // If a nested type doesn't have any `ReVar`s, then we won't insert - // anything into `vars` anyway, so skip for better perf. - if !t.has_infer_regions() { - return; - } - t.super_visit_with(self); - } - fn visit_const(&mut self, c: I::Const) { - // The same goes for consts. - if !c.has_infer_regions() { - return; - } - c.super_visit_with(self); - } - fn visit_region(&mut self, r: Region) { - if let ty::ReVar(vid) = r.kind() { - self.vars.insert(vid); - } - } - } - - // If we have a constraint like `'re: '?1`, where '?1 can name 're and '?1 appears - // only on the RHS of region constraints, then this kind of constraint is also trivial, - // since we're able to pick '?1 := 'empty, and 're: 'empty is always true for any 're. - if let ExternalRegionConstraints::Old(r) = &mut external_constraints.region_constraints - && !r.is_empty() - { - let mut vis = NonTrivialVars::default(); - var_values.visit_with(&mut vis); - // We have to visit each component of `external_constraints` individually here - // because we skip the RHS of outlives constraints, and `TypeVisitor` doesn't - // have a method we can easily override in order to do this. - external_constraints.opaque_types.visit_with(&mut vis); - external_constraints.normalization_nested_goals.visit_with(&mut vis); - for (constraint, _) in r.iter() { - match constraint { - ty::RegionConstraint::Outlives(ty::OutlivesClause(sup, _)) => { - sup.visit_with(&mut vis) - } - ty::RegionConstraint::Eq(eq) => eq.visit_with(&mut vis), - } - } - - r.retain(|(outlives, _)| { - if let ty::RegionConstraint::Outlives(ty::OutlivesClause(sup, re)) = *outlives - && let Some(sup_re) = sup.as_region() - && let ty::RegionKind::ReVar(vid) = re.kind() - // This is only safe if we call `eager_resolve_vars` beforehand, - // which we do. - && self.delegate.universe_of_region(vid).unwrap() - .can_name(max_universe(&**self.delegate, sup_re)) - { - vis.vars.contains(&vid) - } else { - true - } - }); - } + filter_irrelevant_region_constraints(self.delegate, &var_values, &mut external_constraints); let canonical = canonicalize_response( self.delegate, @@ -1802,6 +1735,88 @@ where } } +fn filter_irrelevant_region_constraints( + delegate: &D, + var_values: &CanonicalVarValues, + external_constraints: &mut ExternalConstraintsData, +) where + D: SolverDelegate, + I: Interner, +{ + #[derive(Default)] + struct NonTrivialVars { + vars: HashSet, + } + impl TypeVisitor for NonTrivialVars + where + I: Interner, + { + type Result = (); + fn visit_ty(&mut self, t: I::Ty) { + // If a nested type doesn't have any `ReVar`s, then we won't insert + // anything into `vars` anyway, so skip for better perf. + if !t.has_infer_regions() { + return; + } + t.super_visit_with(self); + } + fn visit_const(&mut self, c: I::Const) { + // The same goes for consts. + if !c.has_infer_regions() { + return; + } + c.super_visit_with(self); + } + fn visit_region(&mut self, r: Region) { + if let ty::ReVar(vid) = r.kind() { + self.vars.insert(vid); + } + } + } + + let ExternalConstraintsData { region_constraints, opaque_types, normalization_nested_goals } = + external_constraints; + + // If we have a constraint like `'re: '?1`, where '?1 can name 're and '?1 appears + // only on the RHS of region constraints, then this kind of constraint is also trivial, + // since we're able to pick '?1 := glb('re, other_regions), and by definition of glb, + // `'re: glb`. + if let ExternalRegionConstraints::Old(r) = region_constraints + && !r.is_empty() + { + let mut vis = NonTrivialVars::default(); + var_values.visit_with(&mut vis); + // We have to visit each component of `external_constraints` individually here + // because we skip the RHS of outlives constraints, and `TypeVisitor` doesn't + // have a method we can easily override in order to do this. + opaque_types.visit_with(&mut vis); + normalization_nested_goals.visit_with(&mut vis); + for (constraint, _) in r.iter() { + match constraint { + ty::RegionConstraint::Outlives(ty::OutlivesClause(sup, _)) => { + sup.visit_with(&mut vis) + } + ty::RegionConstraint::Eq(eq) => eq.visit_with(&mut vis), + } + } + + r.retain(|(outlives, _)| { + if let ty::RegionConstraint::Outlives(ty::OutlivesClause(sup, re)) = *outlives + && let Some(sup_re) = sup.as_region() + && let ty::RegionKind::ReVar(vid) = re.kind() + // This is only safe if we call `eager_resolve_vars` before calling, + // this function, which we do. + && delegate.universe_of_region(vid).unwrap() + .can_name(max_universe(&**delegate, sup_re)) + { + vis.vars.contains(&vid) + } else { + true + } + }); + } +} + #[derive(Debug)] enum RerunDecision { Yes, diff --git a/compiler/rustc_parse/src/diagnostics.rs b/compiler/rustc_parse/src/diagnostics.rs index 1dc2d625fe0e0..829fc5a600e8a 100644 --- a/compiler/rustc_parse/src/diagnostics.rs +++ b/compiler/rustc_parse/src/diagnostics.rs @@ -7,8 +7,8 @@ use rustc_ast::token::{self, InvisibleOrigin, MetaVarKind, Token}; use rustc_ast_pretty::pprust; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, - Level, Subdiagnostic, SuggestionStyle, msg, + Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, IntoDiagArg, Level, + Subdiagnostic, SuggestionStyle, msg, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::edition::{Edition, LATEST_STABLE_EDITION}; @@ -1537,7 +1537,7 @@ pub(crate) struct ExpectedIdentifier { pub help_cannot_start_number: Option, } -impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for ExpectedIdentifier { +impl<'a, G> Diagnostic<'a, G> for ExpectedIdentifier { #[track_caller] fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let token_descr = TokenDescription::from_token(&self.token); @@ -1603,7 +1603,7 @@ pub(crate) struct ExpectedSemi { pub sugg: ExpectedSemiSugg, } -impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for ExpectedSemi { +impl<'a, G> Diagnostic<'a, G> for ExpectedSemi { #[track_caller] fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let token_descr = TokenDescription::from_token(&self.token); @@ -2010,7 +2010,7 @@ pub(crate) struct FnTraitMissingParen { } impl Subdiagnostic for FnTraitMissingParen { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.span_label(self.span, msg!("`Fn` bounds require arguments in parentheses")); diag.span_suggestion_short( self.span.shrink_to_hi(), @@ -3697,7 +3697,7 @@ pub(crate) struct UseDerefMacro { } impl Subdiagnostic for UseDerefMacro { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let Self { field, before, after } = self; let mut parts = Vec::new(); @@ -4355,7 +4355,7 @@ pub(crate) struct HiddenUnicodeCodepointsDiagLabels { } impl Subdiagnostic for HiddenUnicodeCodepointsDiagLabels { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { for (c, span) in self.spans { diag.span_label(span, format!("{c:?}")); } @@ -4369,7 +4369,7 @@ pub(crate) enum HiddenUnicodeCodepointsDiagSub { // Used because of multiple multipart_suggestion and note impl Subdiagnostic for HiddenUnicodeCodepointsDiagSub { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { match self { HiddenUnicodeCodepointsDiagSub::Escape { spans } => { diag.multipart_suggestion_with_style( diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 6ed61a9f4e01d..2afb55b02e2e6 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -1007,7 +1007,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> { err.emit() } - fn report_unterminated_block_comment(&self, start: BytePos, doc_style: Option) { + fn report_unterminated_block_comment(&self, start: BytePos, doc_style: Option) -> ! { let msg = match doc_style { Some(_) => "unterminated block doc-comment", None => "unterminated block comment", diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 539c15f18a9a4..16a438b5387ee 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -17,7 +17,7 @@ use rustc_ast as ast; use rustc_ast::token; use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; use rustc_ast_pretty::pprust; -use rustc_errors::{Diag, EmissionGuarantee, FatalError, PResult, pluralize}; +use rustc_errors::{Diag, FatalError, PResult, pluralize}; pub use rustc_lexer::UNICODE_VERSION; use rustc_session::parse::ParseSess; use rustc_span::edit_distance::find_best_match_for_name; @@ -165,11 +165,11 @@ pub fn new_parser_from_file<'a>( new_parser_from_source_file(psess, source_file, strip_tokens) } -pub fn utf8_error( +pub fn utf8_error( sm: &SourceMap, path: &str, sp: Option, - err: &mut Diag<'_, E>, + err: &mut Diag<'_, G>, utf8err: Utf8Error, contents: &[u8], ) { diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 6d4a0215eb7b3..8b8f3e862ae3b 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1720,7 +1720,7 @@ impl<'a> Parser<'a> { ); err.span_label(op_span, format!("not a valid {} operator", kind.fixity)); - let help_base_case = |mut err: Diag<'_, _>, base| { + let help_base_case = |mut err: Diag<'_, ErrorGuaranteed>, base| { err.help(format!("use `{}= 1` instead", kind.op.chr())); err.emit(); Ok(base) diff --git a/compiler/rustc_passes/src/diagnostics.rs b/compiler/rustc_passes/src/diagnostics.rs index a396695ba6d52..6ea0dc2c8f244 100644 --- a/compiler/rustc_passes/src/diagnostics.rs +++ b/compiler/rustc_passes/src/diagnostics.rs @@ -2,9 +2,7 @@ use std::io::Error; use std::path::{Path, PathBuf}; use rustc_errors::codes::*; -use rustc_errors::{ - Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, Level, MultiSpan, msg, -}; +use rustc_errors::{Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, Level, MultiSpan, msg}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::middle::resolve::MainDefinition; use rustc_middle::ty::Ty; @@ -414,7 +412,7 @@ pub(crate) struct NoMainErr { pub add_teach_note: bool, } -impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for NoMainErr { +impl<'a, G> Diagnostic<'a, G> for NoMainErr { #[track_caller] fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let mut diag = @@ -480,7 +478,7 @@ pub(crate) struct DuplicateLangItem { pub(crate) duplicate: Duplicate, } -impl Diagnostic<'_, G> for DuplicateLangItem { +impl Diagnostic<'_, G> for DuplicateLangItem { #[track_caller] fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new( diff --git a/compiler/rustc_resolve/src/diagnostics/mod.rs b/compiler/rustc_resolve/src/diagnostics/mod.rs index dfa58ab73778f..b581777901195 100644 --- a/compiler/rustc_resolve/src/diagnostics/mod.rs +++ b/compiler/rustc_resolve/src/diagnostics/mod.rs @@ -2,7 +2,7 @@ use rustc_errors::codes::*; use rustc_errors::formatting::DiagMessageAddArg; use rustc_errors::{ Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, ElidedLifetimeInPathSubdiag, - EmissionGuarantee, IntoDiagArg, Level, MultiSpan, Subdiagnostic, msg, + IntoDiagArg, Level, MultiSpan, Subdiagnostic, msg, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Ident, Span, Spanned, Symbol}; @@ -1380,7 +1380,7 @@ pub(crate) enum ItemWas { } impl Subdiagnostic for FoundItemConfigureOut { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut multispan: MultiSpan = self.span.into(); match self.item_was { ItemWas::BehindFeature { feature, span } => { @@ -1522,7 +1522,7 @@ pub(crate) struct Ambiguity { pub is_error: bool, } -impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for Ambiguity { +impl<'a, G> Diagnostic<'a, G> for Ambiguity { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let Self { ident, diff --git a/compiler/rustc_session/src/diagnostics.rs b/compiler/rustc_session/src/diagnostics.rs index 3cae99b483872..a2bf9a0d2dfc3 100644 --- a/compiler/rustc_session/src/diagnostics.rs +++ b/compiler/rustc_session/src/diagnostics.rs @@ -4,8 +4,7 @@ use rustc_ast::token; use rustc_ast::util::literal::LitError; use rustc_errors::codes::*; use rustc_errors::{ - Diag, DiagCtxtHandle, DiagMessage, Diagnostic, EmissionGuarantee, ErrorGuaranteed, Level, - MultiSpan, StashKey, + Diag, DiagCtxtHandle, DiagMessage, Diagnostic, ErrorGuaranteed, Level, MultiSpan, StashKey, }; use rustc_feature::{GateIssue, find_feature_issue}; use rustc_macros::{Diagnostic, Subdiagnostic}; @@ -96,11 +95,7 @@ pub fn feature_warn_issue( /// Adds the diagnostics for a feature to an existing error. /// Must be a language feature! -pub fn add_feature_diagnostics( - err: &mut Diag<'_, G>, - sess: &Session, - feature: Symbol, -) { +pub fn add_feature_diagnostics(err: &mut Diag<'_, G>, sess: &Session, feature: Symbol) { add_feature_diagnostics_for_issue(err, sess, feature, GateIssue::Language, false, None); } @@ -109,7 +104,7 @@ pub fn add_feature_diagnostics( /// This variant allows you to control whether it is a library or language feature. /// Almost always, you want to use this for a language feature. If so, prefer /// `add_feature_diagnostics`. -pub fn add_feature_diagnostics_for_issue( +pub fn add_feature_diagnostics_for_issue( err: &mut Diag<'_, G>, sess: &Session, feature: Symbol, @@ -197,7 +192,7 @@ pub(crate) struct FeatureGateError { pub(crate) explain: DiagMessage, } -impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for FeatureGateError { +impl<'a, G> Diagnostic<'a, G> for FeatureGateError { #[track_caller] fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { Diag::new(dcx, level, self.explain).with_span(self.span).with_code(E0658) diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 0f192379ce7fc..9f97a33bfdc75 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2262,11 +2262,12 @@ pub struct TargetOptions { /// Extra arguments to pass to the external assembler (when used) pub asm_args: StaticCow<[StaticCow]>, - /// Default CPU to pass to LLVM. Corresponds to `llc -mcpu=$cpu`. Defaults - /// to "generic". + /// Default CPU to pass to LLVM. Corresponds to `llc -mcpu=$cpu`. Must be a name the backend + /// accepts. Defaults to "generic" (which some backends won't accept). pub cpu: StaticCow, - /// Whether a cpu needs to be explicitly set. - /// Set to true if there is no default cpu. Defaults to false. + /// Whether a cpu needs to be explicitly set via `-Ctarget-cpu` for codegen to run. (Even if + /// true, `cpu` is still consulted on non-codegen paths such as cfg/feature computation.) + /// Defaults to false. pub need_explicit_cpu: bool, /// Whether `-Ctarget-cpu` is treated as a target modifier. If this is set /// all crates that are linked together must have been compiled with the diff --git a/compiler/rustc_target/src/spec/targets/avr_none.rs b/compiler/rustc_target/src/spec/targets/avr_none.rs index 0dcd2428fc703..d4b0bf64206c7 100644 --- a/compiler/rustc_target/src/spec/targets/avr_none.rs +++ b/compiler/rustc_target/src/spec/targets/avr_none.rs @@ -14,6 +14,7 @@ pub(crate) fn target() -> Target { pointer_width: 16, options: TargetOptions { c_int_width: 16, + cpu: "avr2".into(), exe_suffix: ".elf".into(), linker: Some("avr-gcc".into()), eh_frame_header: false, diff --git a/compiler/rustc_trait_selection/src/diagnostics.rs b/compiler/rustc_trait_selection/src/diagnostics.rs index 6e2a4f10fb458..02a181adfadb7 100644 --- a/compiler/rustc_trait_selection/src/diagnostics.rs +++ b/compiler/rustc_trait_selection/src/diagnostics.rs @@ -2,8 +2,8 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::formatting::DiagMessageAddArg; use rustc_errors::{ - Applicability, Diag, DiagCtxtHandle, DiagMessage, DiagStyledString, Diagnostic, - EmissionGuarantee, IntoDiagArg, Level, MultiSpan, Subdiagnostic, msg, + Applicability, Diag, DiagCtxtHandle, DiagMessage, DiagStyledString, Diagnostic, IntoDiagArg, + Level, MultiSpan, Subdiagnostic, msg, }; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -36,7 +36,7 @@ pub(crate) struct NegativePositiveConflict<'tcx> { pub positive_impl_span: Result, } -impl Diagnostic<'_, G> for NegativePositiveConflict<'_> { +impl Diagnostic<'_, G> for NegativePositiveConflict<'_> { #[track_caller] fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new( @@ -89,7 +89,7 @@ pub(crate) enum AdjustSignatureBorrow { } impl Subdiagnostic for AdjustSignatureBorrow { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { match self { AdjustSignatureBorrow::Borrow { to_borrow } => { diag.arg("borrow_len", to_borrow.len()); @@ -437,7 +437,7 @@ pub(crate) enum RegionOriginNote<'a> { } impl Subdiagnostic for RegionOriginNote<'_> { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let label_or_note = |diag: &mut Diag<'_, G>, span, msg: DiagMessage| { let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count(); let expanded_sub_count = diag.children.iter().filter(|d| !d.span.is_dummy()).count(); @@ -532,7 +532,7 @@ pub(crate) enum LifetimeMismatchLabels { } impl Subdiagnostic for LifetimeMismatchLabels { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { match self { LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => { diag.span_label(param_span, msg!("this parameter and the return type are declared with different lifetimes...")); @@ -605,7 +605,7 @@ pub(crate) struct AddLifetimeParamsSuggestion<'a> { } impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut mk_suggestion = || { let Some(anon_reg) = self.tcx.is_suitable_region(self.generic_param_scope, self.sub) else { @@ -789,7 +789,7 @@ pub(crate) struct IntroducesStaticBecauseUnmetLifetimeReq { } impl Subdiagnostic for IntroducesStaticBecauseUnmetLifetimeReq { - fn add_to_diag(mut self, diag: &mut Diag<'_, G>) { + fn add_to_diag(mut self, diag: &mut Diag<'_, G>) { self.unmet_requirements.push_span_label( self.binding_span, msg!("introduces a `'static` lifetime requirement"), @@ -1184,7 +1184,7 @@ pub(crate) struct ConsiderBorrowingParamHelp { } impl Subdiagnostic for ConsiderBorrowingParamHelp { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut type_param_span: MultiSpan = self.spans.clone().into(); for &span in &self.spans { // Seems like we can't call f() here as Into is required @@ -1661,7 +1661,7 @@ pub(crate) struct SuggestTuplePatternMany { } impl Subdiagnostic for SuggestTuplePatternMany { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.arg("path", self.path); let message = msg!("try wrapping the pattern in a variant of `{$path}`"); diag.multipart_suggestions( @@ -1907,7 +1907,7 @@ pub(crate) struct AddPreciseCapturingAndParams { } impl Subdiagnostic for AddPreciseCapturingAndParams { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.arg("new_lifetime", self.new_lifetime); diag.multipart_suggestion( msg!("add a `use<...>` bound to explicitly capture `{$new_lifetime}` after turning all argument-position `impl Trait` into type parameters, noting that this possibly affects the API of this crate"), @@ -2047,7 +2047,7 @@ pub struct AddPreciseCapturingForOvercapture { } impl Subdiagnostic for AddPreciseCapturingForOvercapture { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let applicability = if self.apit_spans.is_empty() { Applicability::MachineApplicable } else { diff --git a/compiler/rustc_trait_selection/src/diagnostics/note_and_explain.rs b/compiler/rustc_trait_selection/src/diagnostics/note_and_explain.rs index 07b8adb898aa6..32a35b58f3186 100644 --- a/compiler/rustc_trait_selection/src/diagnostics/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/diagnostics/note_and_explain.rs @@ -1,5 +1,5 @@ use rustc_errors::formatting::DiagMessageAddArg; -use rustc_errors::{Diag, EmissionGuarantee, IntoDiagArg, Subdiagnostic, msg}; +use rustc_errors::{Diag, IntoDiagArg, Subdiagnostic, msg}; use rustc_hir::def_id::LocalDefId; use rustc_middle::bug; use rustc_middle::ty::{self, TyCtxt}; @@ -163,7 +163,7 @@ impl RegionExplanation<'_> { } impl Subdiagnostic for RegionExplanation<'_> { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let msg = msg!( "{$pref_kind -> *[should_not_happen] [{$pref_kind}] diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs index e8765e3b0ad27..cea5c2f5a3d53 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs @@ -1,6 +1,6 @@ use std::fmt; -use rustc_errors::{Diag, E0275, EmissionGuarantee, ErrorGuaranteed, struct_span_code_err}; +use rustc_errors::{Diag, E0275, ErrorGuaranteed, struct_span_code_err}; use rustc_hir::def::Namespace; use rustc_hir::def_id::LOCAL_CRATE; use rustc_infer::traits::{Obligation, PredicateObligation}; @@ -17,10 +17,7 @@ pub enum OverflowCause<'tcx> { TraitSolver(ty::Predicate<'tcx>), } -pub fn suggest_new_overflow_limit<'tcx, G: EmissionGuarantee>( - tcx: TyCtxt<'tcx>, - err: &mut Diag<'_, G>, -) { +pub fn suggest_new_overflow_limit<'tcx, G>(tcx: TyCtxt<'tcx>, err: &mut Diag<'_, G>) { let suggested_limit = match tcx.recursion_limit() { Limit(0) => Limit(2), limit => limit * 2, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 0b178f86249a9..06efc92d9e727 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -9,8 +9,7 @@ use rustc_abi::ExternAbi; use rustc_data_structures::fx::FxHashSet; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, EmissionGuarantee, MultiSpan, Style, SuggestionStyle, pluralize, - struct_span_code_err, + Applicability, Diag, MultiSpan, Style, SuggestionStyle, pluralize, struct_span_code_err, }; use rustc_hir::attrs::lang_items::{self, LangItem}; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; @@ -120,7 +119,7 @@ fn predicate_constraint(generics: &hir::Generics<'_>, pred: ty::Predicate<'_>) - /// Type parameter needs more bounds. The trivial case is `T` `where T: Bound`, but /// it can also be an `impl Trait` param that needs to be decomposed to a type /// param for cleaner code. -pub fn suggest_restriction<'tcx, G: EmissionGuarantee>( +pub fn suggest_restriction<'tcx, G>( tcx: TyCtxt<'tcx>, item_id: LocalDefId, hir_generics: &hir::Generics<'tcx>, @@ -2752,7 +2751,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { false } - pub(super) fn suggest_borrow_for_unsized_closure_return( + pub(super) fn suggest_borrow_for_unsized_closure_return( &self, body_def_id: LocalDefId, err: &mut Diag<'_, G>, @@ -3297,7 +3296,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// /// Returns `true` if an async-await specific note was added to the diagnostic. #[instrument(level = "debug", skip_all, fields(?obligation.predicate, ?obligation.cause.span))] - pub fn maybe_note_obligation_cause_for_async_await( + pub fn maybe_note_obligation_cause_for_async_await( &self, err: &mut Diag<'_, G>, obligation: &PredicateObligation<'tcx>, @@ -3529,7 +3528,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// Unconditionally adds the diagnostic note described in /// `maybe_note_obligation_cause_for_async_await`'s documentation comment. #[instrument(level = "debug", skip_all)] - fn note_obligation_cause_for_async_await( + fn note_obligation_cause_for_async_await( &self, err: &mut Diag<'_, G>, interior_or_upvar_span: CoroutineInteriorOrUpvar, @@ -3763,7 +3762,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); } - fn note_closure_capture( + fn note_closure_capture( &self, err: &mut Diag<'_, G>, closure_def_id: DefId, @@ -3816,7 +3815,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { true } - pub(super) fn note_obligation_cause_code( + pub(super) fn note_obligation_cause_code( &self, body_def_id: LocalDefId, err: &mut Diag<'_, G>, @@ -3845,7 +3844,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); } - fn note_obligation_cause_code_inner( + fn note_obligation_cause_code_inner( &self, body_def_id: LocalDefId, err: &mut Diag<'_, G>, @@ -5202,7 +5201,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - fn note_function_argument_obligation( + fn note_function_argument_obligation( &self, body_def_id: LocalDefId, err: &mut Diag<'_, G>, @@ -5441,7 +5440,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - fn suggest_option_method_if_applicable( + fn suggest_option_method_if_applicable( &self, failed_pred: ty::Predicate<'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -5516,7 +5515,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - fn look_for_iterator_item_mistakes( + fn look_for_iterator_item_mistakes( &self, assocs_in_this_method: &[Option<(Span, (DefId, Ty<'tcx>))>], typeck_results: &TypeckResults<'tcx>, @@ -5665,7 +5664,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - fn point_at_chain( + fn point_at_chain( &self, expr: &hir::Expr<'_>, typeck_results: &TypeckResults<'tcx>, @@ -5914,7 +5913,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// | | `Iterator::Item` is `&mut Vec` here /// | this expression has type `Vec>` /// ``` - fn point_at_chain_in_return_position( + fn point_at_chain_in_return_position( &self, body_def_id: LocalDefId, expr: &hir::Expr<'_>, @@ -7102,7 +7101,7 @@ pub fn suggest_desugaring_async_fn_to_impl_future_in_trait<'tcx>( /// On `impl` evaluation cycles, look for `Self::AssocTy` restrictions in `where` clauses, explain /// they are not allowed and if possible suggest alternatives. -fn point_at_assoc_type_restriction( +fn point_at_assoc_type_restriction( tcx: TyCtxt<'_>, err: &mut Diag<'_, G>, self_ty_str: &str, diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 5605325309275..e69b1d6188576 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -7,7 +7,7 @@ use std::fmt::Debug; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; -use rustc_errors::{Diag, EmissionGuarantee}; +use rustc_errors::Diag; use rustc_hir::def_id::{CRATE_DEF_ID, DefId}; use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::{PredicateObligations, TraitErrors}; @@ -61,14 +61,14 @@ pub struct OverlapResult<'tcx> { pub overflowing_predicates: Vec>, } -pub fn add_placeholder_note(err: &mut Diag<'_, G>) { +pub fn add_placeholder_note(err: &mut Diag<'_, G>) { err.note( "this behavior recently changed as a result of a bug fix; \ see rust-lang/rust#56105 for details", ); } -pub(crate) fn suggest_increasing_recursion_limit<'tcx, G: EmissionGuarantee>( +pub(crate) fn suggest_increasing_recursion_limit<'tcx, G>( tcx: TyCtxt<'tcx>, err: &mut Diag<'_, G>, overflowing_predicates: &[ty::Predicate<'tcx>], diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index a9ac96424d018..0b870f0d72e37 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -9,7 +9,7 @@ use std::ops::ControlFlow; use hir::def::DefKind; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; -use rustc_errors::{Diag, EmissionGuarantee}; +use rustc_errors::Diag; use rustc_hir as hir; use rustc_hir::attrs::lang_items::LangItem; use rustc_hir::def_id::DefId; @@ -63,7 +63,7 @@ pub enum IntercrateAmbiguityCause<'tcx> { impl<'tcx> IntercrateAmbiguityCause<'tcx> { /// Emits notes when the overlap is caused by complex intercrate ambiguities. /// See #23980 for details. - pub fn add_intercrate_ambiguity_hint(&self, err: &mut Diag<'_, G>) { + pub fn add_intercrate_ambiguity_hint(&self, err: &mut Diag<'_, G>) { err.note(self.intercrate_ambiguity_hint()); } diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 9a0894891f625..f1626d1c69759 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -12,8 +12,8 @@ pub mod specialization_graph; use rustc_data_structures::fx::FxIndexSet; +use rustc_errors::Diag; use rustc_errors::codes::*; -use rustc_errors::{Diag, EmissionGuarantee}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_infer::traits::Obligation; use rustc_lint_defs::builtin::COHERENCE_LEAK_CHECK; @@ -528,7 +528,7 @@ fn report_conflicting_impls<'tcx>( // Work to be done after we've built the Diag. We have to define it now // because the lint emit methods don't return back the Diag that's passed // in. - fn decorate<'tcx, G: EmissionGuarantee>( + fn decorate<'tcx, G>( tcx: TyCtxt<'tcx>, overlap: &OverlapError<'tcx>, impl_span: Span, diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index bf77b477eef70..734c114d74d91 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -448,10 +448,7 @@ impl Box { #[unstable(feature = "allocator_api", issue = "32838")] #[must_use] #[inline] - pub fn new_in(x: T, alloc: A) -> Self - where - A: Allocator, - { + pub fn new_in(x: T, alloc: A) -> Self { let mut boxed = Self::new_uninit_in(alloc); boxed.write(x); // SAFETY: Initialised by the above. @@ -475,10 +472,7 @@ impl Box { /// ``` #[unstable(feature = "allocator_api", issue = "32838")] #[inline] - pub fn try_new_in(x: T, alloc: A) -> Result - where - A: Allocator, - { + pub fn try_new_in(x: T, alloc: A) -> Result { let mut boxed = Self::try_new_uninit_in(alloc)?; boxed.write(x); // SAFETY: Initialised by the above. @@ -504,10 +498,7 @@ impl Box { #[unstable(feature = "allocator_api", issue = "32838")] #[cfg(not(no_global_oom_handling))] #[must_use] - pub fn new_uninit_in(alloc: A) -> Box, A> - where - A: Allocator, - { + pub fn new_uninit_in(alloc: A) -> Box, A> { let layout = Layout::new::>(); // NOTE: Prefer match over unwrap_or_else since closure sometimes not inlineable. // That would make code size bigger. @@ -536,10 +527,7 @@ impl Box { /// # Ok::<(), std::alloc::AllocError>(()) /// ``` #[unstable(feature = "allocator_api", issue = "32838")] - pub fn try_new_uninit_in(alloc: A) -> Result, A>, AllocError> - where - A: Allocator, - { + pub fn try_new_uninit_in(alloc: A) -> Result, A>, AllocError> { let ptr = if T::IS_ZST { NonNull::dangling() } else { @@ -573,10 +561,7 @@ impl Box { #[unstable(feature = "allocator_api", issue = "32838")] #[cfg(not(no_global_oom_handling))] #[must_use] - pub fn new_zeroed_in(alloc: A) -> Box, A> - where - A: Allocator, - { + pub fn new_zeroed_in(alloc: A) -> Box, A> { let layout = Layout::new::>(); // NOTE: Prefer match over unwrap_or_else since closure sometimes not inlineable. // That would make code size bigger. @@ -609,10 +594,7 @@ impl Box { /// /// [zeroed]: mem::MaybeUninit::zeroed #[unstable(feature = "allocator_api", issue = "32838")] - pub fn try_new_zeroed_in(alloc: A) -> Result, A>, AllocError> - where - A: Allocator, - { + pub fn try_new_zeroed_in(alloc: A) -> Result, A>, AllocError> { let ptr = if T::IS_ZST { NonNull::dangling() } else { diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 9b55d70fecb9a..a30940bf2db71 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -10,6 +10,30 @@ //! and , //! and for const evaluation in . //! +//! Intrinsics don't need a body. However, they optionally can have a body, which we call the +//! "fallback body". This will be used by codegen backends that do not have a dedicated +//! implementation of the intrinsic, making it easier to add new intrinsics for specific operations +//! without having to implement them in each codegen backend. The fallback body obviously has to be +//! a valid implementation of the documented specification of the intrinsic. In some cases, the +//! fallback body will be *equivalent* to the specification. Note that this is a strong requirement: +//! if the spec says "UB if input `x` is even", then a valid implementation can just ignore this and +//! do whatever it wants in that case; an *equivalent* implementation needs to actually check this +//! condition and trigger UB in that case (e.g. by using `hint::assert_unchecked()`). Similar, if +//! the spec says "returns `x` or `y` non-deterministically", then an *equivalent* implementation +//! must actually do non-deterministic choice and return either value (e.g. by invoking some other +//! language operation that has the same non-determinism). Intrinsics with such a fallback body that +//! is equivalent to the spec may be marked with `#[miri::intrinsic_fallback_is_spec]`; the fallback +//! body will then also be used by Miri for UB checking. When in doubt, do not use this attribute or +//! ask the Miri maintainers for advice. +//! +//! Intrinsics are, in general, language extensions. Therefore, t-lang should be involved whenever a +//! new intrinsic is exposed to stable code. However, if an intrinsic is marked +//! `#[miri::intrinsic_fallback_is_spec]` with a fallback body that only uses stable features (or if +//! such a fallback body could be written, but for one reason or another the actual fallback body is +//! different), and if it also does not make other promises that go beyond observable program +//! behavior (such as steering the optimizer in a particular direction), then an intrinsic may be +//! used without t-lang involvement. +//! //! # Const intrinsics //! //! In order to make an intrinsic unstable usable at compile-time, copy the implementation from @@ -19,9 +43,10 @@ //! wg-const-eval. //! //! If an intrinsic is supposed to be used from a `const fn` with a `rustc_const_stable` attribute, -//! `#[rustc_intrinsic_const_stable_indirect]` needs to be added to the intrinsic. Such a change requires -//! T-lang approval, because it may bake a feature into the language that cannot be replicated in -//! user code without compiler support. +//! `#[rustc_intrinsic_const_stable_indirect]` needs to be added to the intrinsic. Such a change +//! requires T-lang approval, because it may bake a feature into the language that cannot be +//! replicated in user code without compiler support. The same exception as above applies for +//! `#[miri::intrinsic_fallback_is_spec]` intrinsics. //! //! # Volatiles //! diff --git a/library/test/src/console.rs b/library/test/src/console.rs index b1c5404a7160c..b337fa7834525 100644 --- a/library/test/src/console.rs +++ b/library/test/src/console.rs @@ -170,7 +170,7 @@ impl ConsoleTestState { } // List the tests to console, and optionally to logfile. Filters are honored. -pub(crate) fn list_tests_console(opts: &TestOpts, tests: TestList) -> io::Result<()> { +pub(crate) fn list_tests_console(opts: &TestOpts, tests: TestList<'_>) -> io::Result<()> { let output = match term::stdout() { None => OutputLocation::Raw(io::stdout().lock()), Some(t) => OutputLocation::Pretty(t), @@ -307,9 +307,13 @@ pub(crate) fn get_formatter(opts: &TestOpts, max_name_len: usize) -> Box io::Result { - let max_name_len = tests - .tests +pub fn run_tests_console(opts: &TestOpts, tests: TestList<'_>) -> io::Result { + let all_test_len = tests.tests.len(); + let filtered_tests = filter_tests(opts, tests); + + // Only iterate the filtered tests: only those are actually printed, and also the + // full list can be very long and we want to avoid ever iterating that list in Miri. + let max_name_len = filtered_tests .iter() .max_by_key(|t| len_if_padded(t)) .map(|t| t.desc.name.as_slice().len()) @@ -325,7 +329,7 @@ pub fn run_tests_console(opts: &TestOpts, tests: TestList) -> io::Result { (cfg!(target_family = "wasm") && cfg!(target_os = "unknown")) || cfg!(target_os = "zkvm"); let start_time = (!is_instant_unsupported).then(Instant::now); - run_tests(opts, tests, |x| on_test_event(&x, &mut st, &mut *out))?; + run_tests(opts, filtered_tests, all_test_len, |x| on_test_event(&x, &mut st, &mut *out))?; st.exec_time = start_time.map(|t| TestSuiteExecTime(t.elapsed())); assert!(opts.fail_fast || st.current_test_count() == st.total); diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index e4280520bd8ba..187299b0f4cf8 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -18,6 +18,7 @@ #![doc(test(attr(deny(warnings))))] #![doc(rust_logo)] #![feature(rustdoc_internals)] +#![feature(exitcode_exit_method)] #![feature(file_buffered)] #![feature(internal_output_capture)] #![feature(io_const_error)] @@ -51,14 +52,14 @@ pub mod test { DynTestFn, DynTestName, StaticBenchFn, StaticTestFn, StaticTestName, TestDesc, TestDescAndFn, TestId, TestList, TestListOrder, TestName, TestType, }; - pub use crate::{assert_test_result, filter_tests, run_test, test_main, test_main_static}; + pub use crate::{assert_test_result, filter_tests, run_test, test_main, test_main_env_args}; } use std::collections::VecDeque; use std::io::prelude::Write; use std::mem::ManuallyDrop; use std::panic::{self, AssertUnwindSafe, PanicHookInfo, catch_unwind}; -use std::process::{self, Command, Termination}; +use std::process::{self, Command, ExitCode, Termination}; use std::sync::mpsc::{Sender, channel}; use std::sync::{Arc, Mutex}; use std::time::{Duration, Instant}; @@ -90,40 +91,26 @@ use test_result::*; use time::TestExecTime; /// Process exit code to be used to indicate test failures. -pub const ERROR_EXIT_CODE: i32 = 101; +pub const ERROR_EXIT_CODE: u8 = 101; const SECONDARY_TEST_INVOKER_VAR: &str = "__RUST_TEST_INVOKE"; const SECONDARY_TEST_BENCH_BENCHMARKS_VAR: &str = "__RUST_TEST_BENCH_BENCHMARKS"; // The default console test runner. It accepts the command line // arguments and a vector of test_descs. -pub fn test_main(args: &[String], tests: Vec, options: Option) { - test_main_with_exit_callback(args, tests, options, || {}) -} - -pub fn test_main_with_exit_callback( - args: &[String], - tests: Vec, - options: Option, - exit_callback: F, -) { +pub fn test_main(args: &[String], tests: &[&TestDescAndFn]) -> ExitCode { let tests = TestList::new(tests, TestListOrder::Unsorted); - test_main_inner(args, tests, options, exit_callback) + test_main_inner(args, tests, None) } -fn test_main_inner( - args: &[String], - tests: TestList, - options: Option, - exit_callback: F, -) { +fn test_main_inner(args: &[String], tests: TestList<'_>, options: Option) -> ExitCode { let mut opts = match cli::parse_opts(args) { Some(Ok(o)) => o, Some(Err(msg)) => { eprintln!("error: {msg}"); - process::exit(ERROR_EXIT_CODE); + return ERROR_EXIT_CODE.into(); } - None => return, + None => return ExitCode::SUCCESS, // help was shown }; if let Some(options) = options { opts.options = options; @@ -131,7 +118,7 @@ fn test_main_inner( if opts.list { if let Err(e) = console::list_tests_console(&opts, tests) { eprintln!("error: io error when listing tests: {e:?}"); - process::exit(ERROR_EXIT_CODE); + return ERROR_EXIT_CODE.into(); } } else { if !opts.nocapture { @@ -170,40 +157,41 @@ fn test_main_inner( let res = console::run_tests_console(&opts, tests); // Prevent Valgrind from reporting reachable blocks in users' unit tests. drop(panic::take_hook()); - exit_callback(); match res { Ok(true) => {} - Ok(false) => process::exit(ERROR_EXIT_CODE), + Ok(false) => return ExitCode::from(ERROR_EXIT_CODE), Err(e) => { eprintln!("error: io error when listing tests: {e:?}"); - process::exit(ERROR_EXIT_CODE); + return ExitCode::from(ERROR_EXIT_CODE); } } } + + ExitCode::SUCCESS } -/// A variant optimized for invocation with a static test vector. -/// This will panic (intentionally) when fed any dynamic tests. +/// A variant that takes the arguments from the command line, and exist the process. /// /// This is the entry point for the main function generated by `rustc --test` /// when panic=unwind. -pub fn test_main_static(tests: &[&TestDescAndFn]) { +pub fn test_main_env_args(tests: &[&TestDescAndFn]) -> ! { + // This is supposed to be reasonably fast even in Miri. In particular, when invoked via `--exact + // test`, we want the entire invocation to be `O(log n)` in the number of tests: never iterate + // the entire test list (as that list could be big)! let args = env::args().collect::>(); - let owned_tests: Vec<_> = tests.iter().map(make_owned_test).collect(); // Tests are sorted by name at compile time by mk_tests_slice. - let tests = TestList::new(owned_tests, TestListOrder::Sorted); - test_main_inner(&args, tests, None, || {}) + let tests = TestList::new(tests, TestListOrder::Sorted); + test_main_inner(&args, tests, None).exit_process() } -/// A variant optimized for invocation with a static test vector. -/// This will panic (intentionally) when fed any dynamic tests. +/// A variant that takes the arguments from the command line, and exits the process. /// /// Runs tests in panic=abort mode, which involves spawning subprocesses for /// tests. /// /// This is the entry point for the main function generated by `rustc --test` /// when panic=abort. -pub fn test_main_static_abort(tests: &[&TestDescAndFn]) { +pub fn test_main_env_args_abort(tests: &[&TestDescAndFn]) -> ! { // If we're being run in SpawnedSecondary mode, run the test here. run_test // will then exit the process. if let Ok(name) = env::var(SECONDARY_TEST_INVOKER_VAR) { @@ -220,7 +208,7 @@ pub fn test_main_static_abort(tests: &[&TestDescAndFn]) { } // Convert benchmarks to tests if we're not benchmarking. - let mut tests = tests.iter().map(make_owned_test).collect::>(); + let mut tests = tests.iter().copied().cloned().collect::>(); if env::var(SECONDARY_TEST_BENCH_BENCHMARKS_VAR).is_ok() { // SAFETY: Same as for SECONDARY_TEST_INVOKER_VAR unsafe { @@ -246,25 +234,13 @@ pub fn test_main_static_abort(tests: &[&TestDescAndFn]) { panic!("benchmarks should not be executed into child processes") } } + // Unreachable } let args = env::args().collect::>(); - let owned_tests: Vec<_> = tests.iter().map(make_owned_test).collect(); // Tests are sorted by name at compile time by mk_tests_slice. - let tests = TestList::new(owned_tests, TestListOrder::Sorted); - test_main_inner(&args, tests, Some(Options::new().panic_abort(true)), || {}) -} - -/// Clones static values for putting into a dynamic vector, which test_main() -/// needs to hand out ownership of tests to parallel test runners. -/// -/// This will panic when fed any dynamic tests, because they cannot be cloned. -fn make_owned_test(test: &&TestDescAndFn) -> TestDescAndFn { - match test.testfn { - StaticTestFn(f) => TestDescAndFn { testfn: StaticTestFn(f), desc: test.desc.clone() }, - StaticBenchFn(f) => TestDescAndFn { testfn: StaticBenchFn(f), desc: test.desc.clone() }, - _ => panic!("non-static tests passed to test::test_main_static"), - } + let tests = TestList::new(tests, TestListOrder::Sorted); + test_main_inner(&args, tests, Some(Options::new().panic_abort(true))).exit_process() } /// Public API used by rustdoc to display the `total` and `compilation` times in the expected @@ -274,7 +250,7 @@ pub fn print_merged_doctests_times(args: &[String], total_time: f64, compilation Some(Ok(o)) => o, Some(Err(msg)) => { eprintln!("error: {msg}"); - process::exit(ERROR_EXIT_CODE); + process::exit(ERROR_EXIT_CODE.into()); } None => return, }; @@ -321,7 +297,8 @@ impl FilteredTests { pub fn run_tests( opts: &TestOpts, - tests: TestList, + mut filtered_tests: Vec, + all_tests_len: usize, mut notify_about_test_event: F, ) -> io::Result<()> where @@ -357,11 +334,8 @@ where timeout: Instant, } - let tests_len = tests.tests.len(); - let mut filtered = FilteredTests { tests: Vec::new(), benches: Vec::new(), next_id: 0 }; - let mut filtered_tests = filter_tests(opts, tests); if !opts.bench_benchmarks { filtered_tests = convert_benchmarks_to_tests(filtered_tests); } @@ -380,7 +354,7 @@ where }; } - let filtered_out = tests_len - filtered.total_len(); + let filtered_out = all_tests_len - filtered.total_len(); let event = TestEvent::TeFilteredOut(filtered_out); notify_about_test_event(event)?; @@ -535,25 +509,28 @@ where Ok(()) } -pub fn filter_tests(opts: &TestOpts, tests: TestList) -> Vec { +pub fn filter_tests(opts: &TestOpts, tests: TestList<'_>) -> Vec { let TestList { tests, order } = tests; - let mut filtered = tests; - - // Remove tests that don't match the test filter. - if !opts.filters.is_empty() { - if opts.filter_exact && order == TestListOrder::Sorted { - // Let's say that `f` is the number of filters and `n` is the number - // of tests. - // - // The test array is sorted by name (guaranteed by the caller via - // TestListOrder::Sorted), so use binary search for O(f log n) - // exact-match lookups instead of an O(n) linear scan. - // - // This is important for Miri, where the interpreted execution makes - // the linear scan very expensive. - filtered = filter_exact_match(filtered, &opts.filters); - } else { - filtered.retain(|test| { + + // Initial filtering: Remove tests that don't match the test filter. + let mut filtered = if opts.filters.is_empty() { + tests.iter().copied().cloned().collect::>() + } else if opts.filter_exact && order == TestListOrder::Sorted { + // Let's say that `f` is the number of filters and `n` is the number + // of tests. + // + // The test array is sorted by name (guaranteed by the caller via + // TestListOrder::Sorted), so use binary search for O(f log n) + // exact-match lookups instead of an O(n) linear scan. + // + // This is important for Miri, where the interpreted execution makes + // the linear scan very expensive. + filter_exact_match(tests, &opts.filters) + } else { + tests + .iter() + .copied() + .filter(|test| { let test_name = test.desc.name.as_slice(); opts.filters.iter().any(|filter| { if opts.filter_exact { @@ -562,9 +539,10 @@ pub fn filter_tests(opts: &TestOpts, tests: TestList) -> Vec { test_name.contains(filter.as_str()) } }) - }); - } - } + }) + .cloned() + .collect::>() + }; // Skip tests that match any of the skip filters // @@ -601,7 +579,7 @@ pub fn filter_tests(opts: &TestOpts, tests: TestList) -> Vec { /// Extract tests whose names exactly match one of the given `filters`, using /// binary search on the (assumed sorted) test list. -fn filter_exact_match(mut tests: Vec, filters: &[String]) -> Vec { +fn filter_exact_match<'a>(tests: &[&'a TestDescAndFn], filters: &[String]) -> Vec { // Binary search for each filter in the sorted test list. let mut indexes: Vec = filters .iter() @@ -610,16 +588,11 @@ fn filter_exact_match(mut tests: Vec, filters: &[String]) -> Vec< indexes.sort_unstable(); indexes.dedup(); - // Extract matching tests. Process indexes in descending order so that - // swap_remove (which replaces the removed element with the last) does not - // invalidate indexes we haven't visited yet. + // Extract matching tests. let mut result = Vec::with_capacity(indexes.len()); - for &idx in indexes.iter().rev() { - result.push(tests.swap_remove(idx)); + for &idx in indexes.iter() { + result.push(tests[idx].clone()); } - // Reverse to restore the original sorted order, since we extracted the - // matching tests in descending index order. - result.reverse(); result } diff --git a/library/test/src/tests.rs b/library/test/src/tests.rs index b25462cce1f99..95fd18e483288 100644 --- a/library/test/src/tests.rs +++ b/library/test/src/tests.rs @@ -55,7 +55,7 @@ fn one_ignored_one_unignored_test() -> Vec { no_run: false, test_type: TestType::Unknown, }, - testfn: DynTestFn(Box::new(move || Ok(()))), + testfn: DynTestFn(Arc::new(move || Ok(()))), }, TestDescAndFn { desc: TestDesc { @@ -72,11 +72,20 @@ fn one_ignored_one_unignored_test() -> Vec { no_run: false, test_type: TestType::Unknown, }, - testfn: DynTestFn(Box::new(move || Ok(()))), + testfn: DynTestFn(Arc::new(move || Ok(()))), }, ] } +fn filter_tests_owned( + opts: &TestOpts, + (tests, order): (Vec, TestListOrder), +) -> Vec { + let tests_bor = tests.iter().collect::>(); + let tests = TestList::new(&tests_bor, order); + filter_tests(opts, tests) +} + #[test] fn do_not_run_ignored_tests() { fn f() -> Result<(), String> { @@ -97,7 +106,7 @@ fn do_not_run_ignored_tests() { no_run: false, test_type: TestType::Unknown, }, - testfn: DynTestFn(Box::new(f)), + testfn: DynTestFn(Arc::new(f)), }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, TestId(0), desc, RunStrategy::InProcess, tx); @@ -125,7 +134,7 @@ fn ignored_tests_result_in_ignored() { no_run: false, test_type: TestType::Unknown, }, - testfn: DynTestFn(Box::new(f)), + testfn: DynTestFn(Arc::new(f)), }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, TestId(0), desc, RunStrategy::InProcess, tx); @@ -154,7 +163,7 @@ fn test_should_panic() { no_run: false, test_type: TestType::Unknown, }, - testfn: DynTestFn(Box::new(f)), + testfn: DynTestFn(Arc::new(f)), }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, TestId(0), desc, RunStrategy::InProcess, tx); @@ -183,7 +192,7 @@ fn test_should_panic_good_message() { no_run: false, test_type: TestType::Unknown, }, - testfn: DynTestFn(Box::new(f)), + testfn: DynTestFn(Arc::new(f)), }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, TestId(0), desc, RunStrategy::InProcess, tx); @@ -217,7 +226,7 @@ fn test_should_panic_bad_message() { no_run: false, test_type: TestType::Unknown, }, - testfn: DynTestFn(Box::new(f)), + testfn: DynTestFn(Arc::new(f)), }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, TestId(0), desc, RunStrategy::InProcess, tx); @@ -256,7 +265,7 @@ fn test_should_panic_non_string_message_type() { no_run: false, test_type: TestType::Unknown, }, - testfn: DynTestFn(Box::new(f)), + testfn: DynTestFn(Arc::new(f)), }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, TestId(0), desc, RunStrategy::InProcess, tx); @@ -288,7 +297,7 @@ fn test_should_panic_but_succeeds() { no_run: false, test_type: TestType::Unknown, }, - testfn: DynTestFn(Box::new(f)), + testfn: DynTestFn(Arc::new(f)), }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, TestId(0), desc, RunStrategy::InProcess, tx); @@ -321,7 +330,7 @@ fn report_time_test_template(report_time: bool) -> Option { no_run: false, test_type: TestType::Unknown, }, - testfn: DynTestFn(Box::new(f)), + testfn: DynTestFn(Arc::new(f)), }; let time_options = if report_time { Some(TestTimeOptions::default()) } else { None }; @@ -363,7 +372,7 @@ fn time_test_failure_template(test_type: TestType) -> TestResult { no_run: false, test_type, }, - testfn: DynTestFn(Box::new(f)), + testfn: DynTestFn(Arc::new(f)), }; // `Default` will initialize all the thresholds to 0 milliseconds. let mut time_options = TestTimeOptions::default(); @@ -477,8 +486,8 @@ fn filter_for_ignored_option() { opts.run_tests = true; opts.run_ignored = RunIgnored::Only; - let tests = TestList::new(one_ignored_one_unignored_test(), TestListOrder::Unsorted); - let filtered = filter_tests(&opts, tests); + let tests = (one_ignored_one_unignored_test(), TestListOrder::Unsorted); + let filtered = filter_tests_owned(&opts, tests); assert_eq!(filtered.len(), 1); assert_eq!(filtered[0].desc.name.to_string(), "1"); @@ -494,8 +503,8 @@ fn run_include_ignored_option() { opts.run_tests = true; opts.run_ignored = RunIgnored::Yes; - let tests = TestList::new(one_ignored_one_unignored_test(), TestListOrder::Unsorted); - let filtered = filter_tests(&opts, tests); + let tests = (one_ignored_one_unignored_test(), TestListOrder::Unsorted); + let filtered = filter_tests_owned(&opts, tests); assert_eq!(filtered.len(), 2); assert!(!filtered[0].desc.ignore); @@ -524,10 +533,10 @@ fn exclude_should_panic_option() { no_run: false, test_type: TestType::Unknown, }, - testfn: DynTestFn(Box::new(move || Ok(()))), + testfn: DynTestFn(Arc::new(move || Ok(()))), }); - let filtered = filter_tests(&opts, TestList::new(tests, TestListOrder::Unsorted)); + let filtered = filter_tests_owned(&opts, (tests, TestListOrder::Unsorted)); assert_eq!(filtered.len(), 2); assert!(filtered.iter().all(|test| test.desc.should_panic == ShouldPanic::No)); @@ -535,7 +544,7 @@ fn exclude_should_panic_option() { #[test] fn exact_filter_match() { - fn tests() -> TestList { + fn tests() -> (Vec, TestListOrder) { let tests = ["base", "base::test", "base::test1", "base::test2"] .into_iter() .map(|name| TestDescAndFn { @@ -553,59 +562,63 @@ fn exact_filter_match() { no_run: false, test_type: TestType::Unknown, }, - testfn: DynTestFn(Box::new(move || Ok(()))), + testfn: DynTestFn(Arc::new(move || Ok(()))), }) .collect(); - TestList::new(tests, TestListOrder::Sorted) + (tests, TestListOrder::Sorted) } let substr = - filter_tests(&TestOpts { filters: vec!["base".into()], ..TestOpts::new() }, tests()); + filter_tests_owned(&TestOpts { filters: vec!["base".into()], ..TestOpts::new() }, tests()); assert_eq!(substr.len(), 4); let substr = - filter_tests(&TestOpts { filters: vec!["bas".into()], ..TestOpts::new() }, tests()); + filter_tests_owned(&TestOpts { filters: vec!["bas".into()], ..TestOpts::new() }, tests()); assert_eq!(substr.len(), 4); - let substr = - filter_tests(&TestOpts { filters: vec!["::test".into()], ..TestOpts::new() }, tests()); + let substr = filter_tests_owned( + &TestOpts { filters: vec!["::test".into()], ..TestOpts::new() }, + tests(), + ); assert_eq!(substr.len(), 3); - let substr = - filter_tests(&TestOpts { filters: vec!["base::test".into()], ..TestOpts::new() }, tests()); + let substr = filter_tests_owned( + &TestOpts { filters: vec!["base::test".into()], ..TestOpts::new() }, + tests(), + ); assert_eq!(substr.len(), 3); - let substr = filter_tests( + let substr = filter_tests_owned( &TestOpts { filters: vec!["test1".into(), "test2".into()], ..TestOpts::new() }, tests(), ); assert_eq!(substr.len(), 2); - let exact = filter_tests( + let exact = filter_tests_owned( &TestOpts { filters: vec!["base".into()], filter_exact: true, ..TestOpts::new() }, tests(), ); assert_eq!(exact.len(), 1); - let exact = filter_tests( + let exact = filter_tests_owned( &TestOpts { filters: vec!["bas".into()], filter_exact: true, ..TestOpts::new() }, tests(), ); assert_eq!(exact.len(), 0); - let exact = filter_tests( + let exact = filter_tests_owned( &TestOpts { filters: vec!["::test".into()], filter_exact: true, ..TestOpts::new() }, tests(), ); assert_eq!(exact.len(), 0); - let exact = filter_tests( + let exact = filter_tests_owned( &TestOpts { filters: vec!["base::test".into()], filter_exact: true, ..TestOpts::new() }, tests(), ); assert_eq!(exact.len(), 1); - let exact = filter_tests( + let exact = filter_tests_owned( &TestOpts { filters: vec!["base".into(), "base::test".into()], filter_exact: true, @@ -650,7 +663,7 @@ fn sample_tests() -> Vec { no_run: false, test_type: TestType::Unknown, }, - testfn: DynTestFn(Box::new(testfn)), + testfn: DynTestFn(Arc::new(testfn)), }; tests.push(test); } @@ -900,7 +913,7 @@ fn test_dyn_bench_returning_err_fails_when_run_as_test() { no_run: false, test_type: TestType::Unknown, }, - testfn: DynBenchFn(Box::new(f)), + testfn: DynBenchFn(Arc::new(f)), }; let (tx, rx) = channel(); let notify = move |event: TestEvent| { @@ -909,8 +922,10 @@ fn test_dyn_bench_returning_err_fails_when_run_as_test() { } Ok(()) }; - let tests = TestList::new(vec![desc], TestListOrder::Unsorted); - run_tests(&TestOpts { run_tests: true, ..TestOpts::new() }, tests, notify).unwrap(); + let opts = TestOpts { run_tests: true, ..TestOpts::new() }; + let tests = (vec![desc], TestListOrder::Unsorted); + let filtered_tests = filter_tests_owned(&opts, tests); + run_tests(&opts, filtered_tests, 1, notify).unwrap(); let result = rx.recv().unwrap().result; assert_eq!(result, TrFailed); } diff --git a/library/test/src/types.rs b/library/test/src/types.rs index 14c81bc2d1cf1..7dd6994e8e54c 100644 --- a/library/test/src/types.rs +++ b/library/test/src/types.rs @@ -2,6 +2,7 @@ use std::borrow::Cow; use std::fmt; +use std::sync::Arc; use std::sync::mpsc::Sender; pub use NamePadding::*; @@ -81,13 +82,14 @@ impl fmt::Display for TestName { // then the test fails. We may need to come up with a more clever // definition of test in order to support isolation of tests into // threads. +#[derive(Clone)] pub enum TestFn { StaticTestFn(fn() -> Result<(), String>), StaticBenchFn(fn(&mut Bencher) -> Result<(), String>), StaticBenchAsTestFn(fn(&mut Bencher) -> Result<(), String>), - DynTestFn(Box Result<(), String> + Send>), - DynBenchFn(Box Result<(), String> + Send>), - DynBenchAsTestFn(Box Result<(), String> + Send>), + DynTestFn(Arc Result<(), String> + Send + Sync>), + DynBenchFn(Arc Result<(), String> + Send + Sync>), + DynBenchAsTestFn(Arc Result<(), String> + Send + Sync>), } impl TestFn { @@ -134,16 +136,16 @@ pub(crate) enum Runnable { pub(crate) enum RunnableTest { Static(fn() -> Result<(), String>), - Dynamic(Box Result<(), String> + Send>), + Dynamic(Arc Result<(), String> + Send + Sync>), StaticBenchAsTest(fn(&mut Bencher) -> Result<(), String>), - DynamicBenchAsTest(Box Result<(), String> + Send>), + DynamicBenchAsTest(Arc Result<(), String> + Send + Sync>), } impl RunnableTest { pub(crate) fn run(self) -> Result<(), String> { match self { RunnableTest::Static(f) => __rust_begin_short_backtrace(f), - RunnableTest::Dynamic(f) => __rust_begin_short_backtrace(f), + RunnableTest::Dynamic(f) => __rust_begin_short_backtrace(|| f()), RunnableTest::StaticBenchAsTest(f) => { crate::bench::run_once(|b| __rust_begin_short_backtrace(|| f(b))) } @@ -165,7 +167,7 @@ impl RunnableTest { pub(crate) enum RunnableBench { Static(fn(&mut Bencher) -> Result<(), String>), - Dynamic(Box Result<(), String> + Send>), + Dynamic(Arc Result<(), String> + Send + Sync>), } impl RunnableBench { @@ -181,7 +183,7 @@ impl RunnableBench { crate::bench::benchmark(id, desc.clone(), monitor_ch.clone(), nocapture, f) } RunnableBench::Dynamic(f) => { - crate::bench::benchmark(id, desc.clone(), monitor_ch.clone(), nocapture, f) + crate::bench::benchmark(id, desc.clone(), monitor_ch.clone(), nocapture, |b| f(b)) } } } @@ -245,7 +247,7 @@ impl TestDesc { } } -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct TestDescAndFn { pub desc: TestDesc, pub testfn: TestFn, @@ -301,13 +303,13 @@ pub enum TestListOrder { /// A list of tests, tagged with whether they are sorted by name. #[derive(Debug)] -pub struct TestList { - pub tests: Vec, +pub struct TestList<'a> { + pub tests: &'a [&'a TestDescAndFn], pub order: TestListOrder, } -impl TestList { - pub fn new(tests: Vec, order: TestListOrder) -> Self { +impl<'a> TestList<'a> { + pub fn new(tests: &'a [&'a TestDescAndFn], order: TestListOrder) -> Self { Self { tests, order } } } diff --git a/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-structs.md b/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-structs.md index d5a218dfa87c0..7ca97b7b059e4 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-structs.md +++ b/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-structs.md @@ -93,7 +93,7 @@ In the end, the `Diagnostic` derive will generate an implementation of `Diagnostic` that looks like the following: ```rust,ignore -impl<'a, G: EmissionGuarantee> Diagnostic<'a> for FieldAlreadyDeclared { +impl<'a, G> Diagnostic<'a> for FieldAlreadyDeclared { fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> { let mut diag = Diag::new(dcx, level, "field `{$field_name}` is already declared"); diag.set_span(self.span); diff --git a/src/doc/rustc-dev-guide/src/test-implementation.md b/src/doc/rustc-dev-guide/src/test-implementation.md index 14a66e002dba9..707ba040609e0 100644 --- a/src/doc/rustc-dev-guide/src/test-implementation.md +++ b/src/doc/rustc-dev-guide/src/test-implementation.md @@ -90,7 +90,7 @@ something with them using [`rustc_ast`][ast] generates a module like so: #[main] pub fn main() { extern crate test; - test::test_main_static(&[&path::to::test1, /*...*/]); + test::test_main_env_args(&[&path::to::test1, /*...*/]); } ``` @@ -98,7 +98,7 @@ Here `path::to::test1` is a constant of type [`test::TestDescAndFn`][tdaf]. While this transformation is simple, it gives us a lot of insight into how tests are actually run. The tests are aggregated into an array and passed to -a test runner called `test_main_static`. We'll come back to exactly what +a test runner called `test_main_env_args`. We'll come back to exactly what [`TestDescAndFn`][tdaf] is, but for now, the key takeaway is that there is a crate called [`test`][test] that is part of Rust core, that implements all of the runtime for testing. [`test`][test]'s interface is unstable, so the only stable way @@ -124,7 +124,7 @@ configuration information as well. `test` encodes this configuration data into a `struct` called [`TestDesc`]. For each test function in a crate, [`rustc_ast`][rustc_ast] will parse its attributes and generate a [`TestDesc`] instance. It then combines the [`TestDesc`] and test function into the -predictably named [`TestDescAndFn`][tdaf] `struct`, that [`test_main_static`] +predictably named [`TestDescAndFn`][tdaf] `struct`, that [`test_main_env_args`] operates on. For a given test, the generated [`TestDescAndFn`][tdaf] instance looks like so: @@ -161,4 +161,4 @@ $ rustc my_mod.rs -Z unpretty=hir [Symbol]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/symbol/struct.Symbol.html [test]: https://doc.rust-lang.org/test/index.html [tdaf]: https://doc.rust-lang.org/test/struct.TestDescAndFn.html -[`test_main_static`]: https://doc.rust-lang.org/test/fn.test_main_static.html +[`test_main_env_args`]: https://doc.rust-lang.org/test/fn.test_main_env_args.html diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 80affbd132bfe..0ecbc5927cf48 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -423,16 +423,36 @@ pub(crate) fn run_tests( // `running 0 tests...`. if ran_edition_tests == 0 || !standalone_tests.is_empty() { standalone_tests.sort_by(|a, b| a.desc.name.as_slice().cmp(b.desc.name.as_slice())); - test::test_main_with_exit_callback(&test_args, standalone_tests, None, || { - let times = times.times_in_secs(); - // We ensure temp dir destructor is called. - std::mem::drop(temp_dir.take()); - if let Some((total_time, compilation_time)) = times { - test::print_merged_doctests_times(&test_args, total_time, compilation_time); + cfg_select! { + bootstrap => { + test::test_main_with_exit_callback(&test_args, standalone_tests, None, || { + let times = times.times_in_secs(); + // We ensure temp dir destructor is called. + std::mem::drop(temp_dir.take()); + if let Some((total_time, compilation_time)) = times { + test::print_merged_doctests_times(&test_args, total_time, compilation_time); + } + }); + } + _ => { + // We need a vector of `&TestDescAndFn`. + let standalone_test_refs = &standalone_tests.iter().collect::>(); + let exit = test::test_main(&test_args, standalone_test_refs); + let times = times.times_in_secs(); + // We ensure temp dir destructor is called. + std::mem::drop(standalone_tests); + std::mem::drop(temp_dir.take()); + if let Some((total_time, compilation_time)) = times { + test::print_merged_doctests_times(&test_args, total_time, compilation_time); + } + // Fall through on success, the caller may want to do more stuff. + if exit != std::process::ExitCode::SUCCESS { + exit.exit_process(); + } } - }); + } } else { - // If the first condition branch exited successfully, `test_main_with_exit_callback` will + // If the first condition branch exited successfully, it will // not exit the process. So to prevent displaying the times twice, we put it behind an // `else` condition. if let Some((total_time, compilation_time)) = times.times_in_secs() { @@ -442,7 +462,7 @@ pub(crate) fn run_tests( // We ensure temp dir destructor is called. std::mem::drop(temp_dir); if nb_errors != 0 { - std::process::exit(test::ERROR_EXIT_CODE); + std::process::exit(test::ERROR_EXIT_CODE.into()); } } @@ -557,13 +577,13 @@ fn wrapped_rustc_command(rustc_wrappers: &[PathBuf], rustc_binary: &Path) -> Com /// (if multiple doctests are merged), `main` function, /// and everything needed to calculate the compiler's command-line arguments. /// The `# ` prefix on boring lines has also been stripped. -pub(crate) struct RunnableDocTest { +pub(crate) struct RunnableDocTest<'a> { /// In a merged test, this is the code for the "bundle" that contains the actual doctests. /// In a standalone test this is just the regular test code. full_test_code: String, full_test_line_offset: usize, - test_opts: IndividualTestOptions, - global_opts: GlobalTestOptions, + test_opts: &'a IndividualTestOptions, + global_opts: &'a GlobalTestOptions, langstr: LangString, line: usize, edition: Edition, @@ -573,7 +593,7 @@ pub(crate) struct RunnableDocTest { merged_test_runner_code: Option, } -impl RunnableDocTest { +impl RunnableDocTest<'_> { fn path_for_merged_doctest_bundle(&self) -> PathBuf { self.test_opts.outdir.path().join(format!("doctest_bundle_{}.rs", self.edition)) } @@ -592,7 +612,7 @@ impl RunnableDocTest { /// /// Returns a tuple containing the `Duration` of the compilation and the `Result` of the test. fn run_test( - doctest: RunnableDocTest, + doctest: RunnableDocTest<'_>, rustdoc_options: &RustdocOptions, supports_color: bool, report_unused_externs: impl Fn(UnusedExterns), @@ -1155,26 +1175,38 @@ fn generate_test_desc_and_fn( no_run: scraped_test.no_run(&rustdoc_options), test_type: test::TestType::DocTest, }, + #[cfg(bootstrap)] testfn: test::DynTestFn(Box::new(move || { doctest_run_fn( - rustdoc_test_options, - opts, - test, - scraped_test, - rustdoc_options, - unused_externs, + &rustdoc_test_options, + &opts, + &test, + &scraped_test, + &rustdoc_options, + &unused_externs, + ) + })), + #[cfg(not(bootstrap))] + testfn: test::DynTestFn(Arc::new(move || { + doctest_run_fn( + &rustdoc_test_options, + &opts, + &test, + &scraped_test, + &rustdoc_options, + &unused_externs, ) })), } } fn doctest_run_fn( - test_opts: IndividualTestOptions, - global_opts: GlobalTestOptions, - doctest: DocTestBuilder, - scraped_test: ScrapedDocTest, - rustdoc_options: Arc, - unused_externs: Arc>>, + test_opts: &IndividualTestOptions, + global_opts: &GlobalTestOptions, + doctest: &DocTestBuilder, + scraped_test: &ScrapedDocTest, + rustdoc_options: &RustdocOptions, + unused_externs: &Mutex>, ) -> Result<(), String> { let report_unused_externs = |uext| { unused_externs.lock().unwrap().push(uext); diff --git a/src/librustdoc/doctest/runner.rs b/src/librustdoc/doctest/runner.rs index ff9397ea2460b..43ed48aad95d4 100644 --- a/src/librustdoc/doctest/runner.rs +++ b/src/librustdoc/doctest/runner.rs @@ -14,6 +14,7 @@ use crate::html::markdown::{Ignore, LangString}; pub(crate) struct DocTestRunner { crate_attrs: FxIndexSet, global_crate_attrs: FxIndexSet, + /// A comma-separated list of references to test descriptors. ids: String, output: String, output_merged_tests: String, @@ -54,7 +55,7 @@ impl DocTestRunner { } } self.ids.push_str(&format!( - "tests.push({}::TEST);\n", + "&{}::TEST,\n", generate_mergeable_doctest( doctest, scraped_test, @@ -166,18 +167,14 @@ mod __doctest_mod {{ #[rustc_main] fn main() -> std::process::ExitCode {{ -let tests = {{ - let mut tests = Vec::with_capacity({nb_tests}); - {ids} - tests -}}; +let tests = &[{ids}]; let test_args = &[{test_args}]; const ENV_BIN: &'static str = \"RUSTDOC_DOCTEST_BIN_PATH\"; if let Ok(binary) = std::env::var(ENV_BIN) {{ let _ = crate::__doctest_mod::BINARY_PATH.set(binary.into()); unsafe {{ std::env::remove_var(ENV_BIN); }} - return std::process::Termination::report(test::test_main(test_args, tests, None)); + return test::test_main(test_args, tests); }} else if let Ok(nb_test) = std::env::var(__doctest_mod::RUN_OPTION) {{ if let Ok(nb_test) = nb_test.parse::() {{ if let Some(test) = tests.get(nb_test) {{ @@ -191,9 +188,8 @@ if let Ok(binary) = std::env::var(ENV_BIN) {{ eprintln!(\"WARNING: No rustdoc doctest environment variable provided so doctests will be run in \ the same process\"); -std::process::Termination::report(test::test_main(test_args, tests, None)) +test::test_main(test_args, tests) }}", - nb_tests = self.nb_tests, output = self.output_merged_tests, ids = self.ids, ) @@ -201,8 +197,8 @@ std::process::Termination::report(test::test_main(test_args, tests, None)) let runnable_test = RunnableDocTest { full_test_code: format!("{code_prefix}{code}", code = self.output), full_test_line_offset: 0, - test_opts: test_options, - global_opts: opts.clone(), + test_opts: &test_options, + global_opts: opts, langstr: LangString::default(), line: 0, edition, @@ -261,7 +257,7 @@ fn main() {returns_result} {{ output_merged_tests, " mod {test_id} {{ -pub const TEST: test::TestDescAndFn = test::TestDescAndFn::new_doctest( +pub static TEST: test::TestDescAndFn = test::TestDescAndFn::new_doctest( {test_name:?}, {ignore}, {file:?}, {line}, {no_run}, {should_panic}, test::StaticTestFn( || {{{runner}}}, diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 6c93099b74547..20e992945c917 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -1,4 +1,5 @@ // tidy-alphabetical-start +#![cfg_attr(not(bootstrap), feature(exitcode_exit_method))] #![doc( html_root_url = "https://doc.rust-lang.org/nightly/", html_playground_url = "https://play.rust-lang.org/" diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs index 39c0e424b6585..4cda9c4aeb568 100644 --- a/src/tools/clippy/clippy_utils/src/diagnostics.rs +++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs @@ -10,7 +10,7 @@ use rustc_errors::{Applicability, Diag, DiagCtxtHandle, DiagMessage, Diagnostic, Level, MultiSpan}; #[cfg(debug_assertions)] -use rustc_errors::{EmissionGuarantee, SubstitutionPart, Suggestions}; +use rustc_errors::{SubstitutionPart, Suggestions}; use rustc_hir::HirId; use rustc_lint::{LateContext, Lint, LintContext}; use rustc_span::Span; @@ -43,7 +43,7 @@ fn docs_link(diag: &mut Diag<'_, ()>, lint: &'static Lint) { /// /// This function makes sure we also validate them in debug clippy builds. #[cfg(debug_assertions)] -fn validate_diag(diag: &Diag<'_, impl EmissionGuarantee>) { +fn validate_diag(diag: &Diag<'_, G>) { let suggestions = match &diag.suggestions { Suggestions::Enabled(suggs) => &**suggs, Suggestions::Sealed(suggs) => &**suggs, diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 6eeef786b9a1e..d4ee85dade5ad 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -2361,9 +2361,9 @@ fn test_item_names(tcx: TyCtxt<'_>, module: LocalModId) -> Vec { Entry::Vacant(entry) => { let mut names = Vec::new(); for id in tcx.hir_module_free_items(module) { - if tcx.def_kind(id.owner_id) == DefKind::Const + if matches!(tcx.def_kind(id.owner_id), DefKind::Static { .. }) && let item = tcx.hir_item(id) - && let ItemKind::Const(ident, _generics, ty, _body) = item.kind + && let ItemKind::Static(_mut, ident, ty, _body) = item.kind && let TyKind::Path(QPath::Resolved(_, path)) = ty.kind // We could also check for the type name `test::TestDescAndFn` && let Res::Def(DefKind::Struct, _) = path.res diff --git a/src/tools/rust-analyzer/.github/workflows/gen-lints.yml b/src/tools/rust-analyzer/.github/workflows/gen-lints.yml index c978e3571c40d..05dfdc2fc4534 100644 --- a/src/tools/rust-analyzer/.github/workflows/gen-lints.yml +++ b/src/tools/rust-analyzer/.github/workflows/gen-lints.yml @@ -11,6 +11,7 @@ defaults: jobs: lints-gen: + if: ${{ github.repository == 'rust-lang/rust-analyzer' || github.event_name == 'workflow_dispatch' }} name: Generate lints runs-on: ubuntu-latest permissions: diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 5835ed9e552e7..cf4ba4404b367 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -1889,6 +1889,7 @@ dependencies = [ "line-index 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "paths", "proc-macro-test", + "rustc-hash 2.1.2", "span", "stdx", ] diff --git a/src/tools/rust-analyzer/clippy.toml b/src/tools/rust-analyzer/clippy.toml index 1046cb3d56bc6..f0a8a6132c6a2 100644 --- a/src/tools/rust-analyzer/clippy.toml +++ b/src/tools/rust-analyzer/clippy.toml @@ -1,9 +1,9 @@ disallowed-types = [ - { path = "std::collections::HashMap", reason = "use FxHashMap" }, - { path = "std::collections::HashSet", reason = "use FxHashSet" }, - { path = "std::collections::hash_map::RandomState", reason = "use BuildHasherDefault"} + { path = "std::collections::HashMap", replacement = "rustc_hash::FxHashMap" }, + { path = "std::collections::HashSet", replacement = "rustc_hash::FxHashSet" }, + { path = "std::collections::hash_map::RandomState", replacement = "std::hash::BuildHasherDefault"} ] disallowed-methods = [ - { path = "std::process::Command::new", reason = "use `toolchain::command` instead as it forces the choice of a working directory" }, + { path = "std::process::Command::new", replacement = "toolchain::command", reason = "the latter forces the choice of a working directory" }, ] diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs index 230b7cbed680f..229ed82e06cc2 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/input.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs @@ -8,6 +8,7 @@ use std::error::Error; use std::hash::BuildHasherDefault; +use std::str::FromStr; use std::{fmt, mem, ops}; use cfg::{CfgOptions, HashableCfgOptions}; @@ -315,14 +316,17 @@ impl ReleaseChannel { ReleaseChannel::Nightly => "nightly", } } +} + +impl FromStr for ReleaseChannel { + type Err = (); - #[allow(clippy::should_implement_trait)] - pub fn from_str(str: &str) -> Option { - Some(match str { + fn from_str(str: &str) -> Result { + Ok(match str { "" | "stable" => ReleaseChannel::Stable, "nightly" => ReleaseChannel::Nightly, _ if str.starts_with("beta") => ReleaseChannel::Beta, - _ => return None, + _ => return Err(()), }) } } diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs index 0da1faba676c0..1ce5f17e0e26c 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs @@ -19,6 +19,7 @@ use std::{ cell::RefCell, hash::BuildHasherDefault, panic, + str::FromStr as _, sync::{Once, atomic::AtomicUsize}, }; @@ -327,7 +328,7 @@ impl CrateWorkspaceData { } pub fn toolchain_channel(db: &dyn salsa::Database, krate: Crate) -> Option { - krate.workspace_data(db).toolchain.as_ref().and_then(|v| ReleaseChannel::from_str(&v.pre)) + krate.workspace_data(db).toolchain.as_ref().and_then(|v| ReleaseChannel::from_str(&v.pre).ok()) } #[salsa::input(singleton, debug)] diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attrs/docs.rs b/src/tools/rust-analyzer/crates/hir-def/src/attrs/docs.rs index ac8ca70ccc4b9..583bde92679dd 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/attrs/docs.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/attrs/docs.rs @@ -608,6 +608,7 @@ fn expand_doc_macro_call<'db>( ExpandTo::Expr, expander.krate, expander.macro_depth + 1, + expander.recursion_limit, |path| { expander.resolver.resolve_path_as_macro_def(expander.db, path, Some(MacroSubNs::Bang)) }, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/dyn_map.rs b/src/tools/rust-analyzer/crates/hir-def/src/dyn_map.rs index c38ceccd1fc09..92400d0715395 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/dyn_map.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/dyn_map.rs @@ -119,10 +119,6 @@ pub struct Key { } impl Key { - #[allow( - clippy::new_without_default, - reason = "this a const fn, so it can't be default yet. See " - )] pub(crate) const fn new() -> Key { Key { _phantom: PhantomData } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs index 3a63ca80ffc68..7d01a7c436e28 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs @@ -624,7 +624,6 @@ impl ExpressionStore { visitor.on_expr_opt(*end); } Pat::Lit(expr) | Pat::Expr(expr) => visitor.on_expr(*expr), - Pat::ConstBlock(expr) => visitor.on_anon_const_expr(*expr), Pat::Path(path) => visitor.on_path(path), Pat::Wild | Pat::Missing | Pat::Rest | Pat::NotNull => {} &Pat::Bind { subpat, id: _ } => visitor.on_pat_opt(subpat), diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs index a974815cc6423..12a2263697908 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs @@ -111,7 +111,8 @@ impl<'db> Expander<'db> { call_site.ctx, expands_to, krate, - this.macro_depth, + this.macro_depth + 1, + this.recursion_limit, |path| resolver(path).map(|it| it.definition(db)), eager_callback, ) { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs index bb60766197b37..b5d5145927702 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs @@ -3082,16 +3082,7 @@ impl<'db> ExprCollector<'db> { Pat::Deref { inner } } ast::Pat::NotNull(_) => Pat::NotNull, - ast::Pat::ConstBlockPat(const_block_pat) => { - if let Some(block) = const_block_pat.block_expr() { - let expr_id = self.with_label_rib(RibKind::Constant, |this| { - this.with_binding_owner(|this| this.collect_block(block)) - }); - Pat::ConstBlock(expr_id) - } else { - Pat::Missing - } - } + ast::Pat::ConstBlockPat(_) => Pat::Missing, ast::Pat::MacroPat(mac) => { return self.collect_macro_pat_with(mac.clone(), |this, expanded_pat| { this.collect_pat(expanded_pat, binding_list) @@ -3277,16 +3268,6 @@ impl<'db> ExprCollector<'db> { let Some((literal, _)) = pat_literal_to_hir(it) else { return self.missing_expr() }; self.alloc_expr_from_pat(Expr::Literal(literal), ptr) } - ast::Pat::ConstBlockPat(it) => { - if let Some(block) = it.block_expr() { - let expr_id = self.with_label_rib(RibKind::Constant, |this| { - this.with_binding_owner(|this| this.collect_block(block)) - }); - self.alloc_expr_from_pat(Expr::Const(expr_id), ptr) - } else { - self.missing_expr() - } - } ast::Pat::PathPat(it) => { let path = it .path() diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs index 7d7b948d34149..1d01605695a74 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs @@ -1033,10 +1033,6 @@ impl Printer<'_> { self.print_pat(*inner); w!(self, ")"); } - Pat::ConstBlock(c) => { - w!(self, "const "); - self.print_expr(*c); - } Pat::Expr(expr) => { self.print_expr_in(prec, *expr); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs index 24baa0f8c8d89..a7403a0e555b9 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs @@ -115,7 +115,10 @@ impl ExprScopes { } /// If `scope` refers to a macro def scope, returns the corresponding `MacroId`. - #[allow(clippy::borrowed_box)] // If we return `&MacroDefId` we need to move it, this way we just clone the `Box`. + #[expect( + clippy::borrowed_box, + reason = "If we return `&MacroDefId` we need to move it, this way we just clone the `Box`." + )] pub fn macro_def(&self, scope: ScopeId) -> Option<&Box> { match &self.scopes[scope].kind { ScopeKind::MacroDef(macro_def) => Some(macro_def), @@ -818,66 +821,4 @@ fn test() { 100, ); } - #[test] - fn pattern_const_block_expressions_have_scopes() { - do_check( - r#" -fn foo() { - match () { - const { |x: i32| { let y = x; $0 } } => (), - } -} -"#, - &["y", "x"], - ); - } - - #[test] - fn let_pattern_expr_scope() { - do_check( - r#" -fn foo(param: usize) { - let local = 0; - let const { $0 } = (); -} -"#, - &["param"], - ); - } - - #[test] - fn closure_param_pattern_expr_scope() { - do_check( - r#" -fn foo(param: usize) { - let local = 0; - let _ = |const { $0 }: ()| (); -} -"#, - &["param"], - ); - } - - #[test] - fn fn_param_pattern_expr_scope() { - do_check( - r#" -fn foo(param: usize, const { $0 }: ()) {} -"#, - &["param"], - ); - } - - #[test] - fn if_let_pattern_expr_scope() { - do_check( - r#" -fn foo(param: usize) { - let local = 0; - if let const { $0 } = () {} -} -"#, - &["param"], - ); - } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs index 5785a546513c9..85a41c6495159 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs @@ -800,7 +800,6 @@ pub enum Pat { inner: PatId, }, NotNull, - ConstBlock(ExprId), /// An expression inside a pattern. That can only occur inside assignments. /// /// E.g. in `(a, *b) = (1, &mut 2)`, `*b` is an expression. @@ -813,7 +812,6 @@ impl Pat { Pat::Range { .. } | Pat::Lit(..) | Pat::Path(..) - | Pat::ConstBlock(..) | Pat::Wild | Pat::Missing | Pat::Rest diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs index 366857f233168..855b16bc28673 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs @@ -169,7 +169,6 @@ enum PositionUsedAs { } use PositionUsedAs::*; -#[allow(clippy::unnecessary_lazy_evaluations)] pub(crate) fn parse( s: &ast::String, string_ptr: AstPtr, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs index 0712a025b49cb..77d00072fd2df 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs @@ -1442,6 +1442,7 @@ pub fn macro_call_as_call_id( expand_to: ExpandTo, krate: Crate, macro_depth: u32, + recursion_limit: u32, resolver: impl Fn(&ModPath) -> Option + Copy, eager_callback: &mut dyn FnMut( InFile<(syntax::AstPtr, span::FileAstId)>, @@ -1459,6 +1460,7 @@ pub fn macro_call_as_call_id( def, call_site, macro_depth, + recursion_limit, &|path| resolver(path).filter(MacroDefId::is_fn_like), eager_callback, ), diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs index 7120980dd30cf..1ba636ee901c5 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs @@ -628,3 +628,34 @@ const _: bool = foo::<(), fn() -> Foo>(1, ); "#]], ); } + +#[test] +fn eager_recursion_limit() { + check( + r#" +//- minicore: concat + +macro_rules! concat_separator { + () => { + concat!("", concat_separator!()) + }; +} + +fn main() { + concat_separator!() +} + "#, + expect![[r#" + +macro_rules! concat_separator { + () => { + concat!("", concat_separator!()) + }; +} + +fn main() { + concat!("", concat_separator!()) +} + "#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs index 8dea9a4eda1da..0e27d74516007 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs @@ -323,6 +323,7 @@ impl<'db> AssocItemCollector<'db> { ExpandTo::Items, self.module_id.krate(self.db), self.macro_depth + 1, + self.def_map.recursion_limit(), resolver, &mut |ptr, call_id| { self.macro_calls.push((ptr.map(|(_, it)| it.upcast()), call_id)) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs index ce359ebda6af2..e40e4d99bdbd0 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs @@ -1360,6 +1360,7 @@ impl<'db> DefCollector<'db> { *expand_to, self.def_map.krate, directive.depth, + self.def_map.recursion_limit(), resolver_def_id, &mut |ptr, call_id| { eager_callback_buffer.push((directive.module_id, ptr, call_id)); @@ -1793,6 +1794,7 @@ impl<'db> DefCollector<'db> { *expand_to, self.def_map.krate, directive.depth, + self.def_map.recursion_limit(), |path| { let resolved_res = self.def_map.resolve_path_fp_with_macro( self.crate_local_def_map.unwrap_or(&self.local_def_map), @@ -2698,6 +2700,7 @@ impl ModCollector<'_, '_> { expand_to, self.def_collector.def_map.krate, self.macro_depth + 1, + self.def_collector.def_map.recursion_limit(), |path| { path.as_ident().and_then(|name| { let def_map = &self.def_collector.def_map; diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs index d84756377fc75..a7fcbc6f9f535 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs @@ -1,5 +1,4 @@ //! A simplified version of quote-crate like quasi quote macro -#![allow(clippy::crate_in_macro_def)] use intern::{Symbol, sym}; use span::Span; @@ -185,7 +184,7 @@ macro_rules! impl_to_to_tokentrees { $( impl ToTokenTree for $ty { fn to_tokens($this, $span: Span, builder: &mut TopSubtreeBuilder) { - let leaf: crate::tt::Leaf = $im.into(); + let leaf: $crate::tt::Leaf = $im.into(); builder.push(leaf); } } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs b/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs index 7002b70a7687b..bddec50c91c04 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs @@ -26,8 +26,8 @@ use syntax::{ use syntax_bridge::DocCommentDesugarMode; use crate::{ - AstId, EagerCallInfo, ExpandError, ExpandResult, ExpandTo, ExpansionSpanMap, InFile, - MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind, + AstId, EagerCallInfo, ExpandError, ExpandErrorKind, ExpandResult, ExpandTo, ExpansionSpanMap, + InFile, MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind, ast::{self, AstNode}, mod_path::ModPath, }; @@ -45,6 +45,7 @@ pub fn expand_eager_macro_input( def: MacroDefId, call_site: SyntaxContext, macro_depth: u32, + recursion_limit: u32, resolver: &dyn Fn(&ModPath) -> Option, eager_callback: EagerCallBackFn<'_>, ) -> ExpandResult> { @@ -62,7 +63,7 @@ pub fn expand_eager_macro_input( macro_depth, }; let arg_id = MacroCallId::new(db, loc); - #[allow(deprecated)] // builtin eager macros are never derives + #[expect(deprecated, reason = "builtin eager macros are never derives")] let (_, _, span) = arg_id.macro_arg(db); let ExpandResult { value: (arg_exp, arg_exp_map), err: parse_err } = arg_id.parse_macro_expansion(db); @@ -79,6 +80,7 @@ pub fn expand_eager_macro_input( krate, call_site, macro_depth, + recursion_limit, resolver, eager_callback, ) @@ -155,6 +157,7 @@ fn eager_macro_recur( krate: Crate, call_site: SyntaxContext, macro_depth: u32, + recursion_limit: u32, macro_resolver: &dyn Fn(&ModPath) -> Option, eager_callback: EagerCallBackFn<'_>, ) -> ExpandResult> { @@ -213,6 +216,14 @@ fn eager_macro_recur( } }; let ast_id = curr.file_id.ast_id_map(db).ast_id(&call); + + if macro_depth > recursion_limit { + return ExpandResult::only_err(ExpandError::new( + span_map.span_at(call.syntax().text_range().start()), + ExpandErrorKind::RecursionOverflow, + )); + } + let ExpandResult { value, err } = match def.kind { MacroDefKind::BuiltInEager(..) => { let ExpandResult { value, err } = expand_eager_macro_input( @@ -223,6 +234,7 @@ fn eager_macro_recur( def, call_site, macro_depth + 1, + recursion_limit, macro_resolver, eager_callback, ); @@ -277,6 +289,7 @@ fn eager_macro_recur( krate, call_site, macro_depth + 1, + recursion_limit, macro_resolver, eager_callback, ); diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs index 8781358822064..2fda00d6af8d0 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs @@ -343,7 +343,6 @@ pub(crate) fn reverse_fixups(tt: &mut TopSubtree, undo_info: &SyntaxFixupUndoInf let top_subtree = tt.top_subtree(); let open_span = top_subtree.delimiter.open; let close_span = top_subtree.delimiter.close; - #[allow(deprecated)] if never!( close_span.anchor.ast_id == FIXUP_DUMMY_AST_ID || open_span.anchor.ast_id == FIXUP_DUMMY_AST_ID diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs index f7ac3f1c02694..e646c21ec8c5e 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs @@ -519,7 +519,7 @@ impl MacroCallId { /// This is not connected to the database so it does not cache the result. However, the inner [macro_arg] query is /// /// [macro_arg]: Self::macro_arg - #[allow(deprecated)] // we are macro_arg_considering_derives + #[expect(deprecated, reason = "we are `macro_arg_considering_derives`")] pub fn macro_arg_considering_derives<'db>( self, db: &'db dyn SourceDatabase, @@ -537,6 +537,12 @@ impl MacroCallId { /// query, only typing in the macro call itself changes the returned /// subtree. #[salsa::tracked(returns(ref))] + #[allow( + useless_deprecated, + unused_attributes, + reason = "salsa bug, see https://github.com/salsa-rs/salsa/issues/1307" + )] + #[deprecated = "calling this is incorrect, call `macro_arg_considering_derives` instead"] fn macro_arg(self, db: &dyn SourceDatabase) -> MacroArgResult { let loc = self.loc(db); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/builtin_derive.rs b/src/tools/rust-analyzer/crates/hir-ty/src/builtin_derive.rs index baa7b87e457f9..53a232adfc7ac 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/builtin_derive.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/builtin_derive.rs @@ -195,7 +195,7 @@ pub fn predicates(db: &dyn HirDatabase, impl_: BuiltinDeriveImplId) -> GenericPr else { // Malformed derive. return GenericPredicates::from_explicit_own_predicates(StoredEarlyBinder::bind( - Clauses::empty(interner).store(), + Clauses::empty().store(), )); }; let duplicated_bounds = diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs index d65f76cdf1ceb..a1ed1e71aecc3 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs @@ -253,7 +253,7 @@ pub fn try_const_usize<'db>(db: &'db dyn HirDatabase, c: Const<'db>) -> Option { - if val.ty == default_types(db).types.usize { + if val.ty == default_types().types.usize { Some(val.value.inner().to_leaf().to_uint_unchecked()) } else { None @@ -291,7 +291,7 @@ pub fn try_const_isize<'db>(db: &'db dyn HirDatabase, c: Const<'db>) -> Option { - if val.ty == default_types(db).types.isize { + if val.ty == default_types().types.isize { Some(val.value.inner().to_leaf().to_int_unchecked()) } else { None @@ -347,7 +347,7 @@ pub(crate) fn path_to_const<'a, 'db>( | ValueNs::StructId(_) | ValueNs::EnumVariantId(_) => return Err(CreateConstError::ResolveToNonConst), }; - let args = GenericArgs::empty(interner); + let args = GenericArgs::empty(); Ok(Const::new_unevaluated(interner, UnevaluatedConst { def: konst.into(), args })) } @@ -411,7 +411,7 @@ pub(crate) fn create_anon_const<'a, 'db>( let args = if allow_using_generic_params { GenericArgs::identity_for_item(interner, owner.generic_def(interner.db).into()) } else { - GenericArgs::empty(interner) + GenericArgs::empty() }; Ok(Const::new_unevaluated( interner, @@ -426,7 +426,6 @@ pub(crate) fn const_eval_discriminant_variant<'db>( db: &'db dyn HirDatabase, variant_id: EnumVariantId, ) -> Result> { - let interner = DbInterner::new_no_crate(db); let def = variant_id.into(); let body = Body::of(db, def); let loc = variant_id.lookup(db); @@ -446,7 +445,7 @@ pub(crate) fn const_eval_discriminant_variant<'db>( let mir_body = db.monomorphized_mir_body( def.into(), - GenericArgs::empty(interner).store(), + GenericArgs::empty().store(), ParamEnvAndCrate { param_env: db.trait_environment(def.generic_def(db)), krate: def.krate(db), @@ -561,10 +560,9 @@ pub(crate) fn const_eval_static<'db>( db: &'db dyn HirDatabase, def: StaticId, ) -> Result> { - let interner = DbInterner::new_no_crate(db); let body = db.monomorphized_mir_body( def.into(), - GenericArgs::empty(interner).store(), + GenericArgs::empty().store(), ParamEnvAndCrate { param_env: db.trait_environment(def.into()), krate: def.krate(db) } .store(), )?; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs index 6ea8376e48743..b17df991f7afe 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs @@ -14,7 +14,7 @@ use crate::{ db::HirDatabase, display::DisplayTarget, mir::{IsSigned, pad16}, - next_solver::{Allocation, DbInterner, GenericArgs}, + next_solver::{Allocation, GenericArgs}, setup_tracing, test_db::TestDB, }; @@ -120,7 +120,6 @@ fn pretty_print_err(e: ConstEvalError<'_>, db: &TestDB) -> String { fn eval_goal(db: &TestDB, file_id: EditionedFileId) -> Result, ConstEvalError<'_>> { let _tracing = setup_tracing(); - let interner = DbInterner::new_no_crate(db); let module_id = db.module_for_file(file_id.file_id(db)); let def_map = module_id.def_map(db); let scope = &def_map[module_id].scope; @@ -143,7 +142,7 @@ fn eval_goal(db: &TestDB, file_id: EditionedFileId) -> Result, Co _ => None, }) .expect("No const named GOAL found in the test"); - db.const_eval(const_id, GenericArgs::empty(interner), None) + db.const_eval(const_id, GenericArgs::empty(), None) } #[test] diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs index 898d9ea8edf3d..ab6294cb375df 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs @@ -469,7 +469,8 @@ fn floating_point() { IsSigned::Yes, )), ); - #[allow(unknown_lints, clippy::unnecessary_min_or_max)] + // FIXME: this should be an `expect`, but that currently results in `lint_expectation_unfulfilled` + #[allow(clippy::unnecessary_min_or_max, reason = "for symmetry with the expression in `GOAL`")] check_number( r#" #[rustc_intrinsic] diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs index 047a348fb09a7..17ec211bb579c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs @@ -9,8 +9,5 @@ pub use crate::diagnostics::{ expr::{ BodyValidationDiagnostic, record_literal_missing_fields, record_pattern_missing_fields, }, - unsafe_check::{ - InsideUnsafeBlock, UnsafetyReason, missing_unsafe, unsafe_operations, - unsafe_operations_for_body, - }, + unsafe_check::{InsideUnsafeBlock, UnsafetyReason, missing_unsafe, unsafe_operations}, }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs index a465f8be4e175..cccefbc8639ac 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs @@ -507,17 +507,14 @@ impl<'a> DeclValidator<'a> { self.validate_enum_variant_fields(*variant_id); } - let edition = self.edition(enum_id); let mut enum_variants_replacements = data .variants .keys() .filter_map(|name| { - to_camel_case(&name.display_no_db(edition).to_smolstr()).map(|new_name| { - Replacement { - current_name: name.clone(), - suggested_text: new_name, - expected_case: CaseType::UpperCamelCase, - } + to_camel_case(name.as_str()).map(|new_name| Replacement { + current_name: name.clone(), + suggested_text: new_name, + expected_case: CaseType::UpperCamelCase, }) }) .peekable(); @@ -717,11 +714,12 @@ impl<'a> DeclValidator<'a> { CaseType::UpperCamelCase => to_camel_case, }; let edition = self.edition(item_id); - let Some(replacement) = - to_expected_case_type(&name.display(self.db, edition).to_smolstr()).map(|new_name| { - Replacement { current_name: name.clone(), suggested_text: new_name, expected_case } - }) - else { + let Some(replacement) = to_expected_case_type(name.as_str()).map(|mut new_name| { + if is_raw_identifier(&new_name, edition) { + new_name.insert_str(0, "r#"); + } + Replacement { current_name: name.clone(), suggested_text: new_name, expected_case } + }) else { return; }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs index 94b1ec331f87d..1eb2bf0f85bff 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs @@ -703,7 +703,7 @@ fn types_of_subpatterns_do_match(pat: PatId, body: &Body, infer: &InferenceResul false if *has_type_mismatches => (), false => { let pat = &body[pat]; - if let Pat::ConstBlock(expr) | Pat::Lit(expr) = *pat { + if let Pat::Lit(expr) = *pat { *has_type_mismatches |= infer.expr_has_type_mismatch(expr); if *has_type_mismatches { return; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs index ca843c8690f28..4818b2f49bf73 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs @@ -101,25 +101,6 @@ enum UnsafeDiagnostic { DeprecatedSafe2024 { node: ExprId, inside_unsafe_block: InsideUnsafeBlock }, } -pub fn unsafe_operations_for_body( - db: &dyn HirDatabase, - infer: &InferenceResult<'_>, - def: DefWithBodyId, - body: &Body, - callback: &mut dyn FnMut(ExprOrPatId), -) { - let mut visitor_callback = |diag| { - if let UnsafeDiagnostic::UnsafeOperation { node, .. } = diag { - callback(node); - } - }; - let mut visitor = UnsafeVisitor::new(db, infer, body, def.into(), &mut visitor_callback); - visitor.walk_expr(body.root_expr()); - for param in &body.params { - visitor.walk_pat(param.formal); - } -} - pub fn unsafe_operations( db: &dyn HirDatabase, infer: &InferenceResult<'_>, @@ -258,7 +239,6 @@ impl<'db> UnsafeVisitor<'db> { | Pat::Box { .. } | Pat::Deref { .. } | Pat::Expr(..) - | Pat::ConstBlock(..) | Pat::NotNull => self.on_unsafe_op(current.into(), UnsafetyReason::UnionField), // `Or` only wraps other patterns, and `Missing`/`Wild` do not constitute a read. Pat::Missing | Pat::Rest | Pat::Wild | Pat::Or(_) => {} @@ -276,11 +256,6 @@ impl<'db> UnsafeVisitor<'db> { } } Pat::Path(path) => self.mark_unsafe_path(current.into(), path), - &Pat::ConstBlock(expr) => { - let old_inside_assignment = mem::replace(&mut self.inside_assignment, false); - self.walk_expr(expr); - self.inside_assignment = old_inside_assignment; - } &Pat::Expr(expr) => self.walk_expr(expr), _ => {} } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index a87a55b3c8980..e83962ec25ec2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -811,7 +811,7 @@ fn render_const_scalar<'db>( memory_map: &MemoryMap<'db>, ty: Ty<'db>, ) -> Result { - let param_env = ParamEnv::empty(f.interner); + let param_env = ParamEnv::empty(); let infcx = f.interner.infer_ctxt().build(TypingMode::PostAnalysis); let ty = infcx.at(&ObligationCause::dummy(), param_env).deeply_normalize(ty).unwrap_or(ty); render_const_scalar_inner(f, b, memory_map, ty, param_env) @@ -1086,7 +1086,7 @@ fn render_const_scalar_from_valtree<'db>( ty: Ty<'db>, valtree: ValTree<'db>, ) -> Result { - let param_env = ParamEnv::empty(f.interner); + let param_env = ParamEnv::empty(); let infcx = f.interner.infer_ctxt().build(TypingMode::PostAnalysis); let ty = infcx.at(&ObligationCause::dummy(), param_env).deeply_normalize(ty).unwrap_or(ty); render_const_scalar_from_valtree_inner(f, ty, valtree, param_env) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs index a70f98a0fe7bb..241beea6779e7 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs @@ -14,14 +14,13 @@ use super::{ use DynCompatibilityViolationKind::*; -#[allow(clippy::upper_case_acronyms)] #[derive(Debug, Clone, PartialEq, Eq, Hash)] enum DynCompatibilityViolationKind { SizedSelf, SelfReferential, Method(MethodViolationCode), AssocConst, - GAT, + Gat, HasNonCompatibleSuperTrait, } @@ -63,7 +62,7 @@ fn check_dyn_compatibility<'a>( DynCompatibilityViolation::SelfReferential => SelfReferential, DynCompatibilityViolation::Method(_, mvc) => Method(mvc), DynCompatibilityViolation::AssocConst(_) => AssocConst, - DynCompatibilityViolation::GAT(_) => GAT, + DynCompatibilityViolation::GAT(_) => Gat, DynCompatibilityViolation::HasNonCompatibleSuperTrait(_) => { HasNonCompatibleSuperTrait } @@ -236,7 +235,7 @@ trait GatTrait { trait SuperTrait: GatTrait {} "#, - [("GatTrait", vec![GAT]), ("SuperTrait", vec![HasNonCompatibleSuperTrait])], + [("GatTrait", vec![Gat]), ("SuperTrait", vec![HasNonCompatibleSuperTrait])], ); } @@ -396,6 +395,6 @@ trait Foo { type Bar<'a>; } "#, - [("Foo", vec![DynCompatibilityViolationKind::GAT])], + [("Foo", vec![DynCompatibilityViolationKind::Gat])], ); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs index 0ab147096a749..cbe5b671fe83a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -109,12 +109,7 @@ use crate::{ utils::TargetFeatureIsSafeInTarget, }; -// This lint has a false positive here. See the link below for details. -// -// https://github.com/rust-lang/rust/issues/57411 -#[allow(unreachable_pub)] pub use coerce::could_coerce; -#[allow(unreachable_pub)] pub use unify::{could_unify, could_unify_deeply}; use cast::{CastCheck, CastError}; @@ -1429,7 +1424,7 @@ impl<'db> InferenceContext<'db> { ) -> Self { let trait_env = db.trait_environment(generic_def); let table = unify::InferenceTable::new(db, trait_env, resolver.krate(), owner); - let types = crate::next_solver::default_types(db); + let types = crate::next_solver::default_types(); InferenceContext { result: InferenceResult::new(types.types.error), return_ty: types.types.error, // set in collect_* calls diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs index da9c5ab10fc46..6a4e38c5264a7 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs @@ -976,7 +976,7 @@ impl<'a, 'db, D: Delegate<'db>> ExprUseVisitor<'a, 'db, D> { read_discriminant(this); } } - Pat::Lit(_) | Pat::ConstBlock(_) | Pat::Range { .. } => { + Pat::Lit(_) | Pat::Range { .. } => { // When matching against a literal or range, we need to // borrow the place to compare it against the pattern. // @@ -1690,7 +1690,6 @@ impl<'db, D: Delegate<'db>> ExprUseVisitor<'_, 'db, D> { | Pat::Expr(..) | Pat::Path(_) | Pat::Lit(..) - | Pat::ConstBlock(..) | Pat::Range { .. } | Pat::Missing | Pat::Rest diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs index af301731c7156..8c9e814015897 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs @@ -192,7 +192,6 @@ impl<'db> InferenceContext<'db> { | Pat::Lit(_) | Pat::Range { .. } | Pat::Slice { .. } - | Pat::ConstBlock(_) | Pat::Record { .. } | Pat::NotNull | Pat::Missing => true, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs index 09b0d3c03d5b8..9d55bf36e5468 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs @@ -171,7 +171,6 @@ impl<'db> InferenceContext<'db> { &Expr::Assignment { target, value } => { self.store.walk_pats(target, &mut |pat| match self.store[pat] { Pat::Expr(expr) => self.infer_mut_expr(expr, Mutability::Mut), - Pat::ConstBlock(block) => self.infer_mut_expr(block, Mutability::Not), _ => {} }); self.infer_mut_expr(value, Mutability::Not); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs index 3a867286eec53..17c198879f265 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs @@ -530,9 +530,6 @@ impl<'db> InferenceContext<'db> { self.infer_slice_pat(pat, before, slice, after, expected, pat_info) } Pat::Expr(expr) => self.infer_destructuring_assignment_expr(expr, expected), - Pat::ConstBlock(expr) => { - self.infer_expr(expr, &Expectation::has_type(expected), ExprIsRead::Yes) - } } } @@ -634,9 +631,8 @@ impl<'db> InferenceContext<'db> { // All other literals result in non-reference types. // As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo" {}` unless // `deref_patterns` is enabled. - &Pat::Lit(expr) | &Pat::ConstBlock(expr) => { + &Pat::Lit(expr) => { let lit_ty = self.infer_expr_pat_unadjusted(expr); - // Call `resolve_vars_if_possible` here for inline const blocks. let lit_ty = self.infcx().resolve_vars_if_possible(lit_ty); // If `deref_patterns` is enabled, allow `if let "foo" = &&"foo" {}`. if self.features.deref_patterns { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs index 5098b38c4380c..2a6e8a396279b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs @@ -211,9 +211,7 @@ macro_rules! size_and_align { macro_rules! size_and_align_expr { (minicore: $($x:tt),*; stmts: [$($s:tt)*] $($t:tt)*) => { { - #[allow(dead_code)] - #[allow(unused_must_use)] - #[allow(path_statements)] + #[allow(dead_code, unused_must_use, path_statements)] { $($s)* let val = { $($t)* }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index b86585231cca1..04e453fde3b93 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -252,7 +252,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { db, // Can provide no block since we don't use it for trait solving. interner, - types: crate::next_solver::default_types(db), + types: crate::next_solver::default_types(), lang_items: interner.lang_items(), resolver, def, @@ -635,7 +635,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { // place even if we encounter more opaque types while // lowering the bounds let idx = self.impl_trait_mode.opaque_type_data.alloc(ImplTrait { - predicates: StoredEarlyBinder::bind(Clauses::empty(interner).store()), + predicates: StoredEarlyBinder::bind(Clauses::empty().store()), assoc_ty_bounds_start: 0, }); @@ -2372,12 +2372,12 @@ impl<'db> GenericPredicates { /// A cycle can occur from malformed code. fn generic_predicates_cycle_result<'db>( - db: &'db dyn HirDatabase, + _db: &'db dyn HirDatabase, _: salsa::Id, _def: GenericDefId, ) -> TyLoweringResult<'db, GenericPredicates> { TyLoweringResult::empty(GenericPredicates::from_explicit_own_predicates( - StoredEarlyBinder::bind(Clauses::empty(DbInterner::new_no_crate(db)).store()), + StoredEarlyBinder::bind(Clauses::empty().store()), )) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs index c67c69520db10..7e55ef2963169 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs @@ -576,7 +576,6 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { lowering_assoc_type_generics: bool, span: Span, ) -> GenericArgs<'db> { - let interner = self.ctx.interner; let prev_current_segment_idx = self.current_segment_idx; let prev_current_segment = self.current_or_prev_segment; @@ -586,7 +585,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { ValueTyDefId::UnionId(it) => it.into(), ValueTyDefId::ConstId(it) => it.into(), ValueTyDefId::StaticId(_) => { - return GenericArgs::empty(interner); + return GenericArgs::empty(); } ValueTyDefId::EnumVariantId(var) => { // the generic args for an enum variant may be either specified diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs index d6db51dec52b9..37f3e27631810 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs @@ -309,7 +309,6 @@ const STACK_OFFSET: usize = 1 << 30; const HEAP_OFFSET: usize = 1 << 29; impl Address { - #[allow(clippy::double_parens)] fn from_bytes<'db>(it: &[u8]) -> Result<'db, Self> { Ok(Address::from_usize(from_bytes!(usize, it))) } @@ -1504,8 +1503,7 @@ impl<'a, 'db> Evaluator<'a, 'db> { )?) } AggregateKind::Union(it, f) => { - let layout = - self.layout_adt((*it).into(), GenericArgs::empty(self.interner()))?; + let layout = self.layout_adt((*it).into(), GenericArgs::empty())?; let offset = layout .fields .offset(u32::from(f.local_id.into_raw()) as usize) @@ -2093,7 +2091,6 @@ impl<'a, 'db> Evaluator<'a, 'db> { } } - #[allow(clippy::double_parens)] fn allocate_const_in_heap( &mut self, locals: &Locals<'a, 'db>, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs index 5a43696233079..ca7c5c7366803 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs @@ -1246,7 +1246,7 @@ impl<'a, 'db> Evaluator<'a, 'db> { def, &args, // FIXME: wrong for manual impls of `FnOnce` - GenericArgs::empty(self.interner()), + GenericArgs::empty(), locals, destination, None, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs index f09ac6f20d271..2ac3811f1769a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs @@ -5,19 +5,14 @@ use syntax::{TextRange, TextSize}; use test_fixture::WithFixture; use crate::{ - db::HirDatabase, - display::DisplayTarget, - mir::MirLowerError, - next_solver::{DbInterner, GenericArgs}, - setup_tracing, - test_db::TestDB, + db::HirDatabase, display::DisplayTarget, mir::MirLowerError, next_solver::GenericArgs, + setup_tracing, test_db::TestDB, }; use super::{MirEvalError, interpret_mir}; fn eval_main(db: &TestDB, file_id: EditionedFileId) -> Result<(String, String), MirEvalError<'_>> { crate::attach_db(db, || { - let interner = DbInterner::new_no_crate(db); let module_id = db.module_for_file(file_id.file_id(db)); let def_map = module_id.def_map(db); let scope = &def_map[module_id].scope; @@ -39,7 +34,7 @@ fn eval_main(db: &TestDB, file_id: EditionedFileId) -> Result<(String, String), let body = db .monomorphized_mir_body( func_id.into(), - GenericArgs::empty(interner).store(), + GenericArgs::empty().store(), crate::ParamEnvAndCrate { param_env: db.trait_environment(func_id.into()), krate: func_id.krate(db), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs index da631c0d595ea..3b82ed6f798e4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs @@ -324,7 +324,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { db, infer, store, - types: crate::next_solver::default_types(db), + types: crate::next_solver::default_types(), owner, store_owner, resolver, @@ -547,7 +547,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { const_id.into(), current, place, - GenericArgs::empty(self.interner()), + GenericArgs::empty(), expr_id.into(), )?; Ok(Some(current)) @@ -1377,10 +1377,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { match pr { ResolveValueResult::ValueNs(v) => { if let ValueNs::ConstId(c) = v { - self.lower_const_to_operand( - GenericArgs::empty(self.interner()), - c.into(), - ) + self.lower_const_to_operand(GenericArgs::empty(), c.into()) } else { not_supported!("bad path in range pattern"); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs index 682ae827db67d..ecc013506689d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs @@ -413,7 +413,7 @@ impl<'db> MirLowerCtx<'_, 'db> { break 'b (c, x.1); } if let ResolveValueResult::ValueNs(ValueNs::ConstId(c)) = pr { - break 'b (c, GenericArgs::empty(self.interner())); + break 'b (c, GenericArgs::empty()); } not_supported!("path in pattern position that is not const or variant") }; @@ -519,7 +519,6 @@ impl<'db> MirLowerCtx<'_, 'db> { } Pat::Box { .. } => not_supported!("box pattern"), Pat::Deref { .. } => not_supported!("deref pattern"), - Pat::ConstBlock(_) => not_supported!("const block pattern"), }) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs index 42fd31f2594da..6263571286721 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs @@ -43,7 +43,6 @@ use rustc_type_ir::MayBeErased; pub use solver::*; pub use ty::*; -use crate::db::HirDatabase; pub use crate::lower::ImplTraitIdx; pub use rustc_ast_ir::Mutability; @@ -143,25 +142,24 @@ impl std::fmt::Debug for DefaultAny<'_> { } #[inline] -pub fn default_types<'db>(db: &'db dyn HirDatabase) -> &'db DefaultAny<'db> { +pub fn default_types<'db>() -> &'db DefaultAny<'db> { static TYPES: OnceLock> = OnceLock::new(); - let interner = DbInterner::new_no_crate(db); TYPES.get_or_init(|| { let create_ty = |kind| { - let ty = Ty::new(interner, kind); + let ty = Ty::new_without_interner(kind); // We need to increase the refcount (forever), so that the types won't be freed. let ty = ManuallyDrop::new(ty.store()); ty.as_ref() }; let create_const = |kind| { - let ty = Const::new(interner, kind); + let ty = Const::new_without_interner(kind); // We need to increase the refcount (forever), so that the types won't be freed. let ty = ManuallyDrop::new(ty.store()); ty.as_ref() }; let create_region = |kind| { - let ty = Region::new(interner, kind); + let ty = Region::new_without_interner(kind); // We need to increase the refcount (forever), so that the types won't be freed. let ty = ManuallyDrop::new(ty.store()); ty.as_ref() diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs index 1cabafa89bc4e..a9cfafb2e4890 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs @@ -48,7 +48,10 @@ const _: () = { }; impl<'db> Const<'db> { - pub fn new(_interner: DbInterner<'db>, kind: ConstKind<'db>) -> Self { + /// You should avoid using this if you can, since we want `Ty` to be defined in `rustc_type_ir` and then this method + /// will become more difficult to use. + #[inline] + pub fn new_without_interner(kind: ConstKind<'db>) -> Self { let kind = unsafe { std::mem::transmute::, ConstKind<'static>>(kind) }; let flags = FlagComputation::for_const_kind(&kind); let cached = WithCachedTypeInfo { @@ -59,6 +62,10 @@ impl<'db> Const<'db> { Self { interned: Interned::new_gc(ConstInterned(cached)) } } + pub fn new(_interner: DbInterner<'db>, kind: ConstKind<'db>) -> Self { + Self::new_without_interner(kind) + } + pub fn inner(&self) -> &WithCachedTypeInfo> { let inner = &self.interned.0; unsafe { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs index 33e4c175d0635..e6416eadc05ec 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs @@ -498,7 +498,7 @@ impl<'cx, 'db> Canonicalizer<'cx, 'db> { { let base = Canonical { max_universe: UniverseIndex::ROOT, - var_kinds: CanonicalVarKinds::empty(tcx), + var_kinds: CanonicalVarKinds::empty(), value: (), }; Canonicalizer::canonicalize_with_base( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs index 7b2a811a01afe..df7c9bfe1ec44 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs @@ -90,8 +90,8 @@ macro_rules! interned_slice { impl<'db> $name<'db> { #[inline] - pub fn empty(interner: DbInterner<'db>) -> Self { - interner.default_types().empty.$default_types_field + pub fn empty() -> Self { + $crate::next_solver::default_types().empty.$default_types_field } #[inline] @@ -168,7 +168,7 @@ macro_rules! interned_slice { impl<'db> Default for $name<'db> { #[inline] fn default() -> Self { - $name::empty(DbInterner::conjure()) + $name::empty() } } @@ -399,7 +399,7 @@ impl<'db> DbInterner<'db> { #[inline] pub fn default_types(&self) -> &'db crate::next_solver::DefaultAny<'db> { - crate::next_solver::default_types(self.db) + crate::next_solver::default_types() } #[inline] @@ -1092,7 +1092,7 @@ impl<'db> Interner for DbInterner<'db> { | SolverDefId::InternedCoroutineId(_) | SolverDefId::InternedCoroutineClosureId(_) | SolverDefId::AnonConstId(_) => { - return VariancesOf::empty(self); + return VariancesOf::empty(); } }; self.db.variances_of(generic_def) @@ -1345,7 +1345,7 @@ impl<'db> Interner for DbInterner<'db> { let own_bounds: FxHashSet<_> = self.item_self_bounds(def_id).skip_binder().into_iter().collect(); if all_bounds.len() == own_bounds.len() { - EarlyBinder::bind(Clauses::empty(self)) + EarlyBinder::bind(Clauses::empty()) } else { EarlyBinder::bind(Clauses::new_from_iter( self, @@ -2172,7 +2172,7 @@ impl<'db> Interner for DbInterner<'db> { }; EarlyBinder::bind(Const::new_unevaluated( self, - UnevaluatedConst { def: GeneralConstIdWrapper(id), args: GenericArgs::empty(self) }, + UnevaluatedConst { def: GeneralConstIdWrapper(id), args: GenericArgs::empty() }, )) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs index cf492e65c3ff3..a1e249eaf9517 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs @@ -16,8 +16,8 @@ use rustc_type_ir::{ }; use crate::next_solver::{ - GenericArg, TraitIdWrapper, impl_foldable_for_interned_slice, impl_stored_interned_slice, - interned_slice, + GenericArg, TraitIdWrapper, default_types, impl_foldable_for_interned_slice, + impl_stored_interned_slice, interned_slice, }; use super::{Binder, BoundVarKinds, DbInterner, Region, Ty}; @@ -274,8 +274,8 @@ impl<'db> std::fmt::Debug for Clauses<'db> { impl<'db> Clauses<'db> { #[inline] - pub fn empty(interner: DbInterner<'db>) -> Self { - interner.default_types().empty.clauses + pub fn empty() -> Self { + default_types().empty.clauses } #[inline] @@ -321,6 +321,13 @@ impl<'db> Clauses<'db> { } } +impl Default for Clauses<'_> { + #[inline] + fn default() -> Self { + Self::empty() + } +} + impl<'db> IntoIterator for Clauses<'db> { type IntoIter = ::std::iter::Copied<::std::slice::Iter<'db, Clause<'db>>>; type Item = Clause<'db>; @@ -437,8 +444,9 @@ pub struct ParamEnv<'db> { } impl<'db> ParamEnv<'db> { - pub fn empty(interner: DbInterner<'db>) -> Self { - ParamEnv { clauses: Clauses::empty(interner) } + #[inline] + pub fn empty() -> Self { + ParamEnv { clauses: Clauses::empty() } } pub fn clauses(self) -> Clauses<'db> { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/region.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/region.rs index a6facff7623d8..53099f67fcd5a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/region.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/region.rs @@ -38,11 +38,17 @@ const _: () = { }; impl<'db> Region<'db> { - pub fn new(_interner: DbInterner<'db>, kind: RegionKind<'db>) -> Self { + /// You should avoid using this if you can, since we want `Region` to be defined in `rustc_type_ir` and then this method + /// will become more difficult to use. + pub fn new_without_interner(kind: RegionKind<'db>) -> Self { let kind = unsafe { std::mem::transmute::, RegionKind<'static>>(kind) }; Self { interned: Interned::new_gc(RegionInterned(kind)) } } + pub fn new(_interner: DbInterner<'db>, kind: RegionKind<'db>) -> Self { + Self::new_without_interner(kind) + } + pub fn inner(&self) -> &RegionKind<'db> { let inner = &self.interned.0; unsafe { std::mem::transmute::<&RegionKind<'static>, &RegionKind<'db>>(inner) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs index 6faf0357e3583..c1810bc659c01 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs @@ -70,8 +70,10 @@ const _: () = { }; impl<'db> Ty<'db> { + /// You should avoid using this if you can, since we want `Const` to be defined in `rustc_type_ir` and then this method + /// will become more difficult to use. #[inline] - pub fn new(_interner: DbInterner<'db>, kind: TyKind<'db>) -> Self { + pub fn new_without_interner(kind: TyKind<'db>) -> Self { let kind = unsafe { std::mem::transmute::, TyKind<'static>>(kind) }; let flags = FlagComputation::for_kind(&kind); let cached = WithCachedTypeInfo { @@ -82,6 +84,11 @@ impl<'db> Ty<'db> { Self { interned: Interned::new_gc(TyInterned(cached)) } } + #[inline] + pub fn new(_interner: DbInterner<'db>, kind: TyKind<'db>) -> Self { + Self::new_without_interner(kind) + } + #[inline] pub fn inner(&self) -> &WithCachedTypeInfo> { let inner = &self.interned.0; @@ -784,7 +791,7 @@ impl<'db> Ty<'db> { let impl_bound = TraitRef::new_from_args( interner, future_trait.into(), - GenericArgs::empty(interner), + GenericArgs::empty(), ) .upcast(interner); Some(vec![impl_bound]) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs index a6e864916f40f..b10f2df273b44 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs @@ -938,36 +938,6 @@ fn foo(tuple: Tuple) { ); } -#[test] -fn const_block_pattern() { - check_infer( - r#" -struct Foo(usize); -fn foo(foo: Foo) { - match foo { - const { Foo(15 + 32) } => {}, - _ => {} - } -}"#, - expect![[r#" - 26..29 'foo': Foo - 36..115 '{ ... } }': () - 42..113 'match ... }': () - 48..51 'foo': Foo - 62..84 'const ... 32) }': Foo - 68..84 '{ Foo(... 32) }': Foo - 70..73 'Foo': fn Foo(usize) -> Foo - 70..82 'Foo(15 + 32)': Foo - 74..76 '15': usize - 74..81 '15 + 32': usize - 79..81 '32': usize - 88..90 '{}': () - 100..101 '_': Foo - 105..107 '{}': () - "#]], - ); -} - #[test] fn macro_pat() { check_types( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs index 7934ffec28745..a6c8b4ac6a271 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs @@ -3135,22 +3135,6 @@ fn f() -> impl Sized { ); } -#[test] -fn regression_22836() { - check( - r#" -fn main() { - match () { - const { - async | v | () - // ^^^^^^^^^^^^^^ expected (), got impl AsyncFn({unknown}) - } - } -} - "#, - ); -} - #[test] fn regression_22986() { check_no_mismatches( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs index f3aa024399e06..61f0e17cc9984 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs @@ -391,6 +391,6 @@ pub fn check_orphan_rules<'db>(db: &'db dyn HirDatabase, impl_: ImplId) -> bool } _ => false, }); - #[allow(clippy::let_and_return)] + #[allow(clippy::let_and_return, reason = "the name clarifies the meaning of the boolean")] is_not_orphan } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs index 2690297283988..cce1b4caf44a7 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs @@ -46,7 +46,7 @@ fn variances_of_query(db: &dyn HirDatabase, def: GenericDefId) -> StoredVariance GenericDefId::AdtId(adt) => { if let AdtId::StructId(id) = adt { let flags = &StructSignature::of(db, id).flags; - let types = || crate::next_solver::default_types(db); + let types = || crate::next_solver::default_types(); if flags.contains(StructFlags::IS_UNSAFE_CELL) { return types().one_invariant.store(); } else if flags.intersects( @@ -56,13 +56,13 @@ fn variances_of_query(db: &dyn HirDatabase, def: GenericDefId) -> StoredVariance } } } - _ => return VariancesOf::empty(DbInterner::new_no_crate(db)).store(), + _ => return VariancesOf::empty().store(), } let generics = generics(db, def); let count = generics.len(true); if count == 0 { - return VariancesOf::empty(DbInterner::new_no_crate(db)).store(); + return VariancesOf::empty().store(); } let variances = Context { generics, variances: vec![Variance::Bivariant; count].into_boxed_slice(), db } diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs index 5c3b628f386d5..a1ff564edcf56 100644 --- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs @@ -1175,7 +1175,11 @@ impl<'a, 'db> DiagnosticsCollector<'a, 'db> { } fn collect_anon_const(&mut self, source_map: &ExpressionStoreSourceMap, def: AnonConstId<'db>) { - self.emit_inference_errors(def.into(), source_map, def.into()); + self.emit_inference_errors( + def.into(), + source_map, + TypeOwnerId::from_anon_const(def, self.db), + ); } fn collect_enum(&mut self, def: EnumId) { @@ -1232,7 +1236,7 @@ impl<'a, 'db> DiagnosticsCollector<'a, 'db> { } } - fn collect_def_with_body(&mut self, def: DefWithBodyId, type_owner: TypeOwnerId<'db>) { + fn collect_def_with_body(&mut self, def: DefWithBodyId, type_owner: TypeOwnerId) { let (body, source_map) = Body::with_source_map(self.db, def); self.collect_expr_store(body, source_map); @@ -1284,7 +1288,7 @@ impl<'a, 'db> DiagnosticsCollector<'a, 'db> { &mut self, def: InferBodyId<'db>, source_map: &ExpressionStoreSourceMap, - type_owner: TypeOwnerId<'db>, + type_owner: TypeOwnerId, ) { let infer = InferenceResult::of(self.db, def); @@ -1548,7 +1552,7 @@ impl<'db> AnyDiagnostic<'db> { edition: Edition, d: &'db InferenceDiagnostic, source_map: &ExpressionStoreSourceMap, - type_owner: TypeOwnerId<'db>, + type_owner: TypeOwnerId, ) -> Option> { let expr_syntax = |expr| Self::expr_syntax(expr, source_map); let pat_syntax = |pat| Self::pat_syntax(pat, source_map); @@ -1918,7 +1922,7 @@ impl<'db> AnyDiagnostic<'db> { db: &'db dyn HirDatabase, d: &'db SolverDiagnosticKind, span: SpanSyntax, - type_owner: TypeOwnerId<'db>, + type_owner: TypeOwnerId, ) -> Option> { let interner = DbInterner::new_no_crate(db); Some(match d { diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 34b9ede4985a6..f9073138e32dd 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -1299,16 +1299,15 @@ impl<'db> AnonConst<'db> { pub fn ty(self, db: &'db dyn HirDatabase) -> Type<'db> { let loc = self.id.loc(db); - Type { owner: self.id.into(), ty: loc.ty.get() } + Type { owner: TypeOwnerId::from_anon_const(self.id, db), ty: loc.ty.get() } } pub fn eval( self, db: &'db dyn HirDatabase, ) -> Result, ConstEvalError<'db>> { - let interner = DbInterner::new_no_crate(db); let ty = self.id.loc(db).ty.get().instantiate_identity().skip_norm_wip(); - db.anon_const_eval(self.id, GenericArgs::empty(interner), None).map(|it| EvaluatedConst { + db.anon_const_eval(self.id, GenericArgs::empty(), None).map(|it| EvaluatedConst { allocation: it, def: self.id.into(), ty, @@ -1550,7 +1549,7 @@ impl Function { } } - fn fn_sig<'db>(self, db: &'db dyn HirDatabase) -> (TypeOwnerId<'db>, PolyFnSig<'db>) { + fn fn_sig<'db>(self, db: &'db dyn HirDatabase) -> (TypeOwnerId, PolyFnSig<'db>) { let fn_ptr = self.fn_ptr_type(db); let TyKind::FnPtr(sig_tys, hdr) = fn_ptr.ty.skip_binder().kind() else { unreachable!(); @@ -1558,7 +1557,7 @@ impl Function { (fn_ptr.owner, sig_tys.with(hdr)) } - fn erased_fn_sig<'db>(self, db: &'db dyn HirDatabase) -> (TypeOwnerId<'db>, FnSig<'db>) { + fn erased_fn_sig<'db>(self, db: &'db dyn HirDatabase) -> (TypeOwnerId, FnSig<'db>) { let (owner, sig) = self.fn_sig(db); let sig = DbInterner::new_no_crate(db).instantiate_bound_regions_with_erased(sig); (owner, sig) @@ -1827,10 +1826,9 @@ impl Function { "evaluation of builtin derive impl methods is not supported".to_owned(), ))); }; - let interner = DbInterner::new_no_crate(db); let body = db.monomorphized_mir_body( id.into(), - GenericArgs::empty(interner).store(), + GenericArgs::empty().store(), ParamEnvAndCrate { param_env: db.trait_environment(id.into()), krate: id.module(db).krate(db), @@ -2109,9 +2107,8 @@ impl Const { /// Evaluate the constant. pub fn eval(self, db: &dyn HirDatabase) -> Result, ConstEvalError<'_>> { - let interner = DbInterner::new_no_crate(db); let ty = db.value_ty(self.id.into()).unwrap().instantiate_identity().skip_norm_wip(); - db.const_eval(self.id, GenericArgs::empty(interner), None).map(|it| EvaluatedConst { + db.const_eval(self.id, GenericArgs::empty(), None).map(|it| EvaluatedConst { allocation: it, def: self.id.into(), ty, @@ -3124,21 +3121,17 @@ impl GenericDef { // We cannot call this `Substitution` unfortunately... #[derive(Debug)] pub struct GenericSubstitution<'db> { - owner: TypeOwnerId<'db>, + owner: TypeOwnerId, def: GenericDefId, subst: GenericArgs<'db>, } impl<'db> GenericSubstitution<'db> { - fn new(def: GenericDefId, subst: GenericArgs<'db>, owner: TypeOwnerId<'db>) -> Self { + fn new(def: GenericDefId, subst: GenericArgs<'db>, owner: TypeOwnerId) -> Self { Self { owner, def, subst } } - fn new_from_fn( - def: Function, - subst: GenericArgs<'db>, - owner: TypeOwnerId<'db>, - ) -> Option { + fn new_from_fn(def: Function, subst: GenericArgs<'db>, owner: TypeOwnerId) -> Option { match def.id { AnyFunctionId::FunctionId(def) => Some(Self::new(def.into(), subst, owner)), AnyFunctionId::BuiltinDeriveImplMethod { .. } => None, @@ -3965,7 +3958,7 @@ impl Impl { #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct TraitRef<'db> { - owner: TypeOwnerId<'db>, + owner: TypeOwnerId, trait_ref: hir_ty::next_solver::TraitRef<'db>, } @@ -4003,7 +3996,7 @@ enum AnyClosureId<'db> { #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Closure<'db> { - owner: TypeOwnerId<'db>, + owner: TypeOwnerId, id: AnyClosureId<'db>, subst: GenericArgs<'db>, } @@ -4347,23 +4340,26 @@ impl CaptureUsageSource { } #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] -enum TypeOwnerId<'db> { +enum TypeOwnerId { GenericDefId(GenericDefId), BuiltinDeriveImplId(BuiltinDeriveImplId), - AnonConstId(AnonConstId<'db>), // FIXME: What do when we unify two different crates? Currently we just randomly keep one. NoParams(base_db::Crate), } impl_from!( - impl<'db> GenericDefId, - BuiltinDeriveImplId, - AnonConstId<'db> - for TypeOwnerId<'db> + BuiltinDeriveImplId + for TypeOwnerId ); -impl TypeOwnerId<'_> { +impl TypeOwnerId { + /// We associated anon consts with their parent, because they can never have generics of their own. + /// It can have *less* than the parent, but providing more generic args is not a problem. + fn from_anon_const<'db>(id: AnonConstId<'db>, db: &'db dyn HirDatabase) -> TypeOwnerId { + TypeOwnerId::GenericDefId(id.loc(db).owner.generic_def(db)) + } + fn unify(self, other: Self) -> Option { match (self, other) { (TypeOwnerId::NoParams(_), owner) => Some(owner), @@ -4394,7 +4390,7 @@ impl TypeOwnerId<'_> { } let self_def = match self { TypeOwnerId::GenericDefId(def) => def, - TypeOwnerId::BuiltinDeriveImplId(_) | TypeOwnerId::AnonConstId(_) => return false, + TypeOwnerId::BuiltinDeriveImplId(_) => return false, TypeOwnerId::NoParams(_) => return true, }; let self_def = match self_def { @@ -4408,9 +4404,7 @@ impl TypeOwnerId<'_> { }; let rebase_into_def = match rebase_into { TypeOwnerId::GenericDefId(def) => def, - TypeOwnerId::BuiltinDeriveImplId(_) - | TypeOwnerId::AnonConstId(_) - | TypeOwnerId::NoParams(_) => return false, + TypeOwnerId::BuiltinDeriveImplId(_) | TypeOwnerId::NoParams(_) => return false, }; let rebase_into_parent = match rebase_into_def { GenericDefId::ConstId(def) => def.loc(db).container, @@ -4429,7 +4423,7 @@ impl TypeOwnerId<'_> { /// with types of different origins will cause errors or panics. Instead, use the `instantiate` methods. #[derive(Clone, Debug)] pub struct Type<'db> { - owner: TypeOwnerId<'db>, + owner: TypeOwnerId, ty: EarlyBinder<'db, Ty<'db>>, } @@ -4513,8 +4507,7 @@ impl<'db> Type<'db> { TypeOwnerId::BuiltinDeriveImplId(def) => { GenericArgs::error_for_item(interner, def.into()) } - TypeOwnerId::AnonConstId(def) => GenericArgs::error_for_item(interner, def.into()), - TypeOwnerId::NoParams(_) => GenericArgs::empty(interner), + TypeOwnerId::NoParams(_) => GenericArgs::empty(), }; Type::no_params(krate, self.ty.instantiate(interner, args).skip_norm_wip()) } @@ -4527,10 +4520,7 @@ impl<'db> Type<'db> { TypeOwnerId::BuiltinDeriveImplId(def) => { generic_args_from_tys(interner, def.into(), args) } - TypeOwnerId::AnonConstId(def) => generic_args_from_tys(interner, def.into(), args), - TypeOwnerId::NoParams(krate) => { - (GenericArgs::empty(interner), TypeOwnerId::NoParams(krate)) - } + TypeOwnerId::NoParams(krate) => (GenericArgs::empty(), TypeOwnerId::NoParams(krate)), }; Type { owner, ty: EarlyBinder::bind(self.ty.instantiate(interner, args).skip_norm_wip()) } } @@ -4546,7 +4536,6 @@ impl<'db> Type<'db> { let owner = match ty.owner { TypeOwnerId::GenericDefId(def) => def.into(), TypeOwnerId::BuiltinDeriveImplId(def) => def.into(), - TypeOwnerId::AnonConstId(def) => def.into(), TypeOwnerId::NoParams(_) => return ty.ty.skip_binder(), }; let args = GenericArgs::for_item(infcx.interner, owner, |_, param, _, _| { @@ -4624,7 +4613,7 @@ impl<'db> Type<'db> { tys: impl IntoIterator>>, ) -> Self { let interner = DbInterner::new_no_crate(db); - let mut owner = None::>; + let mut owner = None::; let ty = EarlyBinder::bind(Ty::new_tup_from_iter( interner, tys.into_iter().map(|ty| { @@ -4840,29 +4829,21 @@ impl<'db> Type<'db> { TypeOwnerId::BuiltinDeriveImplId(def) => { hir_def::HasModule::krate(&def.loc(db).adt, db) } - TypeOwnerId::AnonConstId(def) => hir_def::HasModule::krate(&def, db), TypeOwnerId::NoParams(krate) => krate, } } fn param_env(&self, db: &'db dyn HirDatabase) -> ParamEnvAndCrate<'db> { - let interner = DbInterner::new_no_crate(db); let krate = self.krate(db); match self.owner { TypeOwnerId::GenericDefId(def) => { ParamEnvAndCrate { param_env: db.trait_environment(def), krate } } TypeOwnerId::BuiltinDeriveImplId(def) => ParamEnvAndCrate { - param_env: hir_ty::builtin_derive::param_env(interner, def), - krate, - }, - TypeOwnerId::AnonConstId(def) => ParamEnvAndCrate { - param_env: db.trait_environment(def.loc(db).owner.generic_def(db)), + param_env: hir_ty::builtin_derive::param_env(DbInterner::new_with(db, krate), def), krate, }, - TypeOwnerId::NoParams(_) => { - ParamEnvAndCrate { param_env: ParamEnv::empty(interner), krate } - } + TypeOwnerId::NoParams(_) => ParamEnvAndCrate { param_env: ParamEnv::empty(), krate }, } } @@ -4986,8 +4967,7 @@ impl<'db> Type<'db> { trait_: Trait, args: &[Type<'db>], ) -> bool { - let interner = DbInterner::new_no_crate(db); - let env = ParamEnvAndCrate { param_env: ParamEnv::empty(interner), krate: self.krate(db) }; + let env = ParamEnvAndCrate { param_env: ParamEnv::empty(), krate: self.krate(db) }; traits::implements_trait_unique_with_infcx(db, env, trait_.id, &mut |infcx| { let mut args = Self::instantiate_many_with_infer(iter::once(self).chain(args), infcx); GenericArgs::for_item(infcx.interner, trait_.id.into(), |_, param, _, _| { @@ -5681,7 +5661,7 @@ impl<'db> Type<'db> { pub fn walk(&self, db: &'db dyn HirDatabase, callback: impl FnMut(Type<'db>)) { struct Visitor<'db, F> { db: &'db dyn HirDatabase, - owner: TypeOwnerId<'db>, + owner: TypeOwnerId, callback: F, visited: FxHashSet>, } @@ -6144,7 +6124,7 @@ pub enum PredicatePolarity { #[derive(Debug, Clone, PartialEq, Eq)] pub struct TraitPredicate<'db> { inner: hir_ty::next_solver::TraitPredicate<'db>, - owner: TypeOwnerId<'db>, + owner: TypeOwnerId, } impl<'db> TraitPredicate<'db> { @@ -6549,8 +6529,8 @@ fn generic_args_from_tys<'db>( interner: DbInterner<'db>, def_id: SolverDefId<'db>, args: impl IntoIterator>>, -) -> (GenericArgs<'db>, TypeOwnerId<'db>) { - let mut owner = None::>; +) -> (GenericArgs<'db>, TypeOwnerId) { + let mut owner = None::; let mut args = args.into_iter(); let args = GenericArgs::for_item(interner, def_id, |_, id, _, _| { if matches!(id, GenericParamId::TypeParamId(_)) diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index 907193fe1d7ff..368e5e3c147fd 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -78,7 +78,7 @@ pub(crate) struct SourceAnalyzer<'db> { pub(crate) file_id: HirFileId, pub(crate) resolver: Resolver<'db>, pub(crate) body_or_sig: Option>, - pub(crate) type_owner: TypeOwnerId<'db>, + pub(crate) type_owner: TypeOwnerId, pub(crate) infer_body: Option>, } @@ -350,21 +350,18 @@ impl<'db> SourceAnalyzer<'db> { } fn trait_environment(&self, db: &'db dyn HirDatabase) -> ParamEnvAndCrate<'db> { - self.param_and(self.body_or_sig.as_ref().map_or_else( - || ParamEnv::empty(DbInterner::new_no_crate(db)), - |body_or_sig| { - let def = match *body_or_sig { - BodyOrSig::Body { def, .. } => def.generic_def(db), - BodyOrSig::VariantFields { def, .. } => match def { - VariantId::EnumVariantId(def) => def.loc(db).parent.into(), - VariantId::StructId(def) => def.into(), - VariantId::UnionId(def) => def.into(), - }, - BodyOrSig::Sig { def, .. } => def, - }; - db.trait_environment(def) - }, - )) + self.param_and(self.body_or_sig.as_ref().map_or_else(ParamEnv::empty, |body_or_sig| { + let def = match *body_or_sig { + BodyOrSig::Body { def, .. } => def.generic_def(db), + BodyOrSig::VariantFields { def, .. } => match def { + VariantId::EnumVariantId(def) => def.loc(db).parent.into(), + VariantId::StructId(def) => def.into(), + VariantId::UnionId(def) => def.into(), + }, + BodyOrSig::Sig { def, .. } => def, + }; + db.trait_environment(def) + })) } pub(crate) fn evaluate_where_clause( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs index 9f9bb1d131548..67fa68df1e9df 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs @@ -140,6 +140,7 @@ fn add_missing_impl_members_inner( let missing_items = filter_assoc_items( &ctx.sema, + trait_, &ide_db::traits::get_missing_assoc_items(&ctx.sema, &impl_def), mode, ign_item, @@ -161,6 +162,7 @@ fn add_missing_impl_members_inner( trait_, &impl_def, &target_scope, + mode, ); let Some((first_new_item, other_items)) = new_item.split_first() else { @@ -2747,7 +2749,9 @@ pub trait Read { } impl Read for () { - $0fn read_buf() {} + fn read_buf() { + ${0:todo!()} + } } "#, ); @@ -2887,7 +2891,9 @@ pub trait Read { } impl Read for () { - $0fn read() {} + fn read() { + ${0:todo!()} + } } "#, ); @@ -2918,7 +2924,198 @@ pub trait Read { } impl Read for () { - $0fn read_buf() {} + fn read_buf() { + ${0:todo!()} + } +} + "#, + ); + } + + #[test] + fn required_method_with_body() { + check_assist( + add_missing_impl_members, + r#" +//- minicore: drop, pin +struct Foo; + +impl Drop for Foo { + $0 +} + "#, + r#" +struct Foo; + +impl Drop for Foo { + fn drop(&mut self) { + ${0:todo!()} + } +} + "#, + ); + + check_assist( + add_missing_impl_members, + r#" +#[rustc_must_implement_one_of(read_buf, read)] +pub trait Read { + fn read() { + Self::read_buf() + } + fn read_buf() { + Self::read(); + } +} + +impl Read for () { + $0 +} + "#, + r#" +#[rustc_must_implement_one_of(read_buf, read)] +pub trait Read { + fn read() { + Self::read_buf() + } + fn read_buf() { + Self::read(); + } +} + +impl Read for () { + fn read_buf() { + ${0:todo!()} + } +} + "#, + ); + check_assist( + add_missing_default_members, + r#" +#[rustc_must_implement_one_of(read_buf, read)] +pub trait Read { + fn read() { + Self::read_buf() + } + fn read_buf() { + Self::read(); + } +} + +impl Read for () { + $0 +} + "#, + r#" +#[rustc_must_implement_one_of(read_buf, read)] +pub trait Read { + fn read() { + Self::read_buf() + } + fn read_buf() { + Self::read(); + } +} + +impl Read for () { + $0fn read() { + Self::read_buf() + } +} + "#, + ); + } + + #[test] + fn unstable_item() { + check_assist( + add_missing_impl_members, + r#" +trait Foo { + #[unstable(feature = "foobar")] + fn foobar(); +} + +impl Foo for () { + $0 +} + "#, + r#" +trait Foo { + #[unstable(feature = "foobar")] + fn foobar(); +} + +impl Foo for () { + fn foobar() { + ${0:todo!()} + } +} + "#, + ); + check_assist_not_applicable( + add_missing_default_members, + r#" +trait Foo { + #[unstable(feature = "foobar")] + fn foobar() {} +} + +impl Foo for () { + $0 +} + "#, + ); + check_assist( + add_missing_default_members, + r#" +#![feature(foobar)] + +trait Foo { + #[unstable(feature = "foobar")] + fn foobar() {} +} + +impl Foo for () { + $0 +} + "#, + r#" +#![feature(foobar)] + +trait Foo { + #[unstable(feature = "foobar")] + fn foobar() {} +} + +impl Foo for () { + $0fn foobar() {} +} + "#, + ); + check_assist( + add_missing_default_members, + r#" +#[unstable(feature = "foobar")] +trait Foo { + #[unstable(feature = "foobar")] + fn foobar() {} +} + +impl Foo for () { + $0 +} + "#, + r#" +#[unstable(feature = "foobar")] +trait Foo { + #[unstable(feature = "foobar")] + fn foobar() {} +} + +impl Foo for () { + $0fn foobar() {} } "#, ); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs index d88a94e2f7307..9fa9a0461eaa2 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs @@ -167,6 +167,7 @@ pub(crate) fn generate_impl_trait(acc: &mut Assists, ctx: &AssistContext<'_, '_> let holder_arg = ast::GenericArg::TypeArg(make.type_arg(make.ty_placeholder())); let missing_items = utils::filter_assoc_items( &ctx.sema, + hir_trait, &ide_db::traits::trait_items_with_required(ctx.db(), hir_trait), DefaultMethods::No, IgnoreAssocItems::DocHiddenAttrPresent, @@ -205,6 +206,7 @@ pub(crate) fn generate_impl_trait(acc: &mut Assists, ctx: &AssistContext<'_, '_> hir_trait, &impl_, &target_scope, + DefaultMethods::No, ); let assoc_item_list = make.assoc_item_list(assoc_items); make_impl_(Some(assoc_item_list)) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs index 8648a013438e7..3e98aadb695c3 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs @@ -233,6 +233,7 @@ fn impl_def_from_trait( let trait_items = filter_assoc_items( sema, + trait_, &ide_db::traits::trait_items_with_required(sema.db, trait_), DefaultMethods::No, ignore_items, @@ -252,6 +253,7 @@ fn impl_def_from_trait( trait_, &impl_def, &target_scope, + DefaultMethods::No, ); let assoc_item_list = if let Some((first, other)) = assoc_items.split_first() { let first_item = if let ast::AssocItem::Fn(func) = first diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs index e5e735faf6f93..8acb887133e0f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs @@ -4,7 +4,7 @@ use std::slice; pub(crate) use gen_trait_fn_body::gen_trait_fn_body; use hir::{ - HasAttrs as HirHasAttrs, HirDisplay, InFile, ModuleDef, PathResolution, Semantics, + HasAttrs as HirHasAttrs, HasCrate, HirDisplay, InFile, ModuleDef, PathResolution, Semantics, db::HirDatabase, }; use ide_db::{ @@ -158,11 +158,12 @@ pub enum DefaultMethods { pub fn filter_assoc_items( sema: &Semantics<'_, RootDatabase>, + trait_: hir::Trait, items: &[(hir::AssocItem, IsRequiredAssocItem)], default_methods: DefaultMethods, ignore_items: IgnoreAssocItems, ) -> Vec> { - items + let mut result = items .iter() .copied() .filter(|(assoc_item, is_required)| { @@ -179,16 +180,33 @@ pub fn filter_assoc_items( is_required.0 == (default_methods == DefaultMethods::No) }) + .map(|(item, _)| (item, item.attrs(sema.db).unstable_feature(sema.db))) // Note: This throws away items with no source. - .filter_map(|(assoc_item, _)| { + .filter_map(|(assoc_item, unstable_feature)| { let item = match assoc_item { hir::AssocItem::Function(it) => sema.source(it)?.map(ast::AssocItem::Fn), hir::AssocItem::TypeAlias(it) => sema.source(it)?.map(ast::AssocItem::TypeAlias), hir::AssocItem::Const(it) => sema.source(it)?.map(ast::AssocItem::Const), }; - Some(item) + Some((item, unstable_feature)) }) - .collect() + .collect::>(); + + // Now, we want to filter unstable assoc items whose feature is not enabled, unless: + // - it's required, or + // - the trait has the same feature, so the user probably intends to enable it. + if default_methods == DefaultMethods::Only { + let trait_unstable_feature = trait_.attrs(sema.db).unstable_feature(sema.db); + let krate = trait_.krate(sema.db); + result.retain(|(_, item_unstable_feature)| { + *item_unstable_feature == trait_unstable_feature + || item_unstable_feature + .as_ref() + .is_none_or(|feature| krate.is_unstable_feature_enabled(sema.db, feature)) + }); + } + + result.into_iter().map(|(item, _)| item).collect() } /// Given `original_items` retrieved from the trait definition (usually by @@ -204,6 +222,7 @@ pub fn add_trait_assoc_items_to_impl( trait_: hir::Trait, impl_: &ast::Impl, target_scope: &hir::SemanticsScope<'_>, + default_mode: DefaultMethods, ) -> Vec { let new_indent_level = IndentLevel::from_node(impl_.syntax()) + 1; original_items @@ -240,7 +259,10 @@ pub fn add_trait_assoc_items_to_impl( ast::AssocItem::cast(editor.finish().new_root().clone()).unwrap() }) .filter_map(|item| match item { - ast::AssocItem::Fn(fn_) if fn_.body().is_none() => { + // We can check `fn_.body().is_none()`, but this is actually not what we want to check: some functions (`Drop::drop()` + // or `#[rustc_must_implement_one_of]`) have a default body that should be ignored. So the criteria is whether + // we requested required or defaulted methods, and not whether the method actually has a body. + ast::AssocItem::Fn(fn_) if default_mode == DefaultMethods::No => { let (fn_editor, fn_) = SyntaxEditor::with_ast_node(&fn_); let fill_expr: ast::Expr = match config.expr_fill_default { ExprFillDefaultMode::Todo | ExprFillDefaultMode::Default => make.expr_todo(), diff --git a/src/tools/rust-analyzer/crates/ide-db/src/ra_fixture.rs b/src/tools/rust-analyzer/crates/ide-db/src/ra_fixture.rs index 09a270c143888..ee61cab4828c5 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/ra_fixture.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/ra_fixture.rs @@ -307,7 +307,7 @@ impl IsEmpty for SmallVec<[T; N]> { } } -#[allow(clippy::disallowed_types)] +#[expect(clippy::disallowed_types, reason = "generic allows for `FxHashMap`")] impl IsEmpty for std::collections::HashMap { fn is_empty(&self) -> bool { self.is_empty() @@ -376,7 +376,7 @@ impl UpmapFromRaFixture for SmallVec<[T; } } -#[allow(clippy::disallowed_types)] +#[expect(clippy::disallowed_types, reason = "generic allows for `FxHashMap`")] impl UpmapFromRaFixture for std::collections::HashMap { @@ -391,7 +391,7 @@ impl UpmapFromRaFixture for std::collections::HashMap { diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs index a72da8e7722a5..e13693df99560 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs @@ -247,6 +247,16 @@ struct SCREAMING_CASE {} ); } + #[test] + fn incorrect_raw_struct_name() { + check_diagnostics( + r#" +struct r#pub {} + // ^^^^^ 💡 warn: Structure `r#pub` should have UpperCamelCase name, e.g. `Pub` +"#, + ); + } + #[test] fn no_diagnostic_for_camel_cased_acronyms_in_struct_name() { check_diagnostics( @@ -340,6 +350,16 @@ enum SomeEnum { SOME_VARIANT(u8) } ); } + #[test] + fn incorrect_raw_enum_variant_name() { + check_diagnostics( + r#" +enum SomeEnum { r#pub } + // ^^^^^ 💡 warn: Variant `r#pub` should have UpperCamelCase name, e.g. `Pub` +"#, + ); + } + #[test] fn incorrect_const_name() { check_diagnostics( diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs index 24f1e3ad836a0..52532172ccda0 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs @@ -23,9 +23,21 @@ struct State { has_serialize: bool, has_deserialize: bool, names: FxHashMap, + edition: Option, } impl State { + fn make_name(&self, name: &str) -> ast::Name { + let edition = self.edition.unwrap(); + if syntax::utils::is_identifier(name, edition) + || syntax::utils::is_raw_identifier(name, edition) + { + make::name(name) + } else { + make::name("INVALID") + } + } + fn generate_new_name(&mut self, name: &str) -> ast::Name { let name = stdx::to_camel_case(name); let count = if let Some(count) = self.names.get_mut(&name) { @@ -35,7 +47,7 @@ impl State { self.names.insert(name.clone(), 1); 1 }; - make::name(&format!("{name}{count}")) + self.make_name(&format!("{name}{count}")) } fn serde_derive(&self) -> String { @@ -70,7 +82,7 @@ impl State { None, make::record_field_list(value.iter().sorted_unstable_by_key(|x| x.0).map( |(name, value)| { - make::record_field(None, make::name(name), self.type_of(name, value)) + make::record_field(None, self.make_name(name), self.type_of(name, value)) }, )) .into(), @@ -125,6 +137,7 @@ pub(crate) fn json_in_items( let serialize_resolved = scope_resolve("::serde::Serialize"); state.has_deserialize = deserialize_resolved.is_some(); state.has_serialize = serialize_resolved.is_some(); + state.edition = Some(edition); state.build_struct("Root", &it); edit.insert(range.start(), state.result); let vfs_file_id = file_id.file_id(sema.db); @@ -342,6 +355,36 @@ mod tests { ); } + #[test] + fn invalid_fields() { + check_fix( + r#" + //- /lib.rs crate:lib deps:serde + {$0 + "$": "", + "self": "", + "valided": "" + } + //- /serde.rs crate:serde + + pub trait Serialize { + fn serialize() -> u8; + } + pub trait Deserialize { + fn deserialize() -> u8; + } + "#, + r#" + use serde::Serialize; + use serde::Deserialize; + + #[derive(Serialize, Deserialize)] + struct Root1 { INVALID: String, INVALID: String, valided: String } + + "#, + ); + } + #[test] fn no_emit_outside_of_item_position() { check_no_fix( diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs index f70795ed29bde..1e92a795e47a9 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs @@ -2019,4 +2019,25 @@ fn test(_: Result) { "#, ); } + + #[test] + fn regression_23313() { + check_diagnostics( + r#" +fn hello_world() {} + +struct Wrapper ()>; + +impl ()> Wrapper<{ + Wrapper::<{hello_world}>::call(); + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: no such associated item + }> { +//^ 💡 error: expected fn(), found () + fn hello_world() { + F(); + } +} + "#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs index e2d31503f1d08..e93e74177abe8 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs @@ -464,6 +464,20 @@ fn main() { m!(generic::); } } +"#, + ); + } + + #[test] + fn term_search_lookup_const() { + check_diagnostics( + r#" +struct S { f: i32 } +const C: i32 = 0; +fn main() { + let _: S = _; + //^ 💡 error: invalid `_` expression, expected type `S` +} "#, ); } diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs index ab5a0f70f5a69..c87a10d8e85b7 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs @@ -315,7 +315,6 @@ impl<'db, 'sema> Matcher<'db, 'sema> { Ok(()) } - #[allow(clippy::only_used_in_recursion)] fn check_constraint( &self, constraint: &Constraint, diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs index c152d7e9cc964..94e7db9390bc3 100644 --- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs +++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs @@ -312,7 +312,10 @@ impl DocCommentToken { let DocCommentToken { prefix_len, doc_token } = self; // offset relative to the comments contents let original_start = doc_token.text_range().start(); - let relative_comment_offset = offset - original_start - prefix_len; + // If the cursor points inside the comment like `///` or to the first quote in `#[doc = "..."]` + // (i.e. relative_comment_offset is None) then we return w/o definition. + let relative_comment_offset = + offset.checked_sub(original_start)?.checked_sub(prefix_len)?; sema.descend_into_macros(doc_token).into_iter().find_map(|t| { let (node, descended_prefix_len, is_inner) = match_ast!{ diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs index 033de7dcc20b4..bb317525dd5d8 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs @@ -723,6 +723,13 @@ mod tests { assert!(navs.is_empty(), "didn't expect this to resolve anywhere: {navs:?}") } + #[track_caller] + fn check_no_definition(#[rust_analyzer::rust_fixture] ra_fixture: &str) { + let (analysis, position) = fixture::position(ra_fixture); + let navs = analysis.goto_definition(position, &TEST_CONFIG).unwrap(); + assert!(navs.is_none(), "didn't expect this to resolve anywhere: {navs:?}"); + } + fn check_name(expected_name: &str, #[rust_analyzer::rust_fixture] ra_fixture: &str) { let (analysis, position, _) = fixture::annotations(ra_fixture); let navs = analysis @@ -2132,6 +2139,30 @@ pub fn foo() { } ) } + #[test] + fn no_panic_on_offset_inside_doc_comment_prefix() { + // If the cursor (offset) points inside `///`/`//!`/the opening quote, i.e. before the docs' contents, + // this should not create navigation. + check_no_definition( + r#" +$0/// [`S`] +struct S; +"#, + ); + check_no_definition( + r#" +//$0! [`S`] +struct S; +"#, + ); + check_no_definition( + r#" +#[doc = $0"[`S`]"] +struct S; +"#, + ); + } + #[test] fn goto_def_for_intra_doc_link_outer_same_file() { check( diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs index 92473de4e634f..6f5878071aaa8 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs @@ -156,7 +156,6 @@ pub(crate) fn hover( Some(res) } -#[allow(clippy::field_reassign_with_default)] fn hover_offset( sema: &Semantics<'_, RootDatabase>, FilePosition { file_id, offset }: FilePosition, diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs index e516297f06196..22aac04c28e09 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs @@ -1,13 +1,11 @@ //! Bidirectional protocol messages -#![expect(clippy::disallowed_types)] - use std::{ - collections::{HashMap, HashSet}, io::{self, BufRead, Write}, ops::Range, }; use paths::Utf8PathBuf; +use rustc_hash::{FxHashMap, FxHashSet}; use serde::{Deserialize, Serialize}; use crate::{ @@ -122,7 +120,6 @@ pub struct SpanJoin { pub ctx: u32, } -#[expect(clippy::large_enum_variant)] #[derive(Debug, Serialize, Deserialize)] pub enum BidirectionalMessage { Request(Request), @@ -139,7 +136,6 @@ pub enum Request { SetConfig(ServerConfig), } -#[expect(clippy::large_enum_variant)] #[derive(Debug, Serialize, Deserialize)] pub enum Response { ListMacros(Result, String>), @@ -168,8 +164,8 @@ pub struct ExpandMacro { pub struct ExpandMacroResponse { pub tree: FlatTree, pub span_data_table: Vec, - pub tracked_env_vars: HashMap, Option>>, - pub tracked_paths: HashSet>, + pub tracked_env_vars: FxHashMap, Option>>, + pub tracked_paths: FxHashSet>, } #[derive(Debug, Serialize, Deserialize)] diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml index 05e0012586d5f..0427d0ee74a6e 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml @@ -14,6 +14,7 @@ doctest = false [dependencies] paths.workspace = true +rustc-hash.workspace = true # span = {workspace = true, default-features = false} does not work span = { path = "../span", version = "0.0.0", default-features = false} intern.workspace = true diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs index 7fc04a05155f8..e38d2ac11bce8 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs @@ -10,7 +10,7 @@ #![cfg(feature = "in-rust-tree")] #![feature(proc_macro_internals, proc_macro_diagnostic, proc_macro_span, rustc_private)] -#![expect(internal_features, clippy::disallowed_types, clippy::print_stderr)] +#![expect(internal_features)] #![allow(unused_features, unused_crate_dependencies)] #![deny(deprecated_safe, clippy::undocumented_unsafe_blocks)] #![cfg_attr(test, expect(unreachable_pub))] @@ -29,7 +29,7 @@ mod server_impl; mod token_stream; use std::{ - collections::{HashMap, HashSet, hash_map::Entry}, + collections::hash_map::Entry, env, ffi::OsString, fs, @@ -40,6 +40,7 @@ use std::{ }; use paths::{Utf8Path, Utf8PathBuf}; +use rustc_hash::{FxHashMap, FxHashSet}; use span::{FIXUP_ERASED_FILE_AST_ID_MARKER, Span}; pub use crate::server_impl::token_id::SpanId; @@ -61,7 +62,7 @@ pub enum ProcMacroKind { pub const RUSTC_VERSION_STRING: &str = env!("RUSTC_VERSION"); pub struct ProcMacroSrv<'env> { - expanders: Mutex>>, + expanders: Mutex>>, env: &'env EnvSnapshot, } @@ -226,8 +227,8 @@ impl ProcMacroSrv<'_> { #[derive(Default)] pub struct TrackedEnv { - pub env_vars: HashMap, Option>>, - pub paths: HashSet>, + pub env_vars: FxHashMap, Option>>, + pub paths: FxHashSet>, } pub trait ProcMacroSrvSpan: Copy + Send + Sync { @@ -289,7 +290,7 @@ impl PanicMessage { } pub struct EnvSnapshot { - vars: HashMap, + vars: FxHashMap, } impl Default for EnvSnapshot { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs index 6cbb0c718c3e6..8c8ad34f6c441 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -19,10 +19,7 @@ use hir_def::{ expr_store::{Body, BodySourceMap, ExpressionStore}, hir::{ExprId, PatId, generics::GenericParams}, }; -use hir_ty::{ - InferenceResult, - next_solver::{DbInterner, GenericArgs}, -}; +use hir_ty::{InferenceResult, next_solver::GenericArgs}; use ide::{ Analysis, AnalysisHost, AnnotationConfig, DiagnosticsConfig, Edition, InlayFieldsToResolve, InlayHintsConfig, LineCol, RaFixtureConfig, RootDatabase, @@ -411,7 +408,6 @@ impl flags::AnalysisStats { let mut all = 0; let mut fail = 0; for &a in adts { - let interner = DbInterner::new_no_crate(db); let generic_params = GenericParams::of(db, a.into()); if generic_params.iter_type_or_consts().next().is_some() || generic_params.iter_lt().next().is_some() @@ -422,7 +418,7 @@ impl flags::AnalysisStats { all += 1; let Err(e) = db.layout_of_adt( hir_def::AdtId::from(a), - GenericArgs::empty(interner).store(), + GenericArgs::empty().store(), hir_ty::ParamEnvAndCrate { param_env: db.trait_environment(a.into()), krate: a.krate(db).into(), diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/discover.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/discover.rs index 04d0cedb3eca2..f9491af71e7e1 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/discover.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/discover.rs @@ -68,7 +68,7 @@ impl DiscoverCommand { Ok(DiscoverHandle { handle: CommandHandle::spawn(cmd, DiscoverProjectParser, self.sender.clone(), None)?, - span: info_span!("discover_command").entered(), + _span: info_span!("discover_command").entered(), }) } } @@ -77,8 +77,8 @@ impl DiscoverCommand { #[derive(Debug)] pub(crate) struct DiscoverHandle { pub(crate) handle: CommandHandle, - #[allow(dead_code)] // not accessed, but used to log on drop. - span: EnteredSpan, + // not accessed, but used to log on drop. + _span: EnteredSpan, } /// An enum containing either progress messages, an error, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs index 85edb239e3f57..7f1f4ef137054 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs @@ -490,7 +490,7 @@ impl<'a> Substitutions<'a> { /// /// Same for {saved_file}. /// - #[allow(clippy::disallowed_types)] /* generic parameter allows for FxHashMap */ + #[expect(clippy::disallowed_types, reason = "generic parameter allows for `FxHashMap`")] fn substitute( self, template: &project_json::Runnable, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs index 8e0bb285c2318..19e067334e008 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs @@ -4,7 +4,12 @@ // might strip `false` values from the JSON payload due to their reserialization logic turning false // into null which will then cause them to be omitted in the resolve request. See https://github.com/rust-lang/rust-analyzer/issues/18767 -#![allow(clippy::disallowed_types)] +// FIXME: ideally we'd put this on `SnippetWorkspaceEdit.change_annotations`, but that doesn't work, +// most likely because the lint fires in the impls generated by the derives as well. +#![expect( + clippy::disallowed_types, + reason = "`SnippetWorkspaceEdit.change_annotations` needs to match `lsp_types::WorkspaceEdit.change_annotations` for the `From` impl" +)] use std::ops; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs index 56629f79ea216..4199cb29e66d2 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs @@ -8,7 +8,6 @@ //! specific JSON shapes here -- there's little value in such tests, as we can't //! be sure without a real client anyway. -#![allow(clippy::disallowed_types)] #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] #[cfg(feature = "in-rust-tree")] diff --git a/src/tools/rust-analyzer/crates/stdx/src/rand.rs b/src/tools/rust-analyzer/crates/stdx/src/rand.rs index e028990900af6..07dfa6ef8877c 100644 --- a/src/tools/rust-analyzer/crates/stdx/src/rand.rs +++ b/src/tools/rust-analyzer/crates/stdx/src/rand.rs @@ -14,6 +14,6 @@ pub fn shuffle(slice: &mut [T], mut rand_index: impl FnMut(usize) -> usize) { pub fn seed() -> u64 { use std::hash::{BuildHasher, Hasher}; - #[allow(clippy::disallowed_types)] + #[expect(clippy::disallowed_types, reason = "we need a source of randomness for the seed")] std::collections::hash_map::RandomState::new().build_hasher().finish() } diff --git a/src/tools/rust-analyzer/crates/stdx/src/variance.rs b/src/tools/rust-analyzer/crates/stdx/src/variance.rs index 8465d72bf3719..0f87d1bd9bcc6 100644 --- a/src/tools/rust-analyzer/crates/stdx/src/variance.rs +++ b/src/tools/rust-analyzer/crates/stdx/src/variance.rs @@ -70,12 +70,11 @@ macro_rules! phantom_type { impl Eq for $name where T: ?Sized {} - #[allow(clippy::non_canonical_partial_ord_impl)] impl PartialOrd for $name where T: ?Sized { - fn partial_cmp(&self, _: &Self) -> Option { - Some(Ordering::Equal) + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) } } diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs index ced9163f661af..2b1c91f20517d 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs @@ -335,7 +335,7 @@ impl ast::Literal { pub fn token(&self) -> SyntaxToken { self.syntax() .children_with_tokens() - .find(|e| e.kind() != ATTR && !e.kind().is_trivia()) + .find(|e| !ast::AnyAttr::can_cast(e.kind()) && !e.kind().is_trivia()) .and_then(|e| e.into_token()) .unwrap() } diff --git a/src/tools/rust-analyzer/crates/syntax/src/tests.rs b/src/tools/rust-analyzer/crates/syntax/src/tests.rs index e5beb44f42ec7..1002fdd902d29 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/tests.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/tests.rs @@ -126,6 +126,12 @@ fn self_hosting_parsing() { } } +#[test] +fn doc_comment_on_literal_expr() { + let parse = SourceFile::parse("fn f() { ///\n0..0; }", parser::Edition::CURRENT); + assert!(parse.errors().is_empty()); +} + fn test_data_dir() -> PathBuf { project_root().into_std_path_buf().join("crates/syntax/test_data") } diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs index 0d9bb4f92bdc0..129e63d3988b5 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs @@ -670,7 +670,11 @@ pub mod ops { // region:drop #[lang = "drop"] pub trait Drop { - fn drop(&mut self); + fn drop(&mut self) { + // region:pin + Drop::pin_drop(crate::pin::Pin::new(self)) + // endregion:pin + } // region:pin fn pin_drop(self: crate::pin::Pin<&mut Self>) {} diff --git a/src/tools/rust-analyzer/crates/toolchain/src/lib.rs b/src/tools/rust-analyzer/crates/toolchain/src/lib.rs index 6bed98f4cd2d7..26883add08699 100644 --- a/src/tools/rust-analyzer/crates/toolchain/src/lib.rs +++ b/src/tools/rust-analyzer/crates/toolchain/src/lib.rs @@ -74,7 +74,7 @@ impl Tool { // Prevent rustup from automatically installing toolchains, see https://github.com/rust-lang/rust-analyzer/issues/20719. pub const NO_RUSTUP_AUTO_INSTALL_ENV: (&str, &str) = ("RUSTUP_AUTO_INSTALL", "0"); -#[allow(clippy::disallowed_types)] /* generic parameter allows for FxHashMap */ +#[expect(clippy::disallowed_types, reason = "generic parameter allows for `FxHashMap`")] pub fn command( cmd: impl AsRef, working_directory: impl AsRef, diff --git a/src/tools/rust-analyzer/docs/book/src/contributing/lsp-extensions.md b/src/tools/rust-analyzer/docs/book/src/contributing/lsp-extensions.md index da4a5aaa686c5..42bdb5dc1055a 100644 --- a/src/tools/rust-analyzer/docs/book/src/contributing/lsp-extensions.md +++ b/src/tools/rust-analyzer/docs/book/src/contributing/lsp-extensions.md @@ -1,5 +1,5 @@ $DIR/unexpected-type-for-constructor.rs:7:35 + | +LL | const C_INNER: (*const u8, u8) = (None::, None::); + | ^^^^^^^^^^ expected `*const u8`, found `Option` + | + = note: expected raw pointer `*const u8` + found enum `Option` + +error[E0308]: mismatched types + --> $DIR/unexpected-type-for-constructor.rs:7:47 + | +LL | const C_INNER: (*const u8, u8) = (None::, None::); + | ^^^^^^^^^^ expected `u8`, found `Option` + | + = note: expected type `u8` + found enum `Option` + +error: could not evaluate constant pattern + --> $DIR/unexpected-type-for-constructor.rs:13:9 + | +LL | const C_INNER: (*const u8, u8) = (None::, None::); + | ------------------------------ constant defined here +... +LL | C_INNER => {} + | ^^^^^^^ could not evaluate constant + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/mgca/valtree-leaf-const.rs b/tests/ui/const-generics/mgca/valtree-leaf-const.rs new file mode 100644 index 0000000000000..e372e89fe5e50 --- /dev/null +++ b/tests/ui/const-generics/mgca/valtree-leaf-const.rs @@ -0,0 +1,12 @@ +//@ compile-flags: -Znext-solver + +#![feature(macroless_generic_const_args)] +#![feature(generic_const_args)] +#![feature(min_generic_const_args)] + +const TUPLE: (&'static str, &'static str) = ("a", true); +//~^ ERROR mismatched type + +fn main() { + TUPLE; +} diff --git a/tests/ui/const-generics/mgca/valtree-leaf-const.stderr b/tests/ui/const-generics/mgca/valtree-leaf-const.stderr new file mode 100644 index 0000000000000..db45a82198752 --- /dev/null +++ b/tests/ui/const-generics/mgca/valtree-leaf-const.stderr @@ -0,0 +1,9 @@ +error[E0308]: mismatched types + --> $DIR/valtree-leaf-const.rs:7:51 + | +LL | const TUPLE: (&'static str, &'static str) = ("a", true); + | ^^^^ expected `&str`, found `bool` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/generic-associated-types/trait-method-requires-gat-impl-trait.rs b/tests/ui/generic-associated-types/trait-method-requires-gat-impl-trait.rs new file mode 100644 index 0000000000000..3477f579cd0dd --- /dev/null +++ b/tests/ui/generic-associated-types/trait-method-requires-gat-impl-trait.rs @@ -0,0 +1,17 @@ +//! Regression test for . +//@compile-flags: -Znext-solver=globally +//@ check-pass + +trait Trait { + type Assoc; + fn foo() + where + Self::Assoc: Trait; +} + +impl Trait for T { + type Assoc = T; + fn foo() {} +} + +fn main() {}