diff --git a/Cargo.lock b/Cargo.lock index b00b9c55b7595..796e987fb7264 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3515,6 +3515,7 @@ dependencies = [ "rustc_data_structures", "rustc_errors", "rustc_feature", + "rustc_hir", "rustc_macros", "rustc_session", "rustc_span", diff --git a/compiler/rustc_ast_passes/Cargo.toml b/compiler/rustc_ast_passes/Cargo.toml index fdc735fa8d4ff..c9def6246d1b1 100644 --- a/compiler/rustc_ast_passes/Cargo.toml +++ b/compiler/rustc_ast_passes/Cargo.toml @@ -13,6 +13,7 @@ rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } +rustc_hir = { path = "../rustc_hir" } rustc_macros = { path = "../rustc_macros" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 5f9d29490bb90..c955ada05b09a 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -1,11 +1,14 @@ use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; use rustc_ast::{self as ast, AttrVec, NodeId, PatKind, attr, token}; +use rustc_attr_parsing::AttributeParser; use rustc_errors::msg; use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute, Features}; +use rustc_hir::Attribute; +use rustc_hir::attrs::AttributeKind; use rustc_session::Session; use rustc_session::parse::{feature_err, feature_warn}; use rustc_span::source_map::Spanned; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use thin_vec::ThinVec; use crate::errors; @@ -647,17 +650,27 @@ fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate) return; } let mut errored = false; - for attr in krate.attrs.iter().filter(|attr| attr.has_name(sym::feature)) { + + if let Some(Attribute::Parsed(AttributeKind::Feature(feature_idents, first_span))) = + AttributeParser::parse_limited( + sess, + &krate.attrs, + sym::feature, + DUMMY_SP, + krate.id, + Some(&features), + ) + { // `feature(...)` used on non-nightly. This is definitely an error. let mut err = errors::FeatureOnNonNightly { - span: attr.span, + span: first_span, channel: option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)"), stable_features: vec![], sugg: None, }; let mut all_stable = true; - for ident in attr.meta_item_list().into_iter().flatten().flat_map(|nested| nested.ident()) { + for ident in feature_idents { let name = ident.name; let stable_since = features .enabled_lang_features() @@ -672,7 +685,7 @@ fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate) } } if all_stable { - err.sugg = Some(attr.span); + err.sugg = Some(first_span); } sess.dcx().emit_err(err); errored = true; diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs index 3b3bbf4f0c8af..176af5cdd192e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs +++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs @@ -301,3 +301,49 @@ impl NoArgsAttributeParser for DefaultLibAllocatorParser { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::DefaultLibAllocator; } + +pub(crate) struct FeatureParser; + +impl CombineAttributeParser for FeatureParser { + const PATH: &[Symbol] = &[sym::feature]; + type Item = Ident; + const CONVERT: ConvertFn = AttributeKind::Feature; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); + const TEMPLATE: AttributeTemplate = template!(List: &["feature1, feature2, ..."]); + + fn extend( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, + ) -> impl IntoIterator { + let ArgParser::List(list) = args else { + cx.expected_list(cx.attr_span, args); + return Vec::new(); + }; + + if list.is_empty() { + cx.warn_empty_attribute(cx.attr_span); + } + + let mut res = Vec::new(); + + for elem in list.mixed() { + let Some(elem) = elem.meta_item() else { + cx.expected_identifier(elem.span()); + continue; + }; + if let Err(arg_span) = elem.args().no_args() { + cx.expected_no_args(arg_span); + continue; + } + + let path = elem.path(); + let Some(ident) = path.word() else { + cx.expected_identifier(path.span()); + continue; + }; + res.push(ident); + } + + res + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index 2bd5b9a130d1c..c18e292027517 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -175,6 +175,20 @@ impl SingleAttributeParser for RustcLegacyConstGenericsParser { } } +pub(crate) struct RustcInheritOverflowChecksParser; + +impl NoArgsAttributeParser for RustcInheritOverflowChecksParser { + const PATH: &[Symbol] = &[sym::rustc_inherit_overflow_checks]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Fn), + Allow(Target::Method(MethodKind::Inherent)), + Allow(Target::Method(MethodKind::TraitImpl)), + Allow(Target::Closure), + ]); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcInheritOverflowChecks; +} + pub(crate) struct RustcLintOptDenyFieldAccessParser; impl SingleAttributeParser for RustcLintOptDenyFieldAccessParser { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index b4e91ecebeeb7..3e5d9dc8fb6f5 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -157,6 +157,7 @@ attribute_parsers!( Combine, Combine, Combine, + Combine, Combine, Combine, Combine, @@ -286,6 +287,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 2fc057ae38823..259c6cd7728ce 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -2698,7 +2698,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { let mut_span = tcx.sess.source_map().span_until_non_whitespace(span); - tcx.emit_node_span_lint(UNUSED_MUT, lint_root, span, VarNeedNotMut { span: mut_span }) + tcx.emit_diag_node_span_lint( + UNUSED_MUT, + lint_root, + span, + VarNeedNotMut { span: mut_span }, + ) } } } diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs index 7bde534dafd20..eaa41ce1caacf 100644 --- a/compiler/rustc_borrowck/src/session_diagnostics.rs +++ b/compiler/rustc_borrowck/src/session_diagnostics.rs @@ -47,7 +47,7 @@ pub(crate) struct GenericDoesNotLiveLongEnough { pub span: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("variable does not need to be mutable")] pub(crate) struct VarNeedNotMut { #[suggestion( diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 5d03d2406870f..7fd9c28c43f2b 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -86,9 +86,7 @@ use rustc_codegen_ssa::back::write::{ }; use rustc_codegen_ssa::base::codegen_crate; use rustc_codegen_ssa::target_features::cfg_target_feature; -use rustc_codegen_ssa::traits::{ - CodegenBackend, ExtraBackendMethods, ThinBufferMethods, WriteBackendMethods, -}; +use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, WriteBackendMethods}; use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen, TargetConfig}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::profiling::SelfProfilerRef; @@ -423,20 +421,11 @@ unsafe impl Send for SyncContext {} // FIXME(antoyo): that shouldn't be Sync. Parallel compilation is currently disabled with "CodegenBackend::supports_parallel()". unsafe impl Sync for SyncContext {} -pub struct ThinBuffer; - -impl ThinBufferMethods for ThinBuffer { - fn data(&self) -> &[u8] { - &[] - } -} - impl WriteBackendMethods for GccCodegenBackend { type Module = GccContext; type TargetMachine = (); type ModuleBuffer = ModuleBuffer; type ThinData = (); - type ThinBuffer = ThinBuffer; fn run_and_optimize_fat_lto( cgcx: &CodegenContext, @@ -458,7 +447,7 @@ impl WriteBackendMethods for GccCodegenBackend { // FIXME(bjorn3): Limit LTO exports to these symbols _exported_symbols_for_lto: &[String], _each_linked_rlib_for_lto: &[PathBuf], - _modules: Vec<(String, Self::ThinBuffer)>, + _modules: Vec<(String, Self::ModuleBuffer)>, _cached_modules: Vec<(SerializedModule, WorkProduct)>, ) -> (Vec>, Vec) { unreachable!() @@ -502,11 +491,7 @@ impl WriteBackendMethods for GccCodegenBackend { back::write::codegen(cgcx, prof, shared_emitter, module, config) } - fn prepare_thin(_module: ModuleCodegen) -> (String, Self::ThinBuffer) { - unreachable!() - } - - fn serialize_module(_module: ModuleCodegen) -> (String, Self::ModuleBuffer) { + fn serialize_module(_module: Self::Module, _is_thin: bool) -> Self::ModuleBuffer { unimplemented!(); } } diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 5d272d10930b1..c235437aee751 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -2,7 +2,6 @@ use std::collections::BTreeMap; use std::ffi::{CStr, CString}; use std::fs::File; use std::path::{Path, PathBuf}; -use std::ptr::NonNull; use std::sync::Arc; use std::{io, iter, slice}; @@ -187,7 +186,7 @@ pub(crate) fn run_thin( dcx: DiagCtxtHandle<'_>, exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], - modules: Vec<(String, ThinBuffer)>, + modules: Vec<(String, ModuleBuffer)>, cached_modules: Vec<(SerializedModule, WorkProduct)>, ) -> (Vec>, Vec) { let (symbols_below_threshold, upstream_modules) = @@ -203,12 +202,6 @@ pub(crate) fn run_thin( thin_lto(cgcx, prof, dcx, modules, upstream_modules, cached_modules, &symbols_below_threshold) } -pub(crate) fn prepare_thin(module: ModuleCodegen) -> (String, ThinBuffer) { - let name = module.name; - let buffer = ThinBuffer::new(module.module_llvm.llmod(), true); - (name, buffer) -} - fn fat_lto( cgcx: &CodegenContext, prof: &SelfProfilerRef, @@ -297,7 +290,7 @@ fn fat_lto( // way we know of to do that is to serialize them to a string and them parse // them later. Not great but hey, that's why it's "fat" LTO, right? for module in in_memory { - let buffer = ModuleBuffer::new(module.module_llvm.llmod()); + let buffer = ModuleBuffer::new(module.module_llvm.llmod(), false); let llmod_id = CString::new(&module.name[..]).unwrap(); serialized_modules.push((SerializedModule::Local(buffer), llmod_id)); } @@ -400,7 +393,7 @@ fn thin_lto( cgcx: &CodegenContext, prof: &SelfProfilerRef, dcx: DiagCtxtHandle<'_>, - modules: Vec<(String, ThinBuffer)>, + modules: Vec<(String, ModuleBuffer)>, serialized_modules: Vec<(SerializedModule, CString)>, cached_modules: Vec<(SerializedModule, WorkProduct)>, symbols_below_threshold: &[*const libc::c_char], @@ -634,7 +627,9 @@ pub(crate) fn run_pass_manager( }; unsafe { - write::llvm_optimize(cgcx, prof, dcx, module, None, config, opt_level, opt_stage, stage); + write::llvm_optimize( + cgcx, prof, dcx, module, None, None, config, opt_level, opt_stage, stage, + ); } if cfg!(feature = "llvm_enzyme") && enable_ad && !thin { @@ -643,7 +638,7 @@ pub(crate) fn run_pass_manager( if !config.autodiff.contains(&config::AutoDiff::NoPostopt) { unsafe { write::llvm_optimize( - cgcx, prof, dcx, module, None, config, opt_level, opt_stage, stage, + cgcx, prof, dcx, module, None, None, config, opt_level, opt_stage, stage, ); } } @@ -658,31 +653,26 @@ pub(crate) fn run_pass_manager( debug!("lto done"); } -pub struct ModuleBuffer(&'static mut llvm::ModuleBuffer); - -unsafe impl Send for ModuleBuffer {} -unsafe impl Sync for ModuleBuffer {} +#[repr(transparent)] +pub(crate) struct Buffer(&'static mut llvm::Buffer); -impl ModuleBuffer { - pub(crate) fn new(m: &llvm::Module) -> ModuleBuffer { - ModuleBuffer(unsafe { llvm::LLVMRustModuleBufferCreate(m) }) - } -} +unsafe impl Send for Buffer {} +unsafe impl Sync for Buffer {} -impl ModuleBufferMethods for ModuleBuffer { - fn data(&self) -> &[u8] { +impl Buffer { + pub(crate) fn data(&self) -> &[u8] { unsafe { - let ptr = llvm::LLVMRustModuleBufferPtr(self.0); - let len = llvm::LLVMRustModuleBufferLen(self.0); + let ptr = llvm::LLVMRustBufferPtr(self.0); + let len = llvm::LLVMRustBufferLen(self.0); slice::from_raw_parts(ptr, len) } } } -impl Drop for ModuleBuffer { +impl Drop for Buffer { fn drop(&mut self) { unsafe { - llvm::LLVMRustModuleBufferFree(&mut *(self.0 as *mut _)); + llvm::LLVMRustBufferFree(&mut *(self.0 as *mut _)); } } } @@ -700,48 +690,22 @@ impl Drop for ThinData { } } -pub struct ThinBuffer(&'static mut llvm::ThinLTOBuffer); - -unsafe impl Send for ThinBuffer {} -unsafe impl Sync for ThinBuffer {} - -impl ThinBuffer { - pub(crate) fn new(m: &llvm::Module, is_thin: bool) -> ThinBuffer { - unsafe { - let buffer = llvm::LLVMRustThinLTOBufferCreate(m, is_thin); - ThinBuffer(buffer) - } - } - - pub(crate) unsafe fn from_raw_ptr(ptr: *mut llvm::ThinLTOBuffer) -> ThinBuffer { - let mut ptr = NonNull::new(ptr).unwrap(); - ThinBuffer(unsafe { ptr.as_mut() }) - } - - pub(crate) fn thin_link_data(&self) -> &[u8] { - unsafe { - let ptr = llvm::LLVMRustThinLTOBufferThinLinkDataPtr(self.0) as *const _; - let len = llvm::LLVMRustThinLTOBufferThinLinkDataLen(self.0); - slice::from_raw_parts(ptr, len) - } - } +pub struct ModuleBuffer { + data: Buffer, } -impl ThinBufferMethods for ThinBuffer { - fn data(&self) -> &[u8] { +impl ModuleBuffer { + pub(crate) fn new(m: &llvm::Module, is_thin: bool) -> ModuleBuffer { unsafe { - let ptr = llvm::LLVMRustThinLTOBufferPtr(self.0) as *const _; - let len = llvm::LLVMRustThinLTOBufferLen(self.0); - slice::from_raw_parts(ptr, len) + let buffer = llvm::LLVMRustModuleSerialize(m, is_thin); + ModuleBuffer { data: Buffer(buffer) } } } } -impl Drop for ThinBuffer { - fn drop(&mut self) { - unsafe { - llvm::LLVMRustThinLTOBufferFree(&mut *(self.0 as *mut _)); - } +impl ModuleBufferMethods for ModuleBuffer { + fn data(&self) -> &[u8] { + self.data.data() } } diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index cbf82b05e4d6b..d7ab1356fafe7 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -1,7 +1,6 @@ use std::ffi::{CStr, CString}; use std::io::{self, Write}; use std::path::{Path, PathBuf}; -use std::ptr::null_mut; use std::sync::Arc; use std::{fs, slice, str}; @@ -29,7 +28,7 @@ use rustc_target::spec::{ }; use tracing::{debug, trace}; -use crate::back::lto::ThinBuffer; +use crate::back::lto::{Buffer, ModuleBuffer}; use crate::back::owned_target_machine::OwnedTargetMachine; use crate::back::profiling::{ LlvmSelfProfiler, selfprofile_after_pass_callback, selfprofile_before_pass_callback, @@ -563,7 +562,8 @@ pub(crate) unsafe fn llvm_optimize( prof: &SelfProfilerRef, dcx: DiagCtxtHandle<'_>, module: &ModuleCodegen, - thin_lto_buffer: Option<&mut *mut llvm::ThinLTOBuffer>, + thin_lto_buffer: Option<&mut Option>, + thin_lto_summary_buffer: Option<&mut Option>, config: &ModuleConfig, opt_level: config::OptLevel, opt_stage: llvm::OptStage, @@ -786,7 +786,7 @@ pub(crate) unsafe fn llvm_optimize( config.verify_llvm_ir, config.lint_llvm_ir, thin_lto_buffer, - config.emit_thin_lto_summary, + thin_lto_summary_buffer, merge_functions, unroll_loops, vectorize_slp, @@ -932,13 +932,14 @@ pub(crate) fn optimize( // The bitcode obtained during the `codegen` phase is no longer suitable for performing LTO. // It may have undergone LTO due to ThinLocal, so we need to obtain the embedded bitcode at // this point. - let mut thin_lto_buffer = if (module.kind == ModuleKind::Regular + let (mut thin_lto_buffer, mut thin_lto_summary_buffer) = if (module.kind + == ModuleKind::Regular && config.emit_obj == EmitObj::ObjectCode(BitcodeSection::Full)) || config.emit_thin_lto_summary { - Some(null_mut()) + (Some(None), config.emit_thin_lto_summary.then_some(None)) } else { - None + (None, None) }; unsafe { llvm_optimize( @@ -947,6 +948,7 @@ pub(crate) fn optimize( dcx, module, thin_lto_buffer.as_mut(), + thin_lto_summary_buffer.as_mut(), config, opt_level, opt_stage, @@ -954,17 +956,18 @@ pub(crate) fn optimize( ) }; if let Some(thin_lto_buffer) = thin_lto_buffer { - let thin_lto_buffer = unsafe { ThinBuffer::from_raw_ptr(thin_lto_buffer) }; + let thin_lto_buffer = thin_lto_buffer.unwrap(); module.thin_lto_buffer = Some(thin_lto_buffer.data().to_vec()); let bc_summary_out = cgcx.output_filenames.temp_path_for_cgu( OutputType::ThinLinkBitcode, &module.name, cgcx.invocation_temp.as_deref(), ); - if config.emit_thin_lto_summary + if let Some(thin_lto_summary_buffer) = thin_lto_summary_buffer && let Some(thin_link_bitcode_filename) = bc_summary_out.file_name() { - let summary_data = thin_lto_buffer.thin_link_data(); + let thin_lto_summary_buffer = thin_lto_summary_buffer.unwrap(); + let summary_data = thin_lto_summary_buffer.data(); prof.artifact_size( "llvm_bitcode_summary", thin_link_bitcode_filename.to_string_lossy(), @@ -1032,7 +1035,7 @@ pub(crate) fn codegen( "LLVM_module_codegen_make_bitcode", &*module.name, ); - ThinBuffer::new(llmod, cgcx.lto != Lto::Fat) + ModuleBuffer::new(llmod, cgcx.lto != Lto::Fat) }; let data = thin.data(); let _timer = prof diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 83dcfb812e492..7120ee0afec96 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -153,7 +153,6 @@ impl WriteBackendMethods for LlvmCodegenBackend { type ModuleBuffer = back::lto::ModuleBuffer; type TargetMachine = OwnedTargetMachine; type ThinData = back::lto::ThinData; - type ThinBuffer = back::lto::ThinBuffer; fn print_pass_timings(&self) { let timings = llvm::build_string(|s| unsafe { llvm::LLVMRustPrintPassTimings(s) }).unwrap(); print!("{timings}"); @@ -193,7 +192,7 @@ impl WriteBackendMethods for LlvmCodegenBackend { dcx: DiagCtxtHandle<'_>, exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], - modules: Vec<(String, Self::ThinBuffer)>, + modules: Vec<(String, Self::ModuleBuffer)>, cached_modules: Vec<(SerializedModule, WorkProduct)>, ) -> (Vec>, Vec) { back::lto::run_thin( @@ -233,11 +232,8 @@ impl WriteBackendMethods for LlvmCodegenBackend { ) -> CompiledModule { back::write::codegen(cgcx, prof, shared_emitter, module, config) } - fn prepare_thin(module: ModuleCodegen) -> (String, Self::ThinBuffer) { - back::lto::prepare_thin(module) - } - fn serialize_module(module: ModuleCodegen) -> (String, Self::ModuleBuffer) { - (module.name, back::lto::ModuleBuffer::new(module.module_llvm.llmod())) + fn serialize_module(module: Self::Module, is_thin: bool) -> Self::ModuleBuffer { + back::lto::ModuleBuffer::new(module.llmod(), is_thin) } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 59bf8679d6398..f9af42494cada 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -536,9 +536,6 @@ pub(crate) enum DiagnosticLevel { unsafe extern "C" { // LLVMRustThinLTOData pub(crate) type ThinLTOData; - - // LLVMRustThinLTOBuffer - pub(crate) type ThinLTOBuffer; } /// LLVMRustThinLTOModule @@ -848,7 +845,7 @@ bitflags! { } unsafe extern "C" { - pub(crate) type ModuleBuffer; + pub(crate) type Buffer; } pub(crate) type SelfProfileBeforePassCallback = @@ -2375,8 +2372,8 @@ unsafe extern "C" { NoPrepopulatePasses: bool, VerifyIR: bool, LintIR: bool, - ThinLTOBuffer: Option<&mut *mut ThinLTOBuffer>, - EmitThinLTOSummary: bool, + ThinLTOBuffer: Option<&mut Option>, + ThinLTOSummaryBuffer: Option<&mut Option>, MergeFunctions: bool, UnrollLoops: bool, SLPVectorize: bool, @@ -2457,22 +2454,13 @@ unsafe extern "C" { pub(crate) fn LLVMRustSetModulePICLevel(M: &Module); pub(crate) fn LLVMRustSetModulePIELevel(M: &Module); pub(crate) fn LLVMRustSetModuleCodeModel(M: &Module, Model: CodeModel); - pub(crate) fn LLVMRustModuleBufferCreate(M: &Module) -> &'static mut ModuleBuffer; - pub(crate) fn LLVMRustModuleBufferPtr(p: &ModuleBuffer) -> *const u8; - pub(crate) fn LLVMRustModuleBufferLen(p: &ModuleBuffer) -> usize; - pub(crate) fn LLVMRustModuleBufferFree(p: &'static mut ModuleBuffer); + pub(crate) fn LLVMRustBufferPtr(p: &Buffer) -> *const u8; + pub(crate) fn LLVMRustBufferLen(p: &Buffer) -> usize; + pub(crate) fn LLVMRustBufferFree(p: &'static mut Buffer); pub(crate) fn LLVMRustModuleCost(M: &Module) -> u64; pub(crate) fn LLVMRustModuleInstructionStats(M: &Module) -> u64; - pub(crate) fn LLVMRustThinLTOBufferCreate( - M: &Module, - is_thin: bool, - ) -> &'static mut ThinLTOBuffer; - pub(crate) fn LLVMRustThinLTOBufferFree(M: &'static mut ThinLTOBuffer); - pub(crate) fn LLVMRustThinLTOBufferPtr(M: &ThinLTOBuffer) -> *const c_char; - pub(crate) fn LLVMRustThinLTOBufferLen(M: &ThinLTOBuffer) -> size_t; - pub(crate) fn LLVMRustThinLTOBufferThinLinkDataPtr(M: &ThinLTOBuffer) -> *const c_char; - pub(crate) fn LLVMRustThinLTOBufferThinLinkDataLen(M: &ThinLTOBuffer) -> size_t; + pub(crate) fn LLVMRustModuleSerialize(M: &Module, is_thin: bool) -> &'static mut Buffer; pub(crate) fn LLVMRustCreateThinLTOData( Modules: *const ThinLTOModule, NumModules: size_t, diff --git a/compiler/rustc_codegen_ssa/src/back/lto.rs b/compiler/rustc_codegen_ssa/src/back/lto.rs index 80b3b5a4d7c06..a2c951c16d28d 100644 --- a/compiler/rustc_codegen_ssa/src/back/lto.rs +++ b/compiler/rustc_codegen_ssa/src/back/lto.rs @@ -42,7 +42,7 @@ impl ThinModule { pub struct ThinShared { pub data: B::ThinData, - pub thin_buffers: Vec, + pub thin_buffers: Vec, pub serialized_modules: Vec>, pub module_names: Vec, } diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 81d173af275f9..9898c1296142a 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -362,7 +362,7 @@ fn generate_thin_lto_work( dcx: DiagCtxtHandle<'_>, exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], - needs_thin_lto: Vec<(String, B::ThinBuffer)>, + needs_thin_lto: Vec<(String, B::ModuleBuffer)>, import_only_modules: Vec<(SerializedModule, WorkProduct)>, ) -> Vec<(ThinLtoWorkItem, u64)> { let _prof_timer = prof.generic_activity("codegen_thin_generate_lto_work"); @@ -416,7 +416,7 @@ enum MaybeLtoModules { cgcx: CodegenContext, exported_symbols_for_lto: Arc>, each_linked_rlib_file_for_lto: Vec, - needs_thin_lto: Vec<(String, ::ThinBuffer)>, + needs_thin_lto: Vec<(String, ::ModuleBuffer)>, lto_import_only_modules: Vec<(SerializedModule<::ModuleBuffer>, WorkProduct)>, }, @@ -793,7 +793,7 @@ pub(crate) enum WorkItemResult { /// The backend has finished compiling a CGU, which now needs to go through /// thin LTO. - NeedsThinLto(String, B::ThinBuffer), + NeedsThinLto(String, B::ModuleBuffer), } pub enum FatLtoInput { @@ -868,22 +868,22 @@ fn execute_optimize_work_item( WorkItemResult::Finished(module) } ComputedLtoType::Thin => { - let (name, thin_buffer) = B::prepare_thin(module); + let thin_buffer = B::serialize_module(module.module_llvm, true); if let Some(path) = bitcode { fs::write(&path, thin_buffer.data()).unwrap_or_else(|e| { panic!("Error writing pre-lto-bitcode file `{}`: {}", path.display(), e); }); } - WorkItemResult::NeedsThinLto(name, thin_buffer) + WorkItemResult::NeedsThinLto(module.name, thin_buffer) } ComputedLtoType::Fat => match bitcode { Some(path) => { - let (name, buffer) = B::serialize_module(module); + let buffer = B::serialize_module(module.module_llvm, false); fs::write(&path, buffer.data()).unwrap_or_else(|e| { panic!("Error writing pre-lto-bitcode file `{}`: {}", path.display(), e); }); WorkItemResult::NeedsFatLto(FatLtoInput::Serialized { - name, + name: module.name, buffer: SerializedModule::Local(buffer), }) } @@ -1020,7 +1020,7 @@ fn do_thin_lto( tm_factory: TargetMachineFactoryFn, exported_symbols_for_lto: Arc>, each_linked_rlib_for_lto: Vec, - needs_thin_lto: Vec<(String, ::ThinBuffer)>, + needs_thin_lto: Vec<(String, ::ModuleBuffer)>, lto_import_only_modules: Vec<( SerializedModule<::ModuleBuffer>, WorkProduct, @@ -1804,8 +1804,8 @@ fn start_executing_work( )); } else { if let Some(allocator_module) = allocator_module.take() { - let (name, thin_buffer) = B::prepare_thin(allocator_module); - needs_thin_lto.push((name, thin_buffer)); + let thin_buffer = B::serialize_module(allocator_module.module_llvm, true); + needs_thin_lto.push((allocator_module.name, thin_buffer)); } return Ok(MaybeLtoModules::ThinLto { diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 74f7829ace95a..be1965f674911 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -10,7 +10,7 @@ use rustc_errors::codes::*; use rustc_errors::{ Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level, msg, }; -use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; +use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::ty::layout::LayoutError; use rustc_middle::ty::{FloatTy, Ty}; use rustc_span::{Span, Symbol}; @@ -1164,7 +1164,7 @@ pub(crate) struct XcrunSdkPathWarning { pub stderr: String, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("enabling the `neon` target feature on the current target is unsound due to ABI issues")] pub(crate) struct Aarch64SoftfloatNeon; diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index e9209657984e0..d7f871527e3d1 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -75,7 +75,7 @@ pub(crate) fn from_target_feature_attr( // For "neon" specifically, we emit an FCW instead of a hard error. // See . if tcx.sess.target.arch == Arch::AArch64 && name.as_str() == "neon" { - tcx.emit_node_span_lint( + tcx.emit_diag_node_span_lint( AARCH64_SOFTFLOAT_NEON, tcx.local_def_id_to_hir_id(did), feature_span, diff --git a/compiler/rustc_codegen_ssa/src/traits/mod.rs b/compiler/rustc_codegen_ssa/src/traits/mod.rs index 6d1ac717c0b8f..f46d07ea5008e 100644 --- a/compiler/rustc_codegen_ssa/src/traits/mod.rs +++ b/compiler/rustc_codegen_ssa/src/traits/mod.rs @@ -48,7 +48,7 @@ pub use self::type_::{ ArgAbiBuilderMethods, BaseTypeCodegenMethods, DerivedTypeCodegenMethods, LayoutTypeCodegenMethods, TypeCodegenMethods, TypeMembershipCodegenMethods, }; -pub use self::write::{ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods}; +pub use self::write::{ModuleBufferMethods, WriteBackendMethods}; pub trait CodegenObject = Copy + fmt::Debug; diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs index 5f5d0ac5d9fc4..d33dfc1d014b5 100644 --- a/compiler/rustc_codegen_ssa/src/traits/write.rs +++ b/compiler/rustc_codegen_ssa/src/traits/write.rs @@ -15,7 +15,6 @@ pub trait WriteBackendMethods: Clone + 'static { type TargetMachine; type ModuleBuffer: ModuleBufferMethods; type ThinData: Send + Sync; - type ThinBuffer: ThinBufferMethods; /// Performs fat LTO by merging all modules into a single one, running autodiff /// if necessary and running any further optimizations @@ -37,7 +36,7 @@ pub trait WriteBackendMethods: Clone + 'static { dcx: DiagCtxtHandle<'_>, exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], - modules: Vec<(String, Self::ThinBuffer)>, + modules: Vec<(String, Self::ModuleBuffer)>, cached_modules: Vec<(SerializedModule, WorkProduct)>, ) -> (Vec>, Vec); fn print_pass_timings(&self); @@ -63,12 +62,7 @@ pub trait WriteBackendMethods: Clone + 'static { module: ModuleCodegen, config: &ModuleConfig, ) -> CompiledModule; - fn prepare_thin(module: ModuleCodegen) -> (String, Self::ThinBuffer); - fn serialize_module(module: ModuleCodegen) -> (String, Self::ModuleBuffer); -} - -pub trait ThinBufferMethods: Send + Sync { - fn data(&self) -> &[u8]; + fn serialize_module(module: Self::Module, is_thin: bool) -> Self::ModuleBuffer; } pub trait ModuleBufferMethods: Send + Sync { diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 69aef3b047df2..7efef74e70aa3 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -252,9 +252,9 @@ pub(super) fn lint<'tcx, L>( lint: &'static rustc_session::lint::Lint, decorator: impl FnOnce(Vec) -> L, ) where - L: for<'a> rustc_errors::LintDiagnostic<'a, ()>, + L: for<'a> rustc_errors::Diagnostic<'a, ()>, { let (span, frames) = get_span_and_frames(tcx, &machine.stack); - tcx.emit_node_span_lint(lint, machine.best_lint_scope(*tcx), span, decorator(frames)); + tcx.emit_diag_node_span_lint(lint, machine.best_lint_scope(*tcx), span, decorator(frames)); } diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 025c59747eaf7..3da9f2e2cdcdf 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -2,7 +2,7 @@ use std::borrow::{Borrow, Cow}; use std::fmt; use std::hash::Hash; -use rustc_abi::{Align, Size}; +use rustc_abi::{Align, FIRST_VARIANT, Size}; use rustc_ast::Mutability; use rustc_data_structures::fx::{FxHashMap, FxIndexMap, IndexEntry}; use rustc_errors::msg; @@ -24,7 +24,7 @@ use crate::interpret::{ self, AllocId, AllocInit, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame, GlobalAlloc, ImmTy, InterpCx, InterpResult, OpTy, PlaceTy, Pointer, RangeSet, Scalar, compile_time_machine, err_inval, interp_ok, throw_exhaust, throw_inval, throw_ub, - throw_ub_custom, throw_unsup, throw_unsup_format, + throw_ub_custom, throw_unsup, throw_unsup_format, type_implements_dyn_trait, }; /// When hitting this many interpreted terminators we emit a deny by default lint @@ -598,6 +598,22 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { } } + sym::type_id_vtable => { + let tp_ty = ecx.read_type_id(&args[0])?; + let result_ty = ecx.read_type_id(&args[1])?; + + let (implements_trait, preds) = type_implements_dyn_trait(ecx, tp_ty, result_ty)?; + + if implements_trait { + let vtable_ptr = ecx.get_vtable_ptr(tp_ty, preds)?; + // Writing a non-null pointer into an `Option` will automatically make it `Some`. + ecx.write_pointer(vtable_ptr, dest)?; + } else { + // Write `None` + ecx.write_discriminant(FIRST_VARIANT, dest)?; + } + } + sym::type_of => { let ty = ecx.read_type_id(&args[0])?; ecx.write_type_info(ty, dest)?; @@ -702,7 +718,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { .level .is_error(); let span = ecx.cur_span(); - ecx.tcx.emit_node_span_lint( + ecx.tcx.emit_diag_node_span_lint( rustc_session::lint::builtin::LONG_RUNNING_CONST_EVAL, hir_id, span, diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 6a33a9ae0597c..cdc02ae6933d2 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -9,7 +9,7 @@ use rustc_errors::{ Subdiagnostic, msg, }; use rustc_hir::ConstContext; -use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; +use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::mir::interpret::{ CtfeProvenance, ExpectedKind, InterpErrorKind, InvalidMetaKind, InvalidProgramInfo, Misalignment, Pointer, PointerKind, ResourceExhaustionInfo, UndefinedBehaviorInfo, @@ -318,7 +318,7 @@ pub(crate) struct InteriorMutableBorrowEscaping { pub kind: ConstContext, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("constant evaluation is taking a long time")] #[note( "this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval. diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index e0c75da87a4b6..fe06b0a6e0d81 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -4,19 +4,16 @@ mod simd; -use rustc_abi::{FIRST_VARIANT, FieldIdx, HasDataLayout, Size, VariantIdx}; +use rustc_abi::{FieldIdx, HasDataLayout, Size, VariantIdx}; use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use rustc_data_structures::assert_matches; use rustc_errors::msg; -use rustc_hir::def_id::CRATE_DEF_ID; -use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir::interpret::{CTFE_ALLOC_SALT, read_target_uint, write_target_uint}; use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic}; use rustc_middle::ty::layout::TyAndLayout; -use rustc_middle::ty::{FloatTy, PolyExistentialPredicate, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{FloatTy, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::{bug, span_bug, ty}; use rustc_span::{Symbol, sym}; -use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt}; use tracing::trace; use super::memory::MemoryKind; @@ -227,44 +224,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.write_scalar(Scalar::from_target_usize(offset, self), dest)?; } - sym::vtable_for => { - let tp_ty = instance.args.type_at(0); - let result_ty = instance.args.type_at(1); - - ensure_monomorphic_enough(tcx, tp_ty)?; - ensure_monomorphic_enough(tcx, result_ty)?; - let ty::Dynamic(preds, _) = result_ty.kind() else { - span_bug!( - self.find_closest_untracked_caller_location(), - "Invalid type provided to vtable_for::. U must be dyn Trait, got {result_ty}." - ); - }; - - let (infcx, param_env) = - self.tcx.infer_ctxt().build_with_typing_env(self.typing_env); - - let ocx = ObligationCtxt::new(&infcx); - ocx.register_obligations(preds.iter().map(|pred: PolyExistentialPredicate<'_>| { - let pred = pred.with_self_ty(tcx, tp_ty); - // Lifetimes can only be 'static because of the bound on T - let pred = ty::fold_regions(tcx, pred, |r, _| { - if r == tcx.lifetimes.re_erased { tcx.lifetimes.re_static } else { r } - }); - Obligation::new(tcx, ObligationCause::dummy(), param_env, pred) - })); - let type_impls_trait = ocx.evaluate_obligations_error_on_ambiguity().is_empty(); - // Since `assumed_wf_tys=[]` the choice of LocalDefId is irrelevant, so using the "default" - let regions_are_valid = ocx.resolve_regions(CRATE_DEF_ID, param_env, []).is_empty(); - - if regions_are_valid && type_impls_trait { - let vtable_ptr = self.get_vtable_ptr(tp_ty, preds)?; - // Writing a non-null pointer into an `Option` will automatically make it `Some`. - self.write_pointer(vtable_ptr, dest)?; - } else { - // Write `None` - self.write_discriminant(FIRST_VARIANT, dest)?; - } - } sym::variant_count => { let tp_ty = instance.args.type_at(0); let ty = match tp_ty.kind() { diff --git a/compiler/rustc_const_eval/src/interpret/mod.rs b/compiler/rustc_const_eval/src/interpret/mod.rs index c8ffc0ed208a7..3fbb043885715 100644 --- a/compiler/rustc_const_eval/src/interpret/mod.rs +++ b/compiler/rustc_const_eval/src/interpret/mod.rs @@ -38,6 +38,6 @@ use self::place::{MemPlace, Place}; pub use self::projection::{OffsetMode, Projectable}; pub use self::stack::{Frame, FrameInfo, LocalState, ReturnContinuation}; pub use self::util::EnteredTraceSpan; -pub(crate) use self::util::create_static_alloc; +pub(crate) use self::util::{create_static_alloc, type_implements_dyn_trait}; pub use self::validity::{CtfeValidationMode, RangeSet, RefTracking}; pub use self::visitor::ValueVisitor; diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 0dd17f109be31..126d0fc9b7a1b 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -86,7 +86,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { span = ?stmt.source_info.span, tracing_separate_thread = Empty, ) - .or_if_tracing_disabled(|| info!(stmt = ?stmt.kind)); + .or_if_tracing_disabled(|| info!("{:?}", stmt.kind)); use rustc_middle::mir::StatementKind::*; @@ -490,7 +490,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { span = ?terminator.source_info.span, tracing_separate_thread = Empty, ) - .or_if_tracing_disabled(|| info!(terminator = ?terminator.kind)); + .or_if_tracing_disabled(|| info!("{:?}", terminator.kind)); use rustc_middle::mir::TerminatorKind::*; match terminator.kind { diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index 1e18a22be81c2..57a02769643b7 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -1,12 +1,51 @@ -use rustc_hir::def_id::LocalDefId; -use rustc_middle::mir; +use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; +use rustc_infer::infer::TyCtxtInferExt; +use rustc_infer::traits::{Obligation, ObligationCause}; use rustc_middle::mir::interpret::{AllocInit, Allocation, GlobalAlloc, InterpResult, Pointer}; use rustc_middle::ty::layout::TyAndLayout; -use rustc_middle::ty::{TyCtxt, TypeVisitable, TypeVisitableExt}; +use rustc_middle::ty::{PolyExistentialPredicate, Ty, TyCtxt, TypeVisitable, TypeVisitableExt}; +use rustc_middle::{mir, span_bug, ty}; +use rustc_trait_selection::traits::ObligationCtxt; use tracing::debug; use super::{InterpCx, MPlaceTy, MemoryKind, interp_ok, throw_inval}; use crate::const_eval::{CompileTimeInterpCx, CompileTimeMachine, InterpretationResult}; +use crate::interpret::Machine; + +/// Checks if a type implements predicates. +/// Calls `ensure_monomorphic_enough` on `ty` and `trait_ty` for you. +pub(crate) fn type_implements_dyn_trait<'tcx, M: Machine<'tcx>>( + ecx: &mut InterpCx<'tcx, M>, + ty: Ty<'tcx>, + trait_ty: Ty<'tcx>, +) -> InterpResult<'tcx, (bool, &'tcx ty::List>)> { + ensure_monomorphic_enough(ecx.tcx.tcx, ty)?; + ensure_monomorphic_enough(ecx.tcx.tcx, trait_ty)?; + + let ty::Dynamic(preds, _) = trait_ty.kind() else { + span_bug!( + ecx.find_closest_untracked_caller_location(), + "Invalid type provided to type_implements_predicates. U must be dyn Trait, got {trait_ty}." + ); + }; + + let (infcx, param_env) = ecx.tcx.infer_ctxt().build_with_typing_env(ecx.typing_env); + + let ocx = ObligationCtxt::new(&infcx); + ocx.register_obligations(preds.iter().map(|pred: PolyExistentialPredicate<'_>| { + let pred = pred.with_self_ty(ecx.tcx.tcx, ty); + // Lifetimes can only be 'static because of the bound on T + let pred = rustc_middle::ty::fold_regions(ecx.tcx.tcx, pred, |r, _| { + if r == ecx.tcx.tcx.lifetimes.re_erased { ecx.tcx.tcx.lifetimes.re_static } else { r } + }); + Obligation::new(ecx.tcx.tcx, ObligationCause::dummy(), param_env, pred) + })); + let type_impls_trait = ocx.evaluate_obligations_error_on_ambiguity().is_empty(); + // Since `assumed_wf_tys=[]` the choice of LocalDefId is irrelevant, so using the "default" + let regions_are_valid = ocx.resolve_regions(CRATE_DEF_ID, param_env, []).is_empty(); + + interp_ok((regions_are_valid && type_impls_trait, preds)) +} /// Checks whether a type contains generic parameters which must be instantiated. /// diff --git a/compiler/rustc_error_codes/src/error_codes/E0556.md b/compiler/rustc_error_codes/src/error_codes/E0556.md index 2aac8240d293a..d1eeddc3ab102 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0556.md +++ b/compiler/rustc_error_codes/src/error_codes/E0556.md @@ -1,8 +1,10 @@ +#### Note: this error code is no longer emitted by the compiler. + The `feature` attribute was badly formed. Erroneous code example: -```compile_fail,E0556 +```compile_fail #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)] // error! #![feature] // error! #![feature = "foo"] // error! diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index 0537ba23de944..eff9b9d323c25 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -334,7 +334,7 @@ macro_rules! error_codes { 0551, 0552, 0554, -0556, +0556, // REMOVED: merged with other attribute error codes 0557, 0559, 0560, diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index a8a305310238e..8e4039b32d942 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -7,8 +7,8 @@ use rustc_ast::tokenstream::{ AttrTokenStream, AttrTokenTree, LazyAttrTokenStream, Spacing, TokenTree, }; use rustc_ast::{ - self as ast, AttrItemKind, AttrKind, AttrStyle, Attribute, EarlyParsedAttribute, HasAttrs, - HasTokens, MetaItem, MetaItemInner, NodeId, NormalAttr, + self as ast, AttrItemKind, AttrKind, AttrStyle, Attribute, DUMMY_NODE_ID, EarlyParsedAttribute, + HasAttrs, HasTokens, MetaItem, MetaItemInner, NodeId, NormalAttr, }; use rustc_attr_parsing as attr; use rustc_attr_parsing::{ @@ -20,18 +20,19 @@ use rustc_feature::{ ACCEPTED_LANG_FEATURES, EnabledLangFeature, EnabledLibFeature, Features, REMOVED_LANG_FEATURES, UNSTABLE_LANG_FEATURES, }; -use rustc_hir::Target; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::{ + Target, {self as hir}, +}; use rustc_parse::parser::Recovery; use rustc_session::Session; use rustc_session::parse::feature_err; -use rustc_span::{STDLIB_STABLE_CRATES, Span, Symbol, sym}; -use thin_vec::ThinVec; +use rustc_span::{DUMMY_SP, STDLIB_STABLE_CRATES, Span, Symbol, sym}; use tracing::instrument; use crate::errors::{ CrateNameInCfgAttr, CrateTypeInCfgAttr, FeatureNotAllowed, FeatureRemoved, - FeatureRemovedReason, InvalidCfg, MalformedFeatureAttribute, MalformedFeatureAttributeHelp, - RemoveExprNotSupported, + FeatureRemovedReason, InvalidCfg, RemoveExprNotSupported, }; /// A folder that strips out items that do not belong in the current configuration. @@ -46,44 +47,23 @@ pub struct StripUnconfigured<'a> { } pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -> Features { - fn feature_list(attr: &Attribute) -> ThinVec { - if attr.has_name(sym::feature) - && let Some(list) = attr.meta_item_list() - { - list - } else { - ThinVec::new() - } - } - let mut features = Features::default(); - // Process all features enabled in the code. - for attr in krate_attrs { - for mi in feature_list(attr) { - let name = match mi.ident() { - Some(ident) if mi.is_word() => ident.name, - Some(ident) => { - sess.dcx().emit_err(MalformedFeatureAttribute { - span: mi.span(), - help: MalformedFeatureAttributeHelp::Suggestion { - span: mi.span(), - suggestion: ident.name, - }, - }); - continue; - } - None => { - sess.dcx().emit_err(MalformedFeatureAttribute { - span: mi.span(), - help: MalformedFeatureAttributeHelp::Label { span: mi.span() }, - }); - continue; - } - }; - + if let Some(hir::Attribute::Parsed(AttributeKind::Feature(feature_idents, _))) = + AttributeParser::parse_limited( + sess, + krate_attrs, + sym::feature, + DUMMY_SP, + DUMMY_NODE_ID, + Some(&features), + ) + { + for feature_ident in feature_idents { // If the enabled feature has been removed, issue an error. - if let Some(f) = REMOVED_LANG_FEATURES.iter().find(|f| name == f.feature.name) { + if let Some(f) = + REMOVED_LANG_FEATURES.iter().find(|f| feature_ident.name == f.feature.name) + { let pull_note = if let Some(pull) = f.pull { format!( "; see for more information", @@ -92,7 +72,7 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) - "".to_owned() }; sess.dcx().emit_err(FeatureRemoved { - span: mi.span(), + span: feature_ident.span, reason: f.reason.map(|reason| FeatureRemovedReason { reason }), removed_rustc_version: f.feature.since, pull_note, @@ -101,10 +81,10 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) - } // If the enabled feature is stable, record it. - if let Some(f) = ACCEPTED_LANG_FEATURES.iter().find(|f| name == f.name) { + if let Some(f) = ACCEPTED_LANG_FEATURES.iter().find(|f| feature_ident.name == f.name) { features.set_enabled_lang_feature(EnabledLangFeature { - gate_name: name, - attr_sp: mi.span(), + gate_name: feature_ident.name, + attr_sp: feature_ident.span, stable_since: Some(Symbol::intern(f.since)), }); continue; @@ -114,25 +94,30 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) - // unstable and not also listed as one of the allowed features, // issue an error. if let Some(allowed) = sess.opts.unstable_opts.allow_features.as_ref() { - if allowed.iter().all(|f| name.as_str() != f) { - sess.dcx().emit_err(FeatureNotAllowed { span: mi.span(), name }); + if allowed.iter().all(|f| feature_ident.name.as_str() != f) { + sess.dcx().emit_err(FeatureNotAllowed { + span: feature_ident.span, + name: feature_ident.name, + }); continue; } } // If the enabled feature is unstable, record it. - if UNSTABLE_LANG_FEATURES.iter().find(|f| name == f.name).is_some() { + if UNSTABLE_LANG_FEATURES.iter().find(|f| feature_ident.name == f.name).is_some() { // When the ICE comes from a standard library crate, there's a chance that the person // hitting the ICE may be using -Zbuild-std or similar with an untested target. // The bug is probably in the standard library and not the compiler in that case, // but that doesn't really matter - we want a bug report. - if features.internal(name) && !STDLIB_STABLE_CRATES.contains(&crate_name) { + if features.internal(feature_ident.name) + && !STDLIB_STABLE_CRATES.contains(&crate_name) + { sess.using_internal_features.store(true, std::sync::atomic::Ordering::Relaxed); } features.set_enabled_lang_feature(EnabledLangFeature { - gate_name: name, - attr_sp: mi.span(), + gate_name: feature_ident.name, + attr_sp: feature_ident.span, stable_since: None, }); continue; @@ -140,12 +125,15 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) - // Otherwise, the feature is unknown. Enable it as a lib feature. // It will be checked later whether the feature really exists. - features - .set_enabled_lib_feature(EnabledLibFeature { gate_name: name, attr_sp: mi.span() }); + features.set_enabled_lib_feature(EnabledLibFeature { + gate_name: feature_ident.name, + attr_sp: feature_ident.span, + }); // Similar to above, detect internal lib features to suppress // the ICE message that asks for a report. - if features.internal(name) && !STDLIB_STABLE_CRATES.contains(&crate_name) { + if features.internal(feature_ident.name) && !STDLIB_STABLE_CRATES.contains(&crate_name) + { sess.using_internal_features.store(true, std::sync::atomic::Ordering::Relaxed); } } diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index 70e386ceb95ec..8285733c68aa7 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -183,34 +183,6 @@ pub(crate) struct RecursionLimitReached { pub crate_name: Symbol, } -#[derive(Diagnostic)] -#[diag("malformed `feature` attribute input", code = E0556)] -pub(crate) struct MalformedFeatureAttribute { - #[primary_span] - pub span: Span, - #[subdiagnostic] - pub help: MalformedFeatureAttributeHelp, -} - -#[derive(Subdiagnostic)] -pub(crate) enum MalformedFeatureAttributeHelp { - #[label("expected just one word")] - Label { - #[primary_span] - span: Span, - }, - #[suggestion( - "expected just one word", - code = "{suggestion}", - applicability = "maybe-incorrect" - )] - Suggestion { - #[primary_span] - span: Span, - suggestion: Symbol, - }, -} - #[derive(Diagnostic)] #[diag("removing an expression is not supported in this position")] pub(crate) struct RemoveExprNotSupported { diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 5d154cef66a65..e33d943fa5461 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -954,6 +954,9 @@ pub enum AttributeKind { /// Represents `#[export_stable]`. ExportStable, + /// Represents `#[feature(...)]` + Feature(ThinVec, Span), + /// Represents `#[ffi_const]`. FfiConst(Span), @@ -1274,6 +1277,9 @@ pub enum AttributeKind { /// Represents `#[rustc_if_this_changed]` RustcIfThisChanged(Span, Option), + /// Represents `#[rustc_inherit_overflow_checks]` + RustcInheritOverflowChecks, + /// Represents `#[rustc_insignificant_dtor]` RustcInsignificantDtor, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 0b20ea4d6a83a..3088d4bc32858 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -45,6 +45,7 @@ impl AttributeKind { EiiImpls(..) => No, ExportName { .. } => Yes, ExportStable => No, + Feature(..) => No, FfiConst(..) => No, FfiPure(..) => No, Fundamental { .. } => Yes, @@ -130,6 +131,7 @@ impl AttributeKind { RustcHasIncoherentInherentImpls => Yes, RustcHiddenTypeOfOpaques => No, RustcIfThisChanged(..) => No, + RustcInheritOverflowChecks => No, RustcInsignificantDtor => Yes, RustcIntrinsic => Yes, RustcIntrinsicConstStableIndirect => No, diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 349ad4f7fc43b..e8323a218e7a8 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1264,7 +1264,7 @@ fn check_impl_items_against_trait<'tcx>( } if self_is_guaranteed_unsize_self && tcx.generics_require_sized_self(ty_trait_item.def_id) { - tcx.emit_node_span_lint( + tcx.emit_diag_node_span_lint( rustc_lint_defs::builtin::DEAD_CODE, tcx.local_def_id_to_hir_id(ty_impl_item.def_id.expect_local()), tcx.def_span(ty_impl_item.def_id), diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs index 31104411ab55b..0944edd86ef19 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -345,7 +345,7 @@ fn report_mismatched_rpitit_signature<'tcx>( with_no_trimmed_paths!(with_types_for_signature!(format!("{return_ty}"))); let span = unmatched_bound.unwrap_or(span); - tcx.emit_node_span_lint( + tcx.emit_diag_node_span_lint( if is_internal { REFINING_IMPL_TRAIT_INTERNAL } else { REFINING_IMPL_TRAIT_REACHABLE }, tcx.local_def_id_to_hir_id(impl_m_def_id.expect_local()), span, @@ -442,7 +442,7 @@ fn report_mismatched_rpitit_captures<'tcx>( .sort_by_cached_key(|arg| !matches!(arg.kind(), ty::GenericArgKind::Lifetime(_))); let suggestion = format!("use<{}>", trait_captured_args.iter().join(", ")); - tcx.emit_node_span_lint( + tcx.emit_diag_node_span_lint( if is_internal { REFINING_IMPL_TRAIT_INTERNAL } else { REFINING_IMPL_TRAIT_REACHABLE }, tcx.local_def_id_to_hir_id(impl_opaque_def_id), use_bound_span, diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 5669b6793add7..9167116ca5717 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -213,12 +213,12 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::truncf128 | sym::type_id | sym::type_id_eq + | sym::type_id_vtable | sym::type_name | sym::type_of | sym::ub_checks | sym::va_copy | sym::variant_count - | sym::vtable_for | sym::wrapping_add | sym::wrapping_mul | sym::wrapping_sub @@ -323,6 +323,25 @@ pub(crate) fn check_intrinsic_type( let type_id = tcx.type_of(tcx.lang_items().type_id().unwrap()).no_bound_vars().unwrap(); (0, 0, vec![type_id, type_id], tcx.types.bool) } + sym::type_id_vtable => { + let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, span); + let dyn_metadata_adt_ref = tcx.adt_def(dyn_metadata); + let dyn_metadata_args = + tcx.mk_args(&[Ty::new_ptr(tcx, tcx.types.unit, ty::Mutability::Not).into()]); + let dyn_ty = Ty::new_adt(tcx, dyn_metadata_adt_ref, dyn_metadata_args); + + let option_did = tcx.require_lang_item(LangItem::Option, span); + let option_adt_ref = tcx.adt_def(option_did); + let option_args = tcx.mk_args(&[dyn_ty.into()]); + let ret_ty = Ty::new_adt(tcx, option_adt_ref, option_args); + + ( + 0, + 0, + vec![tcx.type_of(tcx.lang_items().type_id().unwrap()).no_bound_vars().unwrap(); 2], + ret_ty, + ) + } sym::type_of => ( 0, 0, @@ -675,20 +694,6 @@ pub(crate) fn check_intrinsic_type( (0, 0, vec![Ty::new_imm_ptr(tcx, tcx.types.unit)], tcx.types.usize) } - sym::vtable_for => { - let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, span); - let dyn_metadata_adt_ref = tcx.adt_def(dyn_metadata); - let dyn_metadata_args = tcx.mk_args(&[param(1).into()]); - let dyn_ty = Ty::new_adt(tcx, dyn_metadata_adt_ref, dyn_metadata_args); - - let option_did = tcx.require_lang_item(LangItem::Option, span); - let option_adt_ref = tcx.adt_def(option_did); - let option_args = tcx.mk_args(&[dyn_ty.into()]); - let ret_ty = Ty::new_adt(tcx, option_adt_ref, option_args); - - (2, 0, vec![], ret_ty) - } - // This type check is not particularly useful, but the `where` bounds // on the definition in `core` do the heavy lifting for checking it. sym::aggregate_raw_ptr => (3, 0, vec![param(1), param(2)], param(0)), diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index ed951015a4f19..5a4d1794623f1 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -14,7 +14,7 @@ use rustc_hir::{AmbigArg, ItemKind, find_attr}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{self, InferCtxt, SubregionOrigin, TyCtxtInferExt}; use rustc_lint_defs::builtin::SHADOWING_SUPERTRAIT_ITEMS; -use rustc_macros::LintDiagnostic; +use rustc_macros::Diagnostic; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::traits::solve::NoSolution; use rustc_middle::ty::trait_def::TraitSpecializationKind; @@ -797,7 +797,7 @@ fn lint_item_shadowing_supertrait_item<'tcx>(tcx: TyCtxt<'tcx>, trait_item_def_i errors::SupertraitItemShadowee::Several { traits: traits.into(), spans: spans.into() } }; - tcx.emit_node_span_lint( + tcx.emit_diag_node_span_lint( SHADOWING_SUPERTRAIT_ITEMS, tcx.local_def_id_to_hir_id(trait_item_def_id), tcx.def_span(trait_item_def_id), @@ -2458,7 +2458,7 @@ fn lint_redundant_lifetimes<'tcx>( && outlives_env.free_region_map().sub_free_regions(tcx, victim, candidate) { shadowed.insert(victim); - tcx.emit_node_span_lint( + tcx.emit_diag_node_span_lint( rustc_lint_defs::builtin::REDUNDANT_LIFETIMES, tcx.local_def_id_to_hir_id(def_id.expect_local()), tcx.def_span(def_id), @@ -2469,7 +2469,7 @@ fn lint_redundant_lifetimes<'tcx>( } } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("unnecessary lifetime parameter `{$victim}`")] #[note("you can use the `{$candidate}` lifetime directly, in place of `{$victim}`")] struct RedundantLifetimeArgsLint<'tcx> { diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index f1e138dbcb97a..b5e40058e7533 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -497,13 +497,13 @@ fn lint_uncovered_ty_params<'tcx>( let name = tcx.item_ident(param_def_id); match local_ty { - Some(local_type) => tcx.emit_node_span_lint( + Some(local_type) => tcx.emit_diag_node_span_lint( UNCOVERED_PARAM_IN_PROJECTION, hir_id, span, errors::TyParamFirstLocalLint { span, note: (), param: name, local_type }, ), - None => tcx.emit_node_span_lint( + None => tcx.emit_diag_node_span_lint( UNCOVERED_PARAM_IN_PROJECTION, hir_id, span, diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index be10d5ffad471..c91b67e763811 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -7,7 +7,7 @@ use rustc_errors::{ MultiSpan, listify, msg, }; use rustc_hir::limit::Limit; -use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; +use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::ty::{self, Ty}; use rustc_span::{Ident, Span, Symbol}; pub(crate) mod wrong_number_of_generic_args; @@ -888,7 +888,7 @@ pub(crate) enum ImplNotMarkedDefault { }, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("this item cannot be used as its where bounds are not satisfied for the `Self` type")] pub(crate) struct UselessImplItem; @@ -1114,7 +1114,7 @@ pub(crate) enum LateBoundInApit { }, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("unnecessary associated type bound for dyn-incompatible associated type")] #[note( "this associated type has a `where Self: Sized` bound, and while the associated type can be specified, it cannot be used because trait objects are never `Sized`" @@ -1124,7 +1124,7 @@ pub(crate) struct UnusedAssociatedTypeBounds { pub span: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("impl trait in impl method signature does not match trait method signature")] #[note( "add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate" @@ -1149,7 +1149,7 @@ pub(crate) struct ReturnPositionImplTraitInTraitRefined { pub return_ty: String, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("impl trait in impl method captures fewer lifetimes than in trait")] #[note( "add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate" @@ -1467,7 +1467,7 @@ pub(crate) struct TyParamFirstLocal<'tcx> { pub local_type: Ty<'tcx>, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("type parameter `{$param}` must be covered by another type when it appears before the first local type (`{$local_type}`)", code = E0210)] #[note( "implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type" @@ -1499,7 +1499,7 @@ pub(crate) struct TyParamSome { pub param: Ident, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("type parameter `{$param}` must be used as the type parameter for some local type (e.g., `MyStruct<{$param}>`)", code = E0210)] #[note( "implementing a foreign trait is only possible if at least one of the types for which it is implemented is local" @@ -1805,7 +1805,7 @@ pub(crate) struct BadReturnTypeNotation { pub span: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("trait item `{$item}` from `{$subtrait}` shadows identically named item from supertrait")] pub(crate) struct SupertraitItemShadowing { pub item: Symbol, 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 7b8e09943df71..459d13e46e854 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 @@ -291,7 +291,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // FIXME(mgca): Ideally we would generalize the name of this lint to sth. like // `unused_associated_item_bindings` since this can now also trigger on *const* // projections / assoc *const* bindings. - tcx.emit_node_span_lint( + tcx.emit_diag_node_span_lint( UNUSED_ASSOCIATED_TYPE_BOUNDS, hir_id, span, diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index eaa87f1d4cbc6..af529386eee2a 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -687,7 +687,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { }; let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty); let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty); - fcx.tcx.emit_node_span_lint( + fcx.tcx.emit_diag_node_span_lint( lint, self.expr.hir_id, self.span, @@ -1125,7 +1125,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { }; let lint = errors::LossyProvenancePtr2Int { expr_ty, cast_ty, sugg }; - fcx.tcx.emit_node_span_lint( + fcx.tcx.emit_diag_node_span_lint( lint::builtin::LOSSY_PROVENANCE_CASTS, self.expr.hir_id, self.span, @@ -1141,7 +1141,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty); let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty); let lint = errors::LossyProvenanceInt2Ptr { expr_ty, cast_ty, sugg }; - fcx.tcx.emit_node_span_lint( + fcx.tcx.emit_diag_node_span_lint( lint::builtin::FUZZY_PROVENANCE_CASTS, self.expr.hir_id, self.span, diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 5c44836adcd01..8251669ea8d2a 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -11,7 +11,7 @@ use rustc_errors::{ }; use rustc_hir as hir; use rustc_hir::ExprKind; -use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; +use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::ty::{self, Ty}; use rustc_span::edition::{Edition, LATEST_STABLE_EDITION}; use rustc_span::source_map::Spanned; @@ -215,7 +215,7 @@ pub(crate) struct MissingParenthesesInRange<'tcx> { pub add_missing_parentheses: Option, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] pub(crate) enum NeverTypeFallbackFlowingIntoUnsafe { #[help("specify the type explicitly")] #[diag("never type fallback affects this call to an `unsafe` function")] @@ -249,7 +249,7 @@ pub(crate) enum NeverTypeFallbackFlowingIntoUnsafe { }, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[help("specify the types explicitly")] #[diag("this function depends on never type fallback being `()`")] pub(crate) struct DependencyOnUnitNeverTypeFallback<'tcx> { @@ -372,7 +372,7 @@ impl Subdiagnostic for TypeMismatchFruTypo { } } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("strict provenance disallows casting integer `{$expr_ty}` to pointer `{$cast_ty}`")] #[help( "if you can't comply with strict provenance and don't have a pointer with the correct provenance you can use `std::ptr::with_exposed_provenance()` instead" @@ -411,7 +411,7 @@ pub(crate) struct LossyProvenanceInt2PtrSuggestion { pub hi: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag( "under strict provenance it is considered bad style to cast pointer `{$expr_ty}` to integer `{$cast_ty}`" )] @@ -769,7 +769,7 @@ pub(crate) struct SuggestPtrNullMut { pub span: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag( "trivial {$numeric -> [true] numeric cast @@ -1109,7 +1109,7 @@ pub(crate) struct InnerItem { pub span: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("can't reference `Self` constructor from outer item")] pub(crate) struct SelfCtorFromOuterItemLint { #[label( @@ -1214,7 +1214,7 @@ pub(crate) struct ReplaceCommaWithSemicolon { pub descr: &'static str, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("trait item `{$item}` from `{$subtrait}` shadows identically named item from supertrait")] pub(crate) struct SupertraitItemShadowing { pub item: Symbol, diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs index c10e7f3bfb8b9..79fdfd3563676 100644 --- a/compiler/rustc_hir_typeck/src/fallback.rs +++ b/compiler/rustc_hir_typeck/src/fallback.rs @@ -238,7 +238,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { let sugg = self.try_to_suggest_annotations(&[root_vid], coercion_graph); for (hir_id, span, reason) in affected_unsafe_infer_vars { - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( lint::builtin::NEVER_TYPE_FALLBACK_FLOWING_INTO_UNSAFE, hir_id, span, @@ -304,7 +304,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { { self.adjust_fulfillment_error_for_expr_obligation(never_error); let sugg = self.try_to_suggest_annotations(diverging_vids, coercions); - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( lint::builtin::DEPENDENCY_ON_UNIT_NEVER_TYPE_FALLBACK, self.tcx.local_def_id_to_hir_id(self.body_id), self.tcx.def_span(self.body_id), diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 1931222bba30e..81523cdf633d5 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1145,7 +1145,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); return (Ty::new_error(self.tcx, guar), res); } else { - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( SELF_CONSTRUCTOR_FROM_OUTER_ITEM, hir_id, path_span, diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 608bc7dffd9c0..6e5b05a8191fc 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -717,7 +717,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { SupertraitItemShadowee::Several { traits: traits.into(), spans: spans.into() } }; - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( RESOLVING_TO_ITEMS_SHADOWING_SUPERTRAIT_ITEMS, segment.hir_id, segment.ident.span, diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index c83de3b38eb5b..22636959f0db5 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1120,12 +1120,10 @@ declare_lint_pass!( ); impl<'tcx> LateLintPass<'tcx> for UnstableFeatures { - fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &hir::Attribute) { - if attr.has_name(sym::feature) - && let Some(items) = attr.meta_item_list() - { - for item in items { - cx.emit_span_lint(UNSTABLE_FEATURES, item.span(), BuiltinUnstableFeatures); + fn check_attributes(&mut self, cx: &LateContext<'_>, attrs: &[hir::Attribute]) { + if let Some(features) = find_attr!(attrs, Feature(features, _) => features) { + for feature in features { + cx.emit_span_lint(UNSTABLE_FEATURES, feature.span, BuiltinUnstableFeatures); } } } diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h index f6598f9faf522..0cbda23f384cc 100644 --- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h +++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h @@ -46,4 +46,8 @@ class RawRustStringOstream : public llvm::raw_ostream { } }; +struct LLVMRustBuffer { + std::string data; +}; + #endif // INCLUDED_RUSTC_LLVM_LLVMWRAPPER_H diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index f6b4d6cc15439..568335f7dcb51 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -87,19 +87,6 @@ extern "C" void LLVMRustTimeTraceProfilerFinish(const char *FileName) { timeTraceProfilerCleanup(); } -// This struct and various functions are sort of a hack right now, but the -// problem is that we've got in-memory LLVM modules after we generate and -// optimize all codegen-units for one compilation in rustc. To be compatible -// with the LTO support above we need to serialize the modules plus their -// ThinLTO summary into memory. -// -// This structure is basically an owned version of a serialize module, with -// a ThinLTO summary attached. -struct LLVMRustThinLTOBuffer { - std::string data; - std::string thin_link_data; -}; - extern "C" bool LLVMRustHasFeature(LLVMTargetMachineRef TM, const char *Feature) { TargetMachine *Target = unwrap(TM); @@ -566,11 +553,12 @@ extern "C" LLVMRustResult LLVMRustOptimize( LLVMModuleRef ModuleRef, LLVMTargetMachineRef TMRef, LLVMRustPassBuilderOptLevel OptLevelRust, LLVMRustOptStage OptStage, bool IsLinkerPluginLTO, bool NoPrepopulatePasses, bool VerifyIR, - bool LintIR, LLVMRustThinLTOBuffer **ThinLTOBufferRef, - bool EmitThinLTOSummary, bool MergeFunctions, bool UnrollLoops, - bool SLPVectorize, bool LoopVectorize, bool DisableSimplifyLibCalls, - bool EmitLifetimeMarkers, registerEnzymeAndPassPipelineFn EnzymePtr, - bool PrintBeforeEnzyme, bool PrintAfterEnzyme, bool PrintPasses, + bool LintIR, LLVMRustBuffer **ThinLTOBufferRef, + LLVMRustBuffer **ThinLTOSummaryBufferRef, bool MergeFunctions, + bool UnrollLoops, bool SLPVectorize, bool LoopVectorize, + bool DisableSimplifyLibCalls, bool EmitLifetimeMarkers, + registerEnzymeAndPassPipelineFn EnzymePtr, bool PrintBeforeEnzyme, + bool PrintAfterEnzyme, bool PrintPasses, LLVMRustSanitizerOptions *SanitizerOptions, const char *PGOGenPath, const char *PGOUsePath, bool InstrumentCoverage, const char *InstrProfileOutput, const char *PGOSampleUsePath, @@ -809,9 +797,10 @@ extern "C" LLVMRustResult LLVMRustOptimize( ModulePassManager MPM; bool NeedThinLTOBufferPasses = true; - auto ThinLTOBuffer = std::make_unique(); + auto ThinLTOBuffer = std::make_unique(); + auto ThinLTOSummaryBuffer = std::make_unique(); raw_string_ostream ThinLTODataOS(ThinLTOBuffer->data); - raw_string_ostream ThinLinkDataOS(ThinLTOBuffer->thin_link_data); + raw_string_ostream ThinLinkDataOS(ThinLTOSummaryBuffer->data); bool IsLTO = OptStage == LLVMRustOptStage::ThinLTO || OptStage == LLVMRustOptStage::FatLTO; if (!NoPrepopulatePasses) { @@ -836,8 +825,12 @@ extern "C" LLVMRustResult LLVMRustOptimize( // `ThinLTOPreLinkDefaultPipeline`. MPM.addPass(PB.buildThinLTOPreLinkDefaultPipeline(OptLevel)); MPM.addPass(ThinLTOBitcodeWriterPass( - ThinLTODataOS, EmitThinLTOSummary ? &ThinLinkDataOS : nullptr)); + ThinLTODataOS, + ThinLTOSummaryBufferRef ? &ThinLinkDataOS : nullptr)); *ThinLTOBufferRef = ThinLTOBuffer.release(); + if (ThinLTOSummaryBufferRef) { + *ThinLTOSummaryBufferRef = ThinLTOSummaryBuffer.release(); + } MPM.addPass(PB.buildModuleOptimizationPipeline( OptLevel, ThinOrFullLTOPhase::None)); MPM.addPass( @@ -893,11 +886,14 @@ extern "C" LLVMRustResult LLVMRustOptimize( // lto is requested. See PR #136840 for background information. if (OptStage != LLVMRustOptStage::PreLinkFatLTO) { MPM.addPass(ThinLTOBitcodeWriterPass( - ThinLTODataOS, EmitThinLTOSummary ? &ThinLinkDataOS : nullptr)); + ThinLTODataOS, ThinLTOSummaryBufferRef ? &ThinLinkDataOS : nullptr)); } else { MPM.addPass(BitcodeWriterPass(ThinLTODataOS)); } *ThinLTOBufferRef = ThinLTOBuffer.release(); + if (ThinLTOSummaryBufferRef) { + *ThinLTOSummaryBufferRef = ThinLTOSummaryBuffer.release(); + } } // now load "-enzyme" pass: @@ -1408,9 +1404,9 @@ extern "C" bool LLVMRustPrepareThinLTOImport(const LLVMRustThinLTOData *Data, return true; } -extern "C" LLVMRustThinLTOBuffer *LLVMRustThinLTOBufferCreate(LLVMModuleRef M, - bool is_thin) { - auto Ret = std::make_unique(); +extern "C" LLVMRustBuffer *LLVMRustModuleSerialize(LLVMModuleRef M, + bool is_thin) { + auto Ret = std::make_unique(); { auto OS = raw_string_ostream(Ret->data); { @@ -1436,30 +1432,6 @@ extern "C" LLVMRustThinLTOBuffer *LLVMRustThinLTOBufferCreate(LLVMModuleRef M, return Ret.release(); } -extern "C" void LLVMRustThinLTOBufferFree(LLVMRustThinLTOBuffer *Buffer) { - delete Buffer; -} - -extern "C" const void * -LLVMRustThinLTOBufferPtr(const LLVMRustThinLTOBuffer *Buffer) { - return Buffer->data.data(); -} - -extern "C" size_t -LLVMRustThinLTOBufferLen(const LLVMRustThinLTOBuffer *Buffer) { - return Buffer->data.length(); -} - -extern "C" const void * -LLVMRustThinLTOBufferThinLinkDataPtr(const LLVMRustThinLTOBuffer *Buffer) { - return Buffer->thin_link_data.data(); -} - -extern "C" size_t -LLVMRustThinLTOBufferThinLinkDataLen(const LLVMRustThinLTOBuffer *Buffer) { - return Buffer->thin_link_data.length(); -} - // This is what we used to parse upstream bitcode for actual ThinLTO // processing. We'll call this once per module optimized through ThinLTO, and // it'll be called concurrently on many threads. diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index f68f4e71520b3..eabc1c94f26e9 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1529,29 +1529,13 @@ extern "C" void LLVMRustSetDSOLocal(LLVMValueRef Global, bool is_dso_local) { unwrap(Global)->setDSOLocal(is_dso_local); } -struct LLVMRustModuleBuffer { - std::string data; -}; - -extern "C" LLVMRustModuleBuffer *LLVMRustModuleBufferCreate(LLVMModuleRef M) { - auto Ret = std::make_unique(); - { - auto OS = raw_string_ostream(Ret->data); - WriteBitcodeToFile(*unwrap(M), OS); - } - return Ret.release(); -} - -extern "C" void LLVMRustModuleBufferFree(LLVMRustModuleBuffer *Buffer) { - delete Buffer; -} +extern "C" void LLVMRustBufferFree(LLVMRustBuffer *Buffer) { delete Buffer; } -extern "C" const void * -LLVMRustModuleBufferPtr(const LLVMRustModuleBuffer *Buffer) { +extern "C" const void *LLVMRustBufferPtr(const LLVMRustBuffer *Buffer) { return Buffer->data.data(); } -extern "C" size_t LLVMRustModuleBufferLen(const LLVMRustModuleBuffer *Buffer) { +extern "C" size_t LLVMRustBufferLen(const LLVMRustBuffer *Buffer) { return Buffer->data.length(); } diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 4204855f199d4..28ca6f9fcac20 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -573,6 +573,20 @@ pub fn diag_lint_level<'a, D: Diagnostic<'a, ()> + 'a>( false }; + if disable_suggestions { + // If this is a future incompatible that is not an edition fixing lint + // it'll become a hard error, so we have to emit *something*. Also, + // if this lint occurs in the expansion of a macro from an external crate, + // allow individual lints to opt-out from being reported. + let incompatible = future_incompatible.is_some_and(|f| f.reason.edition().is_none()); + + if !incompatible && !lint.report_in_external_macro { + // Don't continue further, since we don't want to have + // `diag_span_note_once` called for a diagnostic that isn't emitted. + return; + } + } + let mut err: Diag<'_, ()> = if !skip { decorate(sess.dcx(), err_level) } else { @@ -597,20 +611,6 @@ pub fn diag_lint_level<'a, D: Diagnostic<'a, ()> + 'a>( // Any suggestions made here are likely to be incorrect, so anything we // emit shouldn't be automatically fixed by rustfix. err.disable_suggestions(); - - // If this is a future incompatible that is not an edition fixing lint - // it'll become a hard error, so we have to emit *something*. Also, - // if this lint occurs in the expansion of a macro from an external crate, - // allow individual lints to opt-out from being reported. - let incompatible = future_incompatible.is_some_and(|f| f.reason.edition().is_none()); - - if !incompatible && !lint.report_in_external_macro { - err.cancel(); - - // Don't continue further, since we don't want to have - // `diag_span_note_once` called for a diagnostic that isn't emitted. - return; - } } err.is_lint(lint.name_lower(), has_future_breakage); diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index e5fe01781e96d..487a3c9c4ea22 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -802,10 +802,10 @@ impl<'de, 'tcx> MirWriter<'de, 'tcx> { } } -impl Debug for Statement<'_> { +impl Debug for StatementKind<'_> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { use self::StatementKind::*; - match self.kind { + match *self { Assign(box (ref place, ref rv)) => write!(fmt, "{place:?} = {rv:?}"), FakeRead(box (ref cause, ref place)) => { write!(fmt, "FakeRead({cause:?}, {place:?})") @@ -844,6 +844,11 @@ impl Debug for Statement<'_> { } } } +impl Debug for Statement<'_> { + fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { + self.kind.fmt(fmt) + } +} impl Debug for StmtDebugInfo<'_> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { @@ -915,6 +920,11 @@ impl<'tcx> Debug for TerminatorKind<'tcx> { } } } +impl Debug for Terminator<'_> { + fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { + self.kind.fmt(fmt) + } +} impl<'tcx> TerminatorKind<'tcx> { /// Writes the "head" part of the terminator; that is, its name and the data it uses to pick the diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 35f67460f51c0..c3da2f0394852 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -306,7 +306,7 @@ pub enum FakeBorrowKind { /// Not all of these are allowed at every [`MirPhase`]. Check the documentation there to see which /// ones you do not have to worry about. The MIR validator will generally enforce such restrictions, /// causing an ICE if they are violated. -#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] +#[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] #[derive(TypeFoldable, TypeVisitable)] pub enum StatementKind<'tcx> { /// Assign statements roughly correspond to an assignment in Rust proper (`x = ...`) except diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 1e7729bd8d657..650c44aa41fbe 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -444,7 +444,7 @@ impl AssertKind { } } -#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] +#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub struct Terminator<'tcx> { pub source_info: SourceInfo, pub kind: TerminatorKind<'tcx>, diff --git a/compiler/rustc_middle/src/query/modifiers.rs b/compiler/rustc_middle/src/query/modifiers.rs index 81b9f0da6446c..44aaa6a3ce3d9 100644 --- a/compiler/rustc_middle/src/query/modifiers.rs +++ b/compiler/rustc_middle/src/query/modifiers.rs @@ -1,66 +1,67 @@ //! This contains documentation which is linked from query modifiers used in the `rustc_queries!` proc macro. +//! +//! The dummy items in this module are used to enable hover documentation for +//! modifier names in the query list, and to allow find-all-references to list +//! all queries that use a particular modifier. #![allow(unused, non_camel_case_types)] // FIXME: Update and clarify documentation for these modifiers. -/// # `desc` query modifier +// tidy-alphabetical-start +// +/// # `anon` query modifier /// -/// The description of the query. This modifier is required on every query. -pub struct desc; +/// Generate a dep node based on the dependencies of the query +pub(crate) struct anon; /// # `arena_cache` query modifier /// /// Use this type for the in-memory cache. -pub struct arena_cache; +pub(crate) struct arena_cache; /// # `cache_on_disk_if` query modifier /// /// Cache the query to disk if the `Block` returns true. -pub struct cache_on_disk_if; - -/// # `cycle_fatal` query modifier -/// -/// A cycle error for this query aborting the compilation with a fatal error. -pub struct cycle_fatal; +pub(crate) struct cache_on_disk_if; /// # `cycle_delay_bug` query modifier /// /// A cycle error results in a delay_bug call -pub struct cycle_delay_bug; +pub(crate) struct cycle_delay_bug; + +/// # `cycle_fatal` query modifier +/// +/// A cycle error for this query aborting the compilation with a fatal error. +pub(crate) struct cycle_fatal; /// # `cycle_stash` query modifier /// /// A cycle error results in a stashed cycle error that can be unstashed and canceled later -pub struct cycle_stash; +pub(crate) struct cycle_stash; -/// # `no_hash` query modifier +/// # `depth_limit` query modifier /// -/// Don't hash the result, instead just mark a query red if it runs -pub struct no_hash; +/// Whether the query has a call depth limit +pub(crate) struct depth_limit; -/// # `anon` query modifier +/// # `desc` query modifier /// -/// Generate a dep node based on the dependencies of the query -pub struct anon; +/// The description of the query. This modifier is required on every query. +pub(crate) struct desc; /// # `eval_always` query modifier /// /// Always evaluate the query, ignoring its dependencies -pub struct eval_always; - -/// # `depth_limit` query modifier -/// -/// Whether the query has a call depth limit -pub struct depth_limit; - -/// # `separate_provide_extern` query modifier -/// -/// Use a separate query provider for local and extern crates -pub struct separate_provide_extern; +pub(crate) struct eval_always; /// # `feedable` query modifier /// /// Generate a `feed` method to set the query's value from another query. -pub struct feedable; +pub(crate) struct feedable; + +/// # `no_hash` query modifier +/// +/// Don't hash the result, instead just mark a query red if it runs +pub(crate) struct no_hash; /// # `return_result_from_ensure_ok` query modifier /// @@ -74,4 +75,11 @@ pub struct feedable; /// /// Can only be applied to queries with a return value of /// `Result<_, ErrorGuaranteed>`. -pub struct return_result_from_ensure_ok; +pub(crate) struct return_result_from_ensure_ok; + +/// # `separate_provide_extern` query modifier +/// +/// Use a separate query provider for local and extern crates +pub(crate) struct separate_provide_extern; + +// tidy-alphabetical-end diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index b57de30201876..9eb41e57d4dce 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -29,7 +29,7 @@ use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{ self, DynSend, DynSync, FreezeReadGuard, Lock, RwLock, WorkerLocal, }; -use rustc_errors::{Applicability, Diag, DiagCtxtHandle, LintDiagnostic, MultiSpan}; +use rustc_errors::{Applicability, Diag, DiagCtxtHandle, Diagnostic, LintDiagnostic, MultiSpan}; use rustc_hir::def::DefKind; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::definitions::{DefPathData, Definitions, DisambiguatorState}; @@ -55,7 +55,7 @@ use crate::dep_graph::dep_node::make_metadata; use crate::dep_graph::{DepGraph, DepKindVTable, DepNodeIndex}; use crate::ich::StableHashingContext; use crate::infer::canonical::{CanonicalParamEnvCache, CanonicalVarKind}; -use crate::lint::lint_level; +use crate::lint::{diag_lint_level, lint_level}; use crate::metadata::ModChild; use crate::middle::codegen_fn_attrs::{CodegenFnAttrs, TargetFeature}; use crate::middle::resolve_bound_vars; @@ -2511,6 +2511,20 @@ impl<'tcx> TyCtxt<'tcx> { }) } + /// Emit a lint at `span` from a lint struct (some type that implements `Diagnostic`, + /// typically generated by `#[derive(Diagnostic)]`). + #[track_caller] + pub fn emit_diag_node_span_lint( + self, + lint: &'static Lint, + hir_id: HirId, + span: impl Into, + decorator: impl for<'a> Diagnostic<'a, ()>, + ) { + let level = self.lint_level_at_node(lint, hir_id); + diag_lint_level(self.sess, lint, level, Some(span.into()), decorator) + } + /// Emit a lint at the appropriate level for a hir node, with an associated span. /// /// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index dbd7809c2e651..c8ca7bfccc07c 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -24,7 +24,6 @@ use itertools::Itertools; use rustc_abi::{ExternAbi, FieldIdx}; use rustc_apfloat::Float; use rustc_apfloat::ieee::{Double, Half, Quad, Single}; -use rustc_ast::attr; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sorted_map::SortedIndexMultiMap; use rustc_errors::ErrorGuaranteed; @@ -41,7 +40,7 @@ use rustc_middle::thir::{self, ExprId, LocalVarId, Param, ParamId, PatKind, Thir use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt, TypeVisitableExt, TypingMode}; use rustc_middle::{bug, span_bug}; use rustc_session::lint; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{Span, Symbol}; use crate::builder::expr::as_place::PlaceBuilder; use crate::builder::scope::{DropKind, LintLevel}; @@ -751,11 +750,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { coroutine: Option>>, ) -> Builder<'a, 'tcx> { let tcx = infcx.tcx; - let attrs = tcx.hir_attrs(hir_id); // Some functions always have overflow checks enabled, // however, they may not get codegen'd, depending on // the settings for the crate they are codegened in. - let mut check_overflow = attr::contains_name(attrs, sym::rustc_inherit_overflow_checks); + let mut check_overflow = find_attr!(tcx.hir_attrs(hir_id), RustcInheritOverflowChecks); // Respect -C overflow-checks. check_overflow |= tcx.sess.overflow_checks(); // Constants always need overflow checks. diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 9af9398d78b96..af76ea183c476 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -253,6 +253,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::EiiForeignItem | AttributeKind::ExportName { .. } | AttributeKind::ExportStable + | AttributeKind::Feature(..) | AttributeKind::FfiConst(..) | AttributeKind::Fundamental | AttributeKind::Ignore { .. } @@ -325,6 +326,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::RustcHasIncoherentInherentImpls | AttributeKind::RustcHiddenTypeOfOpaques | AttributeKind::RustcIfThisChanged(..) + | AttributeKind::RustcInheritOverflowChecks | AttributeKind::RustcInsignificantDtor | AttributeKind::RustcIntrinsic | AttributeKind::RustcIntrinsicConstStableIndirect @@ -404,7 +406,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::rustc_on_unimplemented | sym::rustc_layout | sym::rustc_autodiff - | sym::rustc_inherit_overflow_checks // crate-level attrs, are checked below | sym::feature | sym::register_tool, @@ -1564,75 +1565,82 @@ impl<'tcx> CheckAttrVisitor<'tcx> { fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute, style: Option) { // Warn on useless empty attributes. // FIXME(jdonszelmann): this lint should be moved to attribute parsing, see `AcceptContext::warn_empty_attribute` - let note = if attr.has_any_name(&[ - sym::allow, - sym::expect, - sym::warn, - sym::deny, - sym::forbid, - sym::feature, - ]) && attr.meta_item_list().is_some_and(|list| list.is_empty()) - { - errors::UnusedNote::EmptyList { name: attr.name().unwrap() } - } else if attr.has_any_name(&[sym::allow, sym::warn, sym::deny, sym::forbid, sym::expect]) - && let Some(meta) = attr.meta_item_list() - && let [meta] = meta.as_slice() - && let Some(item) = meta.meta_item() - && let MetaItemKind::NameValue(_) = &item.kind - && item.path == sym::reason - { - errors::UnusedNote::NoLints { name: attr.name().unwrap() } - } else if attr.has_any_name(&[sym::allow, sym::warn, sym::deny, sym::forbid, sym::expect]) - && let Some(meta) = attr.meta_item_list() - && meta.iter().any(|meta| { - meta.meta_item().map_or(false, |item| item.path == sym::linker_messages) - }) - { - if hir_id != CRATE_HIR_ID { - match style { - Some(ast::AttrStyle::Outer) => { - let attr_span = attr.span(); - let bang_position = self - .tcx - .sess - .source_map() - .span_until_char(attr_span, '[') - .shrink_to_hi(); - - self.tcx.emit_node_span_lint( + let note = + if attr.has_any_name(&[sym::allow, sym::expect, sym::warn, sym::deny, sym::forbid]) + && attr.meta_item_list().is_some_and(|list| list.is_empty()) + { + errors::UnusedNote::EmptyList { name: attr.name().unwrap() } + } else if attr.has_any_name(&[ + sym::allow, + sym::warn, + sym::deny, + sym::forbid, + sym::expect, + ]) && let Some(meta) = attr.meta_item_list() + && let [meta] = meta.as_slice() + && let Some(item) = meta.meta_item() + && let MetaItemKind::NameValue(_) = &item.kind + && item.path == sym::reason + { + errors::UnusedNote::NoLints { name: attr.name().unwrap() } + } else if attr.has_any_name(&[ + sym::allow, + sym::warn, + sym::deny, + sym::forbid, + sym::expect, + ]) && let Some(meta) = attr.meta_item_list() + && meta.iter().any(|meta| { + meta.meta_item().map_or(false, |item| item.path == sym::linker_messages) + }) + { + if hir_id != CRATE_HIR_ID { + match style { + Some(ast::AttrStyle::Outer) => { + let attr_span = attr.span(); + let bang_position = self + .tcx + .sess + .source_map() + .span_until_char(attr_span, '[') + .shrink_to_hi(); + + self.tcx.emit_node_span_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr_span, + errors::OuterCrateLevelAttr { + suggestion: errors::OuterCrateLevelAttrSuggestion { + bang_position, + }, + }, + ) + } + Some(ast::AttrStyle::Inner) | None => self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr_span, - errors::OuterCrateLevelAttr { - suggestion: errors::OuterCrateLevelAttrSuggestion { bang_position }, - }, - ) - } - Some(ast::AttrStyle::Inner) | None => self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr.span(), - errors::InnerCrateLevelAttr, - ), - }; - return; - } else { - let never_needs_link = self - .tcx - .crate_types() - .iter() - .all(|kind| matches!(kind, CrateType::Rlib | CrateType::StaticLib)); - if never_needs_link { - errors::UnusedNote::LinkerMessagesBinaryCrateOnly - } else { + attr.span(), + errors::InnerCrateLevelAttr, + ), + }; return; + } else { + let never_needs_link = self + .tcx + .crate_types() + .iter() + .all(|kind| matches!(kind, CrateType::Rlib | CrateType::StaticLib)); + if never_needs_link { + errors::UnusedNote::LinkerMessagesBinaryCrateOnly + } else { + return; + } } - } - } else if attr.has_name(sym::default_method_body_is_const) { - errors::UnusedNote::DefaultMethodBodyConst - } else { - return; - }; + } else if attr.has_name(sym::default_method_body_is_const) { + errors::UnusedNote::DefaultMethodBodyConst + } else { + return; + }; self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index c4a0cde2837a0..9fbc73618ce80 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -629,6 +629,35 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { // `true` for `...::{self [as target]}` imports, `false` otherwise. let type_ns_only = nested && source.ident.name == kw::SelfLower; + if source.ident.name == kw::SelfLower + && let Some(parent) = module_path.pop() + { + // Suggest `use prefix::{self};` for `use prefix::self;` + if !type_ns_only + && (parent.ident.name != kw::PathRoot + || self.r.path_root_is_crate_root(parent.ident)) + { + let span_with_rename = match rename { + Some(rename) => source.ident.span.to(rename.span), + None => source.ident.span, + }; + + self.r.report_error( + parent.ident.span.shrink_to_hi().to(source.ident.span), + ResolutionError::SelfImportsOnlyAllowedWithin { + root: parent.ident.name == kw::PathRoot, + span_with_rename, + }, + ); + } + + let self_span = source.ident.span; + source = parent; + if rename.is_none() { + ident = Ident::new(source.ident.name, self_span); + } + } + match source.ident.name { kw::DollarCrate => { if !module_path.is_empty() { @@ -664,45 +693,14 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { return; } } - kw::SelfLower => { - if let Some(parent) = module_path.pop() { - // Suggest `use prefix::{self};` for `use prefix::self;` - if !type_ns_only - && (parent.ident.name != kw::PathRoot - || self.r.path_root_is_crate_root(parent.ident)) - { - let span_with_rename = match rename { - Some(rename) => source.ident.span.to(rename.span), - None => source.ident.span, - }; - - self.r.report_error( - parent.ident.span.shrink_to_hi().to(source.ident.span), - ResolutionError::SelfImportsOnlyAllowedWithin { - root: parent.ident.name == kw::PathRoot, - span_with_rename, - }, - ); - } - - let self_span = source.ident.span; - source = parent; - if rename.is_none() { - ident = Ident::new(source.ident.name, self_span); - } - } + // Deny `use ::{self};` after edition 2015 + kw::PathRoot if !self.r.path_root_is_crate_root(source.ident) => { + self.r.dcx().span_err(use_tree.span, "extern prelude cannot be imported"); + return; } _ => {} } - // Deny `use ::{self};` after edition 2015 - if source.ident.name == kw::PathRoot - && !self.r.path_root_is_crate_root(source.ident) - { - self.r.dcx().span_err(use_tree.span, "extern prelude cannot be imported"); - return; - } - // Deny importing path-kw without renaming if rename.is_none() && ident.is_path_segment_keyword() { let ident = use_tree.ident(); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 9e16ee115212e..f87189b4de42c 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2054,6 +2054,7 @@ symbols! { type_changing_struct_update, type_id, type_id_eq, + type_id_vtable, type_info, type_ir, type_ir_infer_ctxt_like, @@ -2206,7 +2207,6 @@ symbols! { vsreg, vsx, vtable_align, - vtable_for, vtable_size, warn, wasip2, diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 42f332f7d8ba8..71a529400511c 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -86,7 +86,10 @@ #![stable(feature = "rust1", since = "1.0.0")] -use crate::{fmt, hash, intrinsics, ptr}; +use crate::intrinsics::{self, type_id_vtable}; +use crate::mem::transmute; +use crate::mem::type_info::{TraitImpl, TypeKind}; +use crate::{fmt, hash, ptr}; /////////////////////////////////////////////////////////////////////////////// // Any trait @@ -788,6 +791,67 @@ impl TypeId { const { intrinsics::type_id::() } } + /// Checks if the [TypeId] implements the trait. If it does it returns [TraitImpl] which can be used to build a fat pointer. + /// It can only be called at compile time. `self` must be the [TypeId] of a sized type or None will be returned. + /// + /// # Examples + /// + /// ``` + /// #![feature(type_info)] + /// use std::any::{TypeId}; + /// + /// pub trait Blah {} + /// impl Blah for u8 {} + /// + /// assert!(const { TypeId::of::().trait_info_of::() }.is_some()); + /// assert!(const { TypeId::of::().trait_info_of::() }.is_none()); + /// ``` + #[unstable(feature = "type_info", issue = "146922")] + #[rustc_const_unstable(feature = "type_info", issue = "146922")] + pub const fn trait_info_of< + T: ptr::Pointee> + ?Sized + 'static, + >( + self, + ) -> Option> { + // SAFETY: The vtable was obtained for `T`, so it is guaranteed to be `DynMetadata`. + // The intrinsic can't infer this because it is designed to work with arbitrary TypeIds. + unsafe { transmute(self.trait_info_of_trait_type_id(const { TypeId::of::() })) } + } + + /// Checks if the [TypeId] implements the trait of `trait_represented_by_type_id`. If it does it returns [TraitImpl] which can be used to build a fat pointer. + /// It can only be called at compile time. `self` must be the [TypeId] of a sized type or None will be returned. + /// + /// # Examples + /// + /// ``` + /// #![feature(type_info)] + /// use std::any::{TypeId}; + /// + /// pub trait Blah {} + /// impl Blah for u8 {} + /// + /// assert!(const { TypeId::of::().trait_info_of_trait_type_id(TypeId::of::()) }.is_some()); + /// assert!(const { TypeId::of::().trait_info_of_trait_type_id(TypeId::of::()) }.is_none()); + /// ``` + #[unstable(feature = "type_info", issue = "146922")] + #[rustc_const_unstable(feature = "type_info", issue = "146922")] + pub const fn trait_info_of_trait_type_id( + self, + trait_represented_by_type_id: TypeId, + ) -> Option> { + if self.info().size.is_none() { + return None; + } + + if matches!(trait_represented_by_type_id.info().kind, TypeKind::DynTrait(_)) + && let Some(vtable) = type_id_vtable(self, trait_represented_by_type_id) + { + Some(TraitImpl { vtable }) + } else { + None + } + } + fn as_u128(self) -> u128 { let mut bytes = [0; 16]; @@ -948,7 +1012,8 @@ pub const fn try_as_dyn< >( t: &T, ) -> Option<&U> { - let vtable: Option> = const { intrinsics::vtable_for::() }; + let vtable: Option> = + const { TypeId::of::().trait_info_of::().as_ref().map(TraitImpl::get_vtable) }; match vtable { Some(dyn_metadata) => { let pointer = ptr::from_raw_parts(t, dyn_metadata); @@ -1001,7 +1066,8 @@ pub const fn try_as_dyn_mut< >( t: &mut T, ) -> Option<&mut U> { - let vtable: Option> = const { intrinsics::vtable_for::() }; + let vtable: Option> = + const { TypeId::of::().trait_info_of::().as_ref().map(TraitImpl::get_vtable) }; match vtable { Some(dyn_metadata) => { let pointer = ptr::from_raw_parts_mut(t, dyn_metadata); diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 9d5f49c88295a..95b531994d92a 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -2751,18 +2751,6 @@ pub unsafe fn vtable_size(ptr: *const ()) -> usize; #[rustc_intrinsic] pub unsafe fn vtable_align(ptr: *const ()) -> usize; -/// The intrinsic returns the `U` vtable for `T` if `T` can be coerced to the trait object type `U`. -/// -/// # Compile-time failures -/// Determining whether `T` can be coerced to the trait object type `U` requires trait resolution by the compiler. -/// In some cases, that resolution can exceed the recursion limit, -/// and compilation will fail instead of this function returning `None`. -#[rustc_nounwind] -#[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_intrinsic] -pub const fn vtable_for> + ?Sized>() --> Option>; - /// The size of a type in bytes. /// /// Note that, unlike most intrinsics, this is safe to call; @@ -2864,6 +2852,20 @@ pub const unsafe fn size_of_val(ptr: *const T) -> usize; #[rustc_intrinsic_const_stable_indirect] pub const unsafe fn align_of_val(ptr: *const T) -> usize; +#[rustc_intrinsic] +#[unstable(feature = "core_intrinsics", issue = "none")] +/// Check if a type represented by a `TypeId` implements a trait represented by a `TypeId`. +/// It can only be called at compile time, the backends do +/// not implement it. If it implements the trait the dyn metadata gets returned for vtable access. +pub const fn type_id_vtable( + _id: crate::any::TypeId, + _trait: crate::any::TypeId, +) -> Option> { + panic!( + "`TypeId::trait_info_of` and `trait_info_of_trait_type_id` can only be called at compile-time" + ) +} + /// Compute the type information of a concrete type. /// It can only be called at compile time, the backends do /// not implement it. diff --git a/library/core/src/mem/type_info.rs b/library/core/src/mem/type_info.rs index 740055563d2d8..e4d47dedb8606 100644 --- a/library/core/src/mem/type_info.rs +++ b/library/core/src/mem/type_info.rs @@ -3,6 +3,8 @@ use crate::any::TypeId; use crate::intrinsics::{type_id, type_of}; +use crate::marker::PointeeSized; +use crate::ptr::DynMetadata; /// Compile-time type information. #[derive(Debug)] @@ -16,6 +18,21 @@ pub struct Type { pub size: Option, } +/// Info of a trait implementation, you can retrieve the vtable with [Self::get_vtable] +#[derive(Debug, PartialEq, Eq)] +#[unstable(feature = "type_info", issue = "146922")] +#[non_exhaustive] +pub struct TraitImpl { + pub(crate) vtable: DynMetadata, +} + +impl TraitImpl { + /// Gets the raw vtable for type reflection mapping + pub const fn get_vtable(&self) -> DynMetadata { + self.vtable + } +} + impl TypeId { /// Compute the type information of a concrete type. /// It can only be called at compile time. diff --git a/library/coretests/tests/intrinsics.rs b/library/coretests/tests/intrinsics.rs index c6d841b8383a8..e562f49b0a2fc 100644 --- a/library/coretests/tests/intrinsics.rs +++ b/library/coretests/tests/intrinsics.rs @@ -1,6 +1,7 @@ use core::any::TypeId; -use core::intrinsics::{assume, vtable_for}; +use core::intrinsics::assume; use std::fmt::Debug; +use std::intrinsics::type_id_vtable; use std::option::Option; use std::ptr::DynMetadata; @@ -198,15 +199,17 @@ fn carrying_mul_add_fallback_i128() { } #[test] -fn test_vtable_for() { +fn test_type_id_vtable() { #[derive(Debug)] struct A {} struct B {} - const A_VTABLE: Option> = vtable_for::(); + const A_VTABLE: Option> = + type_id_vtable(TypeId::of::(), TypeId::of::()); assert!(A_VTABLE.is_some()); - const B_VTABLE: Option> = vtable_for::(); + const B_VTABLE: Option> = + type_id_vtable(TypeId::of::(), TypeId::of::()); assert!(B_VTABLE.is_none()); } diff --git a/library/coretests/tests/mem.rs b/library/coretests/tests/mem.rs index 236c02d2a243a..b95e6e13063f5 100644 --- a/library/coretests/tests/mem.rs +++ b/library/coretests/tests/mem.rs @@ -1,4 +1,5 @@ mod fn_ptr; +mod trait_info_of; mod type_info; use core::mem::*; diff --git a/library/coretests/tests/mem/trait_info_of.rs b/library/coretests/tests/mem/trait_info_of.rs new file mode 100644 index 0000000000000..c723a96095815 --- /dev/null +++ b/library/coretests/tests/mem/trait_info_of.rs @@ -0,0 +1,70 @@ +use std::any::TypeId; +use std::ptr::DynMetadata; + +struct Garlic(i32); +trait Blah { + fn get_truth(&self) -> i32; +} +impl Blah for Garlic { + fn get_truth(&self) -> i32 { + self.0 * 21 + } +} + +#[test] +fn test_implements_trait() { + const { + assert!(TypeId::of::().trait_info_of::().is_some()); + assert!(TypeId::of::().trait_info_of::().is_some()); + assert!(TypeId::of::<*const Box>().trait_info_of::().is_none()); + assert!(TypeId::of::().trait_info_of_trait_type_id(TypeId::of::()).is_none()); + } +} + +#[test] +fn test_dyn_creation() { + let garlic = Garlic(2); + unsafe { + assert_eq!( + std::ptr::from_raw_parts::( + &raw const garlic, + const { TypeId::of::().trait_info_of::() }.unwrap().get_vtable() + ) + .as_ref() + .unwrap() + .get_truth(), + 42 + ); + } + + assert_eq!( + const { + TypeId::of::() + .trait_info_of_trait_type_id(TypeId::of::()) + .unwrap() + }.get_vtable(), + unsafe { + crate::mem::transmute::<_, DynMetadata<*const ()>>( + const { + TypeId::of::().trait_info_of::() + }.unwrap().get_vtable(), + ) + } + ); +} + +#[test] +fn test_incorrect_use() { + assert_eq!( + const { TypeId::of::().trait_info_of_trait_type_id(TypeId::of::()) }, + None + ); +} + +trait DstTrait {} +impl DstTrait for [i32] {} + +#[test] +fn dst_ice() { + assert!(const { TypeId::of::<[i32]>().trait_info_of::() }.is_none()); +} diff --git a/src/bootstrap/defaults/bootstrap.compiler.toml b/src/bootstrap/defaults/bootstrap.compiler.toml index 9dcb20ed48323..10fa0b3aeb591 100644 --- a/src/bootstrap/defaults/bootstrap.compiler.toml +++ b/src/bootstrap/defaults/bootstrap.compiler.toml @@ -23,7 +23,7 @@ lto = "off" frame-pointers = true # Compiler contributors often want to build rustc even without any changes to # e.g. check that it builds locally and check the baseline behavior of a -# compiler built from latest `master` commit. +# compiler built from latest `main` commit. download-rustc = false [llvm] diff --git a/src/bootstrap/defaults/bootstrap.dist.toml b/src/bootstrap/defaults/bootstrap.dist.toml index bb0592ce947ab..cce3f068aabcd 100644 --- a/src/bootstrap/defaults/bootstrap.dist.toml +++ b/src/bootstrap/defaults/bootstrap.dist.toml @@ -24,6 +24,8 @@ channel = "auto-detect" download-rustc = false # Build the llvm-bitcode-linker llvm-bitcode-linker = true +# Required to make builds reproducible. +remap-debuginfo = true [dist] # Use better compression when preparing tarballs. diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 325f54d78a505..a918ae929d2e0 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -953,13 +953,6 @@ impl Step for Rustc { cargo.rustdocflag("--extern-html-root-url"); cargo.rustdocflag("ena=https://docs.rs/ena/latest/"); - // Point std library crate links to local docs for offline usage. - for krate in STD_PUBLIC_CRATES { - cargo.rustdocflag("--extern-html-root-url"); - cargo.rustdocflag(&format!("{krate}=../")); - } - cargo.rustdocflag("--extern-html-root-takes-precedence"); - let mut to_open = None; let out_dir = builder.stage_out(build_compiler, Mode::Rustc).join(target).join("doc"); diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index f826ccd31e040..0c607cb6ba6f3 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -23,7 +23,7 @@ use crate::core::config::{Config, TargetSelection}; use crate::utils::build_stamp::{BuildStamp, generate_smart_stamp_hash}; use crate::utils::exec::command; use crate::utils::helpers::{ - self, exe, get_clang_cl_resource_dir, t, unhashed_basename, up_to_date, + self, exe, get_clang_cl_resource_dir, libdir, t, unhashed_basename, up_to_date, }; use crate::{CLang, GitRepo, Kind, trace}; @@ -561,7 +561,6 @@ impl Step for Llvm { } }; - // FIXME(ZuseZ4): Do we need that for Enzyme too? // When building LLVM with LLVM_LINK_LLVM_DYLIB for macOS, an unversioned // libLLVM.dylib will be built. However, llvm-config will still look // for a versioned path like libLLVM-14.dylib. Manually create a symbolic @@ -1167,7 +1166,7 @@ impl Step for Enzyme { let llvm_version_major = llvm::get_llvm_version_major(builder, &host_llvm_config); let lib_ext = std::env::consts::DLL_EXTENSION; let libenzyme = format!("libEnzyme-{llvm_version_major}"); - let build_dir = out_dir.join("lib"); + let build_dir = out_dir.join(libdir(target)); let dylib = build_dir.join(&libenzyme).with_extension(lib_ext); trace!("checking build stamp to see if we need to rebuild enzyme artifacts"); @@ -1205,7 +1204,16 @@ impl Step for Enzyme { // hard to spot more relevant issues. let mut cflags = CcFlags::default(); cflags.push_all("-Wno-deprecated"); - configure_cmake(builder, target, &mut cfg, true, LdFlags::default(), cflags, &[]); + + // Logic copied from `configure_llvm` + // ThinLTO is only available when building with LLVM, enabling LLD is required. + // Apple's linker ld64 supports ThinLTO out of the box though, so don't use LLD on Darwin. + let mut ldflags = LdFlags::default(); + if builder.config.llvm_thin_lto && !target.contains("apple") { + ldflags.push_all("-fuse-ld=lld"); + } + + configure_cmake(builder, target, &mut cfg, true, ldflags, cflags, &[]); // Re-use the same flags as llvm to control the level of debug information // generated by Enzyme. diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index f0fe1c03e7e14..71353397b207a 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -3416,6 +3416,8 @@ fn distcheck_plain_source_tarball(builder: &Builder<'_>, plain_src_dir: &Path) { command("./configure") .arg("--set") .arg("rust.omit-git-hash=false") + .arg("--set") + .arg("rust.remap-debuginfo=false") .args(&configure_args) .arg("--enable-vendor") .current_dir(plain_src_dir) diff --git a/src/ci/docker/host-aarch64/dist-aarch64-linux/Dockerfile b/src/ci/docker/host-aarch64/dist-aarch64-linux/Dockerfile index 3abca36fe70db..9691d4b099b3b 100644 --- a/src/ci/docker/host-aarch64/dist-aarch64-linux/Dockerfile +++ b/src/ci/docker/host-aarch64/dist-aarch64-linux/Dockerfile @@ -97,7 +97,7 @@ ENV RUST_CONFIGURE_ARGS \ ENV SCRIPT python3 ../x.py build --set rust.debug=true opt-dist && \ ./build/$HOSTS/stage1-tools-bin/opt-dist linux-ci -- python3 ../x.py dist \ - --host $HOSTS --target $HOSTS --include-default-paths build-manifest bootstrap + --host $HOSTS --target $HOSTS --include-default-paths build-manifest bootstrap enzyme ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=clang ENV LIBCURL_NO_PKG_CONFIG 1 diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh index c78b76a53f44c..46d34cd001a95 100755 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh @@ -9,6 +9,7 @@ python3 ../x.py build --set rust.debug=true opt-dist --include-default-paths \ build-manifest \ bootstrap \ + enzyme \ rustc_codegen_gcc # Use GCC for building GCC components, as it seems to behave badly when built with Clang diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 88b6855784979..c06c85513856b 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -504,7 +504,7 @@ auto: - name: dist-aarch64-apple env: SCRIPT: >- - ./x.py dist bootstrap + ./x.py dist bootstrap enzyme --include-default-paths --host=aarch64-apple-darwin --target=aarch64-apple-darwin @@ -513,6 +513,7 @@ auto: --enable-sanitizers --enable-profiler --set rust.jemalloc + --set llvm.link-shared=true --set rust.lto=thin --set rust.codegen-units=1 # Aarch64 tooling only needs to support macOS 11.0 and up as nothing else @@ -706,7 +707,7 @@ auto: # i686 has no dedicated job, build it here because this job is fast - name: dist-aarch64-llvm-mingw env: - SCRIPT: python x.py dist bootstrap --include-default-paths + SCRIPT: python x.py dist bootstrap enzyme --include-default-paths RUST_CONFIGURE_ARGS: >- --build=aarch64-pc-windows-gnullvm --target=aarch64-pc-windows-gnullvm,i686-pc-windows-gnullvm @@ -720,7 +721,7 @@ auto: - name: dist-x86_64-llvm-mingw env: - SCRIPT: python x.py dist bootstrap --include-default-paths + SCRIPT: python x.py dist bootstrap enzyme --include-default-paths RUST_CONFIGURE_ARGS: >- --build=x86_64-pc-windows-gnullvm --enable-full-tools diff --git a/src/ci/run.sh b/src/ci/run.sh index b486f0525f40d..215292965e65d 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -116,7 +116,6 @@ if [ "$DEPLOY$DEPLOY_ALT" = "1" ]; then else RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-llvm-static-stdcpp" fi - RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.remap-debuginfo" if [ "$DEPLOY_ALT" != "" ] && isLinux; then RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --debuginfo-level=2" @@ -139,6 +138,8 @@ if [ "$DEPLOY$DEPLOY_ALT" = "1" ]; then RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-debug-assertions" fi else + RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.remap-debuginfo=false" + # We almost always want debug assertions enabled, but sometimes this takes too # long for too little benefit, so we just turn them off. if [ "$NO_DEBUG_ASSERTIONS" = "" ]; then diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 5d6909f0bb97f..556d383a0e9fb 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -2343,9 +2343,10 @@ fn render_impl_summary( if let Some(doc) = doc { if impl_is_empty { w.write_str( - "
\ -
This impl block contains no items.
\ -
", + "\ +
\ +
This impl block contains no public items.
\ +
", )?; } write!(w, "
{doc}
")?; diff --git a/src/tools/rust-analyzer/.github/workflows/ci.yaml b/src/tools/rust-analyzer/.github/workflows/ci.yaml index ca7d3058d8f0b..04de6d11e3ebf 100644 --- a/src/tools/rust-analyzer/.github/workflows/ci.yaml +++ b/src/tools/rust-analyzer/.github/workflows/ci.yaml @@ -50,7 +50,7 @@ jobs: ref: ${{ github.event.pull_request.head.sha }} - name: Install rustup-toolchain-install-master - run: cargo install rustup-toolchain-install-master@1.6.0 + run: cargo install rustup-toolchain-install-master@1.11.0 # Install a pinned rustc commit to avoid surprises - name: Install Rust toolchain @@ -226,7 +226,12 @@ jobs: strategy: matrix: - target: [powerpc-unknown-linux-gnu, x86_64-unknown-linux-musl, wasm32-unknown-unknown] + target: + [ + powerpc-unknown-linux-gnu, + x86_64-unknown-linux-musl, + wasm32-unknown-unknown, + ] include: # The rust-analyzer binary is not expected to compile on WASM, but the IDE # crate should @@ -330,7 +335,18 @@ jobs: run: typos conclusion: - needs: [rust, rust-cross, typescript, typo-check, proc-macro-srv, miri, rustfmt, clippy, analysis-stats] + needs: + [ + rust, + rust-cross, + typescript, + typo-check, + proc-macro-srv, + miri, + rustfmt, + clippy, + analysis-stats, + ] # We need to ensure this job does *not* get skipped if its dependencies fail, # because a skipped job is considered a success by GitHub. So we have to # overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs index 482cf36f95b0b..022f8adfdb06b 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs @@ -184,7 +184,7 @@ static EMPTY: LazyLock> = LazyLock::new(|| { impl GenericParams { /// The index of the self param in the generic of the non-parent definition. - pub(crate) const SELF_PARAM_ID_IN_SELF: la_arena::Idx = + pub const SELF_PARAM_ID_IN_SELF: la_arena::Idx = LocalTypeOrConstParamId::from_raw(RawIdx::from_u32(0)); pub fn new(db: &dyn DefDatabase, def: GenericDefId) -> Arc { 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 8d6c418d75dc5..de674be05f643 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs @@ -86,7 +86,7 @@ use crate::{ builtin_type::BuiltinType, db::DefDatabase, expr_store::ExpressionStoreSourceMap, - hir::generics::{LocalLifetimeParamId, LocalTypeOrConstParamId}, + hir::generics::{GenericParams, LocalLifetimeParamId, LocalTypeOrConstParamId}, nameres::{ LocalDefMap, assoc::{ImplItems, TraitItems}, @@ -553,15 +553,25 @@ pub struct TypeOrConstParamId { pub struct TypeParamId(TypeOrConstParamId); impl TypeParamId { + #[inline] pub fn parent(&self) -> GenericDefId { self.0.parent } + + #[inline] pub fn local_id(&self) -> LocalTypeOrConstParamId { self.0.local_id } -} -impl TypeParamId { + #[inline] + pub fn trait_self(trait_: TraitId) -> TypeParamId { + TypeParamId::from_unchecked(TypeOrConstParamId { + parent: trait_.into(), + local_id: GenericParams::SELF_PARAM_ID_IN_SELF, + }) + } + + #[inline] /// Caller should check if this toc id really belongs to a type pub fn from_unchecked(it: TypeOrConstParamId) -> Self { Self(it) 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 0c3c51366861b..5a93c2b536064 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 @@ -35,6 +35,24 @@ fn coerce_pointee_new_type_param(trait_id: TraitId) -> TypeParamId { }) } +fn trait_args(trait_: BuiltinDeriveImplTrait, self_ty: Ty<'_>) -> GenericArgs<'_> { + match trait_ { + BuiltinDeriveImplTrait::Copy + | BuiltinDeriveImplTrait::Clone + | BuiltinDeriveImplTrait::Default + | BuiltinDeriveImplTrait::Debug + | BuiltinDeriveImplTrait::Hash + | BuiltinDeriveImplTrait::Eq + | BuiltinDeriveImplTrait::Ord => GenericArgs::new_from_slice(&[self_ty.into()]), + BuiltinDeriveImplTrait::PartialOrd | BuiltinDeriveImplTrait::PartialEq => { + GenericArgs::new_from_slice(&[self_ty.into(), self_ty.into()]) + } + BuiltinDeriveImplTrait::CoerceUnsized | BuiltinDeriveImplTrait::DispatchFromDyn => { + panic!("`CoerceUnsized` and `DispatchFromDyn` have special generics") + } + } +} + pub(crate) fn generics_of<'db>(interner: DbInterner<'db>, id: BuiltinDeriveImplId) -> Generics { let db = interner.db; let loc = id.loc(db); @@ -95,21 +113,19 @@ pub fn impl_trait<'db>( | BuiltinDeriveImplTrait::Debug | BuiltinDeriveImplTrait::Hash | BuiltinDeriveImplTrait::Ord - | BuiltinDeriveImplTrait::Eq => { + | BuiltinDeriveImplTrait::Eq + | BuiltinDeriveImplTrait::PartialOrd + | BuiltinDeriveImplTrait::PartialEq => { let self_ty = Ty::new_adt( interner, loc.adt, GenericArgs::identity_for_item(interner, loc.adt.into()), ); - EarlyBinder::bind(TraitRef::new(interner, trait_id.into(), [self_ty])) - } - BuiltinDeriveImplTrait::PartialOrd | BuiltinDeriveImplTrait::PartialEq => { - let self_ty = Ty::new_adt( + EarlyBinder::bind(TraitRef::new_from_args( interner, - loc.adt, - GenericArgs::identity_for_item(interner, loc.adt.into()), - ); - EarlyBinder::bind(TraitRef::new(interner, trait_id.into(), [self_ty, self_ty])) + trait_id.into(), + trait_args(loc.trait_, self_ty), + )) } BuiltinDeriveImplTrait::CoerceUnsized | BuiltinDeriveImplTrait::DispatchFromDyn => { let generic_params = GenericParams::new(db, loc.adt.into()); @@ -260,7 +276,8 @@ fn simple_trait_predicates<'db>( let param_idx = param_idx.into_raw().into_u32() + (generic_params.len_lifetimes() as u32); let param_ty = Ty::new_param(interner, param_id, param_idx); - let trait_ref = TraitRef::new(interner, trait_id.into(), [param_ty]); + let trait_args = trait_args(loc.trait_, param_ty); + let trait_ref = TraitRef::new_from_args(interner, trait_id.into(), trait_args); trait_ref.upcast(interner) }); let mut assoc_type_bounds = Vec::new(); @@ -270,12 +287,14 @@ fn simple_trait_predicates<'db>( &mut assoc_type_bounds, interner.db.field_types(id.into()), trait_id, + loc.trait_, ), AdtId::UnionId(id) => extend_assoc_type_bounds( interner, &mut assoc_type_bounds, interner.db.field_types(id.into()), trait_id, + loc.trait_, ), AdtId::EnumId(id) => { for &(variant_id, _, _) in &id.enum_variants(interner.db).variants { @@ -284,6 +303,7 @@ fn simple_trait_predicates<'db>( &mut assoc_type_bounds, interner.db.field_types(variant_id.into()), trait_id, + loc.trait_, ) } } @@ -305,12 +325,14 @@ fn extend_assoc_type_bounds<'db>( interner: DbInterner<'db>, assoc_type_bounds: &mut Vec>, fields: &ArenaMap>, - trait_: TraitId, + trait_id: TraitId, + trait_: BuiltinDeriveImplTrait, ) { struct ProjectionFinder<'a, 'db> { interner: DbInterner<'db>, assoc_type_bounds: &'a mut Vec>, - trait_: TraitId, + trait_id: TraitId, + trait_: BuiltinDeriveImplTrait, } impl<'db> TypeVisitor> for ProjectionFinder<'_, 'db> { @@ -319,7 +341,12 @@ fn extend_assoc_type_bounds<'db>( fn visit_ty(&mut self, t: Ty<'db>) -> Self::Result { if let TyKind::Alias(AliasTyKind::Projection, _) = t.kind() { self.assoc_type_bounds.push( - TraitRef::new(self.interner, self.trait_.into(), [t]).upcast(self.interner), + TraitRef::new_from_args( + self.interner, + self.trait_id.into(), + trait_args(self.trait_, t), + ) + .upcast(self.interner), ); } @@ -327,7 +354,7 @@ fn extend_assoc_type_bounds<'db>( } } - let mut visitor = ProjectionFinder { interner, assoc_type_bounds, trait_ }; + let mut visitor = ProjectionFinder { interner, assoc_type_bounds, trait_id, trait_ }; for (_, field) in fields.iter() { field.get().instantiate_identity().visit_with(&mut visitor); } @@ -488,10 +515,12 @@ struct MultiGenericParams<'a, T, #[pointee] U: ?Sized, const N: usize>(*const U) #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] struct Simple; -trait Trait {} +trait Trait { + type Assoc; +} #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -struct WithGenerics<'a, T: Trait, const N: usize>(&'a [T; N]); +struct WithGenerics<'a, T: Trait, const N: usize>(&'a [T; N], T::Assoc); "#, expect![[r#" @@ -514,41 +543,49 @@ struct WithGenerics<'a, T: Trait, const N: usize>(&'a [T; N]); Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] }) Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] }) Clause(Binder { value: TraitPredicate(#1: Debug, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(Alias(Projection, AliasTy { args: [#1], def_id: TypeAliasId("Assoc"), .. }): Debug, polarity:Positive), bound_vars: [] }) Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] }) Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] }) Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] }) Clause(Binder { value: TraitPredicate(#1: Clone, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(Alias(Projection, AliasTy { args: [#1], def_id: TypeAliasId("Assoc"), .. }): Clone, polarity:Positive), bound_vars: [] }) Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] }) Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] }) Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] }) Clause(Binder { value: TraitPredicate(#1: Copy, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(Alias(Projection, AliasTy { args: [#1], def_id: TypeAliasId("Assoc"), .. }): Copy, polarity:Positive), bound_vars: [] }) Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] }) Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] }) Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] }) - Clause(Binder { value: TraitPredicate(#1: PartialEq, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(#1: PartialEq<[#1]>, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(Alias(Projection, AliasTy { args: [#1], def_id: TypeAliasId("Assoc"), .. }): PartialEq<[Alias(Projection, AliasTy { args: [#1], def_id: TypeAliasId("Assoc"), .. })]>, polarity:Positive), bound_vars: [] }) Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] }) Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] }) Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] }) Clause(Binder { value: TraitPredicate(#1: Eq, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(Alias(Projection, AliasTy { args: [#1], def_id: TypeAliasId("Assoc"), .. }): Eq, polarity:Positive), bound_vars: [] }) Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] }) Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] }) Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] }) - Clause(Binder { value: TraitPredicate(#1: PartialOrd, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(#1: PartialOrd<[#1]>, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(Alias(Projection, AliasTy { args: [#1], def_id: TypeAliasId("Assoc"), .. }): PartialOrd<[Alias(Projection, AliasTy { args: [#1], def_id: TypeAliasId("Assoc"), .. })]>, polarity:Positive), bound_vars: [] }) Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] }) Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] }) Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] }) Clause(Binder { value: TraitPredicate(#1: Ord, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(Alias(Projection, AliasTy { args: [#1], def_id: TypeAliasId("Assoc"), .. }): Ord, polarity:Positive), bound_vars: [] }) Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] }) Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] }) Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] }) Clause(Binder { value: TraitPredicate(#1: Hash, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(Alias(Projection, AliasTy { args: [#1], def_id: TypeAliasId("Assoc"), .. }): Hash, polarity:Positive), bound_vars: [] }) "#]], ); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs index 5f0261437b77a..b1500bcdb7568 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs @@ -224,22 +224,6 @@ impl Generics { } } -pub(crate) fn trait_self_param_idx(db: &dyn DefDatabase, def: GenericDefId) -> Option { - match def { - GenericDefId::TraitId(_) => { - let params = db.generic_params(def); - params.trait_self_param().map(|idx| idx.into_raw().into_u32() as usize) - } - GenericDefId::ImplId(_) => None, - _ => { - let parent_def = parent_generic_def(db, def)?; - let parent_params = db.generic_params(parent_def); - let parent_self_idx = parent_params.trait_self_param()?.into_raw().into_u32() as usize; - Some(parent_self_idx) - } - } -} - pub(crate) fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option { let container = match def { GenericDefId::FunctionId(it) => it.lookup(db).container, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index f8920904f06f2..8d87276a0b152 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -31,6 +31,7 @@ mod inhabitedness; mod lower; pub mod next_solver; mod opaques; +mod representability; mod specialization; mod target_feature; mod utils; @@ -57,9 +58,12 @@ mod test_db; #[cfg(test)] mod tests; -use std::hash::Hash; +use std::{hash::Hash, ops::ControlFlow}; -use hir_def::{CallableDefId, TypeOrConstParamId, type_ref::Rawness}; +use hir_def::{ + CallableDefId, GenericDefId, TypeAliasId, TypeOrConstParamId, TypeParamId, + hir::generics::GenericParams, resolver::TypeNs, type_ref::Rawness, +}; use hir_expand::name::Name; use indexmap::{IndexMap, map::Entry}; use intern::{Symbol, sym}; @@ -77,10 +81,11 @@ use crate::{ db::HirDatabase, display::{DisplayTarget, HirDisplay}, infer::unify::InferenceTable, + lower::SupertraitsInfo, next_solver::{ AliasTy, Binder, BoundConst, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, Canonical, - CanonicalVarKind, CanonicalVars, Const, ConstKind, DbInterner, FnSig, GenericArgs, - PolyFnSig, Predicate, Region, RegionKind, TraitRef, Ty, TyKind, Tys, abi, + CanonicalVarKind, CanonicalVars, ClauseKind, Const, ConstKind, DbInterner, FnSig, + GenericArgs, PolyFnSig, Predicate, Region, RegionKind, TraitRef, Ty, TyKind, Tys, abi, }, }; @@ -94,7 +99,7 @@ pub use infer::{ }; pub use lower::{ GenericPredicates, ImplTraits, LifetimeElisionKind, TyDefId, TyLoweringContext, ValueTyDefId, - associated_type_shorthand_candidates, diagnostics::*, + diagnostics::*, }; pub use next_solver::interner::{attach_db, attach_db_allow_change, with_attached_db}; pub use target_feature::TargetFeatures; @@ -478,6 +483,55 @@ where } } +/// To be used from `hir` only. +pub fn associated_type_shorthand_candidates( + db: &dyn HirDatabase, + def: GenericDefId, + res: TypeNs, + mut cb: impl FnMut(&Name, TypeAliasId) -> bool, +) -> Option { + let interner = DbInterner::new_no_crate(db); + let (def, param) = match res { + TypeNs::GenericParam(param) => (def, param), + TypeNs::SelfType(impl_) => { + let impl_trait = db.impl_trait(impl_)?.skip_binder().def_id.0; + let param = TypeParamId::from_unchecked(TypeOrConstParamId { + parent: impl_trait.into(), + local_id: GenericParams::SELF_PARAM_ID_IN_SELF, + }); + (impl_trait.into(), param) + } + _ => return None, + }; + + let mut dedup_map = FxHashSet::default(); + let param_ty = Ty::new_param(interner, param, param_idx(db, param.into()).unwrap() as u32); + // We use the ParamEnv and not the predicates because the ParamEnv elaborates bounds. + let param_env = db.trait_environment(def); + for clause in param_env.clauses { + let ClauseKind::Trait(trait_clause) = clause.kind().skip_binder() else { continue }; + if trait_clause.self_ty() != param_ty { + continue; + } + let trait_id = trait_clause.def_id().0; + dedup_map.extend( + SupertraitsInfo::query(db, trait_id) + .defined_assoc_types + .iter() + .map(|(name, id)| (name, *id)), + ); + } + + dedup_map + .into_iter() + .try_for_each( + |(name, id)| { + if cb(name, id) { ControlFlow::Break(id) } else { ControlFlow::Continue(()) } + }, + ) + .break_value() +} + /// To be used from `hir` only. pub fn callable_sig_from_fn_trait<'db>( self_ty: Ty<'db>, 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 386556b156843..1290874177ac4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -20,7 +20,8 @@ use hir_def::{ builtin_type::BuiltinType, expr_store::{ExpressionStore, HygieneId, path::Path}, hir::generics::{ - GenericParamDataRef, TypeOrConstParamData, TypeParamProvenance, WherePredicate, + GenericParamDataRef, GenericParams, TypeOrConstParamData, TypeParamProvenance, + WherePredicate, }, item_tree::FieldsShape, lang_item::LangItems, @@ -36,27 +37,23 @@ use la_arena::{Arena, ArenaMap, Idx}; use path::{PathDiagnosticCallback, PathLoweringContext}; use rustc_ast_ir::Mutability; use rustc_hash::FxHashSet; -use rustc_pattern_analysis::Captures; use rustc_type_ir::{ AliasTyKind, BoundVarIndexKind, ConstKind, DebruijnIndex, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig, Interner, OutlivesPredicate, TermKind, TyKind::{self}, TypeFoldable, TypeVisitableExt, Upcast, UpcastFrom, elaborate, - inherent::{ - Clause as _, GenericArg as _, GenericArgs as _, IntoKind as _, Region as _, SliceLike, - Ty as _, - }, + inherent::{Clause as _, GenericArgs as _, IntoKind as _, Region as _, Ty as _}, }; -use smallvec::{SmallVec, smallvec}; +use smallvec::SmallVec; use stdx::{impl_from, never}; use tracing::debug; use triomphe::{Arc, ThinArc}; use crate::{ - FnAbi, ImplTraitId, TyLoweringDiagnostic, TyLoweringDiagnosticKind, all_super_traits, + FnAbi, ImplTraitId, TyLoweringDiagnostic, TyLoweringDiagnosticKind, consteval::intern_const_ref, db::{HirDatabase, InternedOpaqueTyId}, - generics::{Generics, generics, trait_self_param_idx}, + generics::{Generics, generics}, next_solver::{ AliasTy, Binder, BoundExistentialPredicates, Clause, ClauseKind, Clauses, Const, DbInterner, EarlyBinder, EarlyParamRegion, ErrorGuaranteed, FxIndexMap, GenericArg, @@ -618,33 +615,12 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { &'b mut self, where_predicate: &'b WherePredicate, ignore_bindings: bool, - generics: &Generics, - predicate_filter: PredicateFilter, ) -> impl Iterator, GenericPredicateSource)> + use<'a, 'b, 'db> { match where_predicate { WherePredicate::ForLifetime { target, bound, .. } | WherePredicate::TypeBound { target, bound } => { - if let PredicateFilter::SelfTrait = predicate_filter { - let target_type = &self.store[*target]; - let self_type = 'is_self: { - if let TypeRef::Path(path) = target_type - && path.is_self_type() - { - break 'is_self true; - } - if let TypeRef::TypeParam(param) = target_type - && generics[param.local_id()].is_trait_self() - { - break 'is_self true; - } - false - }; - if !self_type { - return Either::Left(Either::Left(iter::empty())); - } - } let self_ty = self.lower_ty(*target); - Either::Left(Either::Right(self.lower_type_bound(bound, self_ty, ignore_bindings))) + Either::Left(self.lower_type_bound(bound, self_ty, ignore_bindings)) } &WherePredicate::Lifetime { bound, target } => Either::Right(iter::once(( Clause(Predicate::new( @@ -1626,6 +1602,92 @@ pub(crate) fn field_types_with_diagnostics_query<'db>( (res, create_diagnostics(ctx.diagnostics)) } +#[derive(Debug, PartialEq, Eq, Default)] +pub(crate) struct SupertraitsInfo { + /// This includes the trait itself. + pub(crate) all_supertraits: Box<[TraitId]>, + pub(crate) direct_supertraits: Box<[TraitId]>, + pub(crate) defined_assoc_types: Box<[(Name, TypeAliasId)]>, +} + +impl SupertraitsInfo { + #[inline] + pub(crate) fn query(db: &dyn HirDatabase, trait_: TraitId) -> &Self { + return supertraits_info(db, trait_); + + #[salsa::tracked(returns(ref), cycle_result = supertraits_info_cycle)] + fn supertraits_info(db: &dyn HirDatabase, trait_: TraitId) -> SupertraitsInfo { + let mut all_supertraits = FxHashSet::default(); + let mut direct_supertraits = FxHashSet::default(); + let mut defined_assoc_types = FxHashSet::default(); + + all_supertraits.insert(trait_); + defined_assoc_types.extend(trait_.trait_items(db).items.iter().filter_map( + |(name, id)| match *id { + AssocItemId::TypeAliasId(id) => Some((name.clone(), id)), + _ => None, + }, + )); + + let resolver = trait_.resolver(db); + let signature = db.trait_signature(trait_); + for pred in signature.generic_params.where_predicates() { + let (WherePredicate::TypeBound { target, bound } + | WherePredicate::ForLifetime { lifetimes: _, target, bound }) = pred + else { + continue; + }; + let (TypeBound::Path(bounded_trait, TraitBoundModifier::None) + | TypeBound::ForLifetime(_, bounded_trait)) = *bound + else { + continue; + }; + let target = &signature.store[*target]; + match target { + TypeRef::TypeParam(param) + if param.local_id() == GenericParams::SELF_PARAM_ID_IN_SELF => {} + TypeRef::Path(path) if path.is_self_type() => {} + _ => continue, + } + let Some(TypeNs::TraitId(bounded_trait)) = + resolver.resolve_path_in_type_ns_fully(db, &signature.store[bounded_trait]) + else { + continue; + }; + let SupertraitsInfo { + all_supertraits: bounded_trait_all_supertraits, + direct_supertraits: _, + defined_assoc_types: bounded_traits_defined_assoc_types, + } = SupertraitsInfo::query(db, bounded_trait); + all_supertraits.extend(bounded_trait_all_supertraits); + direct_supertraits.insert(bounded_trait); + defined_assoc_types.extend(bounded_traits_defined_assoc_types.iter().cloned()); + } + + SupertraitsInfo { + all_supertraits: Box::from_iter(all_supertraits), + direct_supertraits: Box::from_iter(direct_supertraits), + defined_assoc_types: Box::from_iter(defined_assoc_types), + } + } + + fn supertraits_info_cycle( + _db: &dyn HirDatabase, + _: salsa::Id, + _trait_: TraitId, + ) -> SupertraitsInfo { + SupertraitsInfo::default() + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +enum TypeParamAssocTypeShorthandError { + AssocTypeNotFound, + AmbiguousAssocType, + Cycle, +} + /// Predicates for `param_id` of the form `P: SomeTrait`. If /// `assoc_name` is provided, only return predicates referencing traits /// that have an associated type of that name. @@ -1640,15 +1702,14 @@ pub(crate) fn field_types_with_diagnostics_query<'db>( /// following bounds are disallowed: `T: Foo, U: Foo`, but /// these are fine: `T: Foo, U: Foo<()>`. #[tracing::instrument(skip(db), ret)] -#[salsa::tracked(returns(ref), cycle_result = generic_predicates_for_param_cycle_result)] -pub(crate) fn generic_predicates_for_param<'db>( - db: &'db dyn HirDatabase, +#[salsa::tracked(returns(ref), cycle_result = resolve_type_param_assoc_type_shorthand_cycle_result)] +fn resolve_type_param_assoc_type_shorthand( + db: &dyn HirDatabase, def: GenericDefId, - param_id: TypeOrConstParamId, - assoc_name: Option, -) -> StoredEarlyBinder { + param: TypeParamId, + assoc_name: Name, +) -> Result, TypeParamAssocTypeShorthandError> { let generics = generics(db, def); - let interner = DbInterner::new_no_crate(db); let resolver = def.resolver(db); let mut ctx = TyLoweringContext::new( db, @@ -1657,128 +1718,109 @@ pub(crate) fn generic_predicates_for_param<'db>( def, LifetimeElisionKind::AnonymousReportError, ); + let interner = ctx.interner; + let mut result = None; + let param_ty = Ty::new_param( + interner, + param, + generics.type_or_const_param_idx(param.into()).unwrap() as u32, + ); - // we have to filter out all other predicates *first*, before attempting to lower them - let has_relevant_bound = |pred: &_, ctx: &mut TyLoweringContext<'_, '_>| match pred { - WherePredicate::ForLifetime { target, bound, .. } - | WherePredicate::TypeBound { target, bound, .. } => { - let invalid_target = { ctx.lower_ty_only_param(*target) != Some(param_id) }; - if invalid_target { - // FIXME(sized-hierarchy): Revisit and adjust this properly once we have implemented - // sized-hierarchy correctly. - // If this is filtered out without lowering, `?Sized` or `PointeeSized` is not gathered into - // `ctx.unsized_types` - let lower = || -> bool { - match bound { - TypeBound::Path(_, TraitBoundModifier::Maybe) => true, - TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => { - let TypeRef::Path(path) = &ctx.store[path.type_ref()] else { - return false; - }; - let Some(pointee_sized) = ctx.lang_items.PointeeSized else { - return false; - }; - // Lower the path directly with `Resolver` instead of PathLoweringContext` - // to prevent diagnostics duplications. - ctx.resolver.resolve_path_in_type_ns_fully(ctx.db, path).is_some_and( - |it| matches!(it, TypeNs::TraitId(tr) if tr == pointee_sized), - ) - } - _ => false, - } - }(); - if lower { - ctx.lower_where_predicate(pred, true, &generics, PredicateFilter::All) - .for_each(drop); - } - return false; - } - - match bound { - &TypeBound::ForLifetime(_, path) | &TypeBound::Path(path, _) => { - // Only lower the bound if the trait could possibly define the associated - // type we're looking for. - let path = &ctx.store[path]; - - let Some(assoc_name) = &assoc_name else { return true }; - let Some(TypeNs::TraitId(tr)) = - resolver.resolve_path_in_type_ns_fully(db, path) - else { - return false; - }; - - trait_or_supertrait_has_assoc_type(db, tr, assoc_name) - } - TypeBound::Use(_) | TypeBound::Lifetime(_) | TypeBound::Error => false, - } + if let GenericDefId::TraitId(containing_trait) = param.parent() + && param.local_id() == GenericParams::SELF_PARAM_ID_IN_SELF + { + // Add the trait's own associated types. + if let Some(assoc_type) = + containing_trait.trait_items(db).associated_type_by_name(&assoc_name) + { + let args = GenericArgs::identity_for_item(interner, containing_trait.into()); + result = Some(StoredEarlyBinder::bind((assoc_type, args.store()))); } - WherePredicate::Lifetime { .. } => false, - }; - let mut predicates = Vec::new(); + } + for maybe_parent_generics in std::iter::successors(Some(&generics), |generics| generics.parent_generics()) { ctx.store = maybe_parent_generics.store(); for pred in maybe_parent_generics.where_predicates() { - if has_relevant_bound(pred, &mut ctx) { - predicates.extend( - ctx.lower_where_predicate( - pred, - true, - maybe_parent_generics, - PredicateFilter::All, - ) - .map(|(pred, _)| pred), - ); + let (WherePredicate::TypeBound { target, bound } + | WherePredicate::ForLifetime { lifetimes: _, target, bound }) = pred + else { + continue; + }; + let (TypeBound::Path(bounded_trait_path, TraitBoundModifier::None) + | TypeBound::ForLifetime(_, bounded_trait_path)) = *bound + else { + continue; + }; + let Some(target) = ctx.lower_ty_only_param(*target) else { continue }; + if target != param.into() { + continue; + } + let Some(TypeNs::TraitId(bounded_trait)) = + resolver.resolve_path_in_type_ns_fully(db, &ctx.store[bounded_trait_path]) + else { + continue; + }; + if !SupertraitsInfo::query(db, bounded_trait) + .defined_assoc_types + .iter() + .any(|(name, _)| *name == assoc_name) + { + continue; } + + let Some((bounded_trait_ref, _)) = + ctx.lower_trait_ref_from_path(bounded_trait_path, param_ty) + else { + continue; + }; + // Now, search from the start on the *bounded* trait like if we wrote `Self::Assoc`. Eventually, we'll get + // the correct trait ref (or a cycle). + let lookup_on_bounded_trait = resolve_type_param_assoc_type_shorthand( + db, + bounded_trait.into(), + TypeParamId::trait_self(bounded_trait), + assoc_name.clone(), + ); + let lookup_on_bounded_trait = match lookup_on_bounded_trait { + Ok(it) => it, + Err( + err @ (TypeParamAssocTypeShorthandError::AmbiguousAssocType + | TypeParamAssocTypeShorthandError::Cycle), + ) => return Err(*err), + Err(TypeParamAssocTypeShorthandError::AssocTypeNotFound) => { + never!("we checked that the trait defines this assoc type"); + continue; + } + }; + let (assoc_type, args) = lookup_on_bounded_trait + .get_with(|(assoc_type, args)| (*assoc_type, args.as_ref())) + .skip_binder(); + let args = EarlyBinder::bind(args).instantiate(interner, bounded_trait_ref.args); + let current_result = StoredEarlyBinder::bind((assoc_type, args.store())); + // If we already have a result, this is an ambiguity - unless this is the same result, then we are fine + // (e.g. rustc allows to write the same bound twice without ambiguity). + if let Some(existing_result) = result + && existing_result != current_result + { + return Err(TypeParamAssocTypeShorthandError::AmbiguousAssocType); + } + result = Some(current_result); } } - let args = GenericArgs::identity_for_item(interner, def.into()); - if !args.is_empty() { - let explicitly_unsized_tys = ctx.unsized_types; - if let Some(implicitly_sized_predicates) = implicitly_sized_clauses( - db, - ctx.lang_items, - param_id.parent, - &explicitly_unsized_tys, - &args, - ) { - predicates.extend(implicitly_sized_predicates); - }; - } - StoredEarlyBinder::bind(Clauses::new_from_slice(&predicates).store()) + result.ok_or(TypeParamAssocTypeShorthandError::AssocTypeNotFound) } -pub(crate) fn generic_predicates_for_param_cycle_result( - db: &dyn HirDatabase, +fn resolve_type_param_assoc_type_shorthand_cycle_result( + _db: &dyn HirDatabase, _: salsa::Id, _def: GenericDefId, - _param_id: TypeOrConstParamId, - _assoc_name: Option, -) -> StoredEarlyBinder { - StoredEarlyBinder::bind(Clauses::empty(DbInterner::new_no_crate(db)).store()) -} - -/// Check if this trait or any of its supertraits define an associated -/// type with the given name. -fn trait_or_supertrait_has_assoc_type( - db: &dyn HirDatabase, - tr: TraitId, - assoc_name: &Name, -) -> bool { - for trait_id in all_super_traits(db, tr) { - if trait_id - .trait_items(db) - .items - .iter() - .any(|(name, item)| matches!(item, AssocItemId::TypeAliasId(_)) && name == assoc_name) - { - return true; - } - } - - false + _param: TypeParamId, + _assoc_name: Name, +) -> Result, TypeParamAssocTypeShorthandError> { + Err(TypeParamAssocTypeShorthandError::Cycle) } #[inline] @@ -1904,7 +1946,7 @@ impl<'db> GenericPredicates { db: &'db dyn HirDatabase, def: GenericDefId, ) -> (GenericPredicates, Diagnostics) { - generic_predicates_filtered_by(db, def, PredicateFilter::All, |_| true) + generic_predicates(db, def) } } @@ -2042,24 +2084,10 @@ pub(crate) fn trait_environment<'db>(db: &'db dyn HirDatabase, def: GenericDefId } } -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub(crate) enum PredicateFilter { - SelfTrait, - All, -} - /// Resolve the where clause(s) of an item with generics, /// with a given filter -#[tracing::instrument(skip(db, filter), ret)] -pub(crate) fn generic_predicates_filtered_by( - db: &dyn HirDatabase, - def: GenericDefId, - predicate_filter: PredicateFilter, - filter: F, -) -> (GenericPredicates, Diagnostics) -where - F: Fn(GenericDefId) -> bool, -{ +#[tracing::instrument(skip(db), ret)] +fn generic_predicates(db: &dyn HirDatabase, def: GenericDefId) -> (GenericPredicates, Diagnostics) { let generics = generics(db, def); let resolver = def.resolver(db); let interner = DbInterner::new_no_crate(db); @@ -2081,9 +2109,9 @@ where let all_generics = std::iter::successors(Some(&generics), |generics| generics.parent_generics()) .collect::>(); - let own_implicit_trait_predicate = implicit_trait_predicate(interner, def, predicate_filter); + let own_implicit_trait_predicate = implicit_trait_predicate(interner, def); let parent_implicit_trait_predicate = if all_generics.len() > 1 { - implicit_trait_predicate(interner, all_generics.last().unwrap().def(), predicate_filter) + implicit_trait_predicate(interner, all_generics.last().unwrap().def()) } else { None }; @@ -2091,97 +2119,85 @@ where // Collect only diagnostics from the child, not including parents. ctx.diagnostics.clear(); - if filter(maybe_parent_generics.def()) { - ctx.store = maybe_parent_generics.store(); - for pred in maybe_parent_generics.where_predicates() { - tracing::debug!(?pred); - for (pred, source) in - ctx.lower_where_predicate(pred, false, maybe_parent_generics, predicate_filter) - { - match source { - GenericPredicateSource::SelfOnly => { - if maybe_parent_generics.def() == def { - own_predicates.push(pred); - } else { - parent_predicates.push(pred); - } + ctx.store = maybe_parent_generics.store(); + for pred in maybe_parent_generics.where_predicates() { + tracing::debug!(?pred); + for (pred, source) in ctx.lower_where_predicate(pred, false) { + match source { + GenericPredicateSource::SelfOnly => { + if maybe_parent_generics.def() == def { + own_predicates.push(pred); + } else { + parent_predicates.push(pred); } - GenericPredicateSource::AssocTyBound => { - if maybe_parent_generics.def() == def { - own_assoc_ty_bounds.push(pred); - } else { - parent_assoc_ty_bounds.push(pred); - } + } + GenericPredicateSource::AssocTyBound => { + if maybe_parent_generics.def() == def { + own_assoc_ty_bounds.push(pred); + } else { + parent_assoc_ty_bounds.push(pred); } } } } + } - if maybe_parent_generics.def() == def { - push_const_arg_has_type_predicates(db, &mut own_predicates, maybe_parent_generics); - } else { - push_const_arg_has_type_predicates( - db, - &mut parent_predicates, - maybe_parent_generics, - ); - } + if maybe_parent_generics.def() == def { + push_const_arg_has_type_predicates(db, &mut own_predicates, maybe_parent_generics); + } else { + push_const_arg_has_type_predicates(db, &mut parent_predicates, maybe_parent_generics); + } - if let Some(sized_trait) = sized_trait { - let mut add_sized_clause = |param_idx, param_id, param_data| { - let ( - GenericParamId::TypeParamId(param_id), - GenericParamDataRef::TypeParamData(param_data), - ) = (param_id, param_data) - else { - return; - }; + if let Some(sized_trait) = sized_trait { + let mut add_sized_clause = |param_idx, param_id, param_data| { + let ( + GenericParamId::TypeParamId(param_id), + GenericParamDataRef::TypeParamData(param_data), + ) = (param_id, param_data) + else { + return; + }; - if param_data.provenance == TypeParamProvenance::TraitSelf { - return; - } + if param_data.provenance == TypeParamProvenance::TraitSelf { + return; + } - let param_ty = Ty::new_param(interner, param_id, param_idx); - if ctx.unsized_types.contains(¶m_ty) { - return; - } - let trait_ref = TraitRef::new_from_args( - interner, - sized_trait.into(), - GenericArgs::new_from_slice(&[param_ty.into()]), - ); - let clause = Clause(Predicate::new( - interner, - Binder::dummy(rustc_type_ir::PredicateKind::Clause( - rustc_type_ir::ClauseKind::Trait(TraitPredicate { - trait_ref, - polarity: rustc_type_ir::PredicatePolarity::Positive, - }), - )), - )); - if maybe_parent_generics.def() == def { - own_predicates.push(clause); - } else { - parent_predicates.push(clause); - } - }; - let parent_params_len = maybe_parent_generics.len_parent(); - maybe_parent_generics.iter_self().enumerate().for_each( - |(param_idx, (param_id, param_data))| { - add_sized_clause( - (param_idx + parent_params_len) as u32, - param_id, - param_data, - ); - }, + let param_ty = Ty::new_param(interner, param_id, param_idx); + if ctx.unsized_types.contains(¶m_ty) { + return; + } + let trait_ref = TraitRef::new_from_args( + interner, + sized_trait.into(), + GenericArgs::new_from_slice(&[param_ty.into()]), ); - } - - // We do not clear `ctx.unsized_types`, as the `?Sized` clause of a child (e.g. an associated type) can - // be declared on the parent (e.g. the trait). It is nevertheless fine to register the implicit `Sized` - // predicates before lowering the child, as a child cannot define a `?Sized` predicate for its parent. - // But we do have to lower the parent first. + let clause = Clause(Predicate::new( + interner, + Binder::dummy(rustc_type_ir::PredicateKind::Clause( + rustc_type_ir::ClauseKind::Trait(TraitPredicate { + trait_ref, + polarity: rustc_type_ir::PredicatePolarity::Positive, + }), + )), + )); + if maybe_parent_generics.def() == def { + own_predicates.push(clause); + } else { + parent_predicates.push(clause); + } + }; + let parent_params_len = maybe_parent_generics.len_parent(); + maybe_parent_generics.iter_self().enumerate().for_each( + |(param_idx, (param_id, param_data))| { + add_sized_clause((param_idx + parent_params_len) as u32, param_id, param_data); + }, + ); } + + // We do not clear `ctx.unsized_types`, as the `?Sized` clause of a child (e.g. an associated type) can + // be declared on the parent (e.g. the trait). It is nevertheless fine to register the implicit `Sized` + // predicates before lowering the child, as a child cannot define a `?Sized` predicate for its parent. + // But we do have to lower the parent first. } let diagnostics = create_diagnostics(ctx.diagnostics); @@ -2229,7 +2245,6 @@ where fn implicit_trait_predicate<'db>( interner: DbInterner<'db>, def: GenericDefId, - predicate_filter: PredicateFilter, ) -> Option> { // For traits, add `Self: Trait` predicate. This is // not part of the predicates that a user writes, but it @@ -2243,9 +2258,7 @@ where // prove that the trait applies to the types that were // used, and adding the predicate into this list ensures // that this is done. - if let GenericDefId::TraitId(def_id) = def - && predicate_filter == PredicateFilter::All - { + if let GenericDefId::TraitId(def_id) = def { Some(TraitRef::identity(interner, def_id.into()).upcast(interner)) } else { None @@ -2282,49 +2295,6 @@ fn push_const_arg_has_type_predicates<'db>( } } -/// Generate implicit `: Sized` predicates for all generics that has no `?Sized` bound. -/// Exception is Self of a trait def. -fn implicitly_sized_clauses<'a, 'subst, 'db>( - db: &'db dyn HirDatabase, - lang_items: &LangItems, - def: GenericDefId, - explicitly_unsized_tys: &'a FxHashSet>, - args: &'subst GenericArgs<'db>, -) -> Option> + Captures<'a> + Captures<'subst>> { - let interner = DbInterner::new_no_crate(db); - let sized_trait = lang_items.Sized?; - - let trait_self_idx = trait_self_param_idx(db, def); - - Some( - args.iter() - .enumerate() - .filter_map( - move |(idx, generic_arg)| { - if Some(idx) == trait_self_idx { None } else { Some(generic_arg) } - }, - ) - .filter_map(|generic_arg| generic_arg.as_type()) - .filter(move |self_ty| !explicitly_unsized_tys.contains(self_ty)) - .map(move |self_ty| { - let trait_ref = TraitRef::new_from_args( - interner, - sized_trait.into(), - GenericArgs::new_from_slice(&[self_ty.into()]), - ); - Clause(Predicate::new( - interner, - Binder::dummy(rustc_type_ir::PredicateKind::Clause( - rustc_type_ir::ClauseKind::Trait(TraitPredicate { - trait_ref, - polarity: rustc_type_ir::PredicatePolarity::Positive, - }), - )), - )) - }), - ) -} - #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct GenericDefaults(Option>]>>); @@ -2602,235 +2572,19 @@ pub(crate) fn associated_ty_item_bounds<'db>( pub(crate) fn associated_type_by_name_including_super_traits<'db>( db: &'db dyn HirDatabase, trait_ref: TraitRef<'db>, - name: &Name, -) -> Option<(TraitRef<'db>, TypeAliasId)> { - let module = trait_ref.def_id.0.module(db); - let interner = DbInterner::new_with(db, module.krate(db)); - all_supertraits_trait_refs(db, trait_ref.def_id.0) - .map(|t| t.instantiate(interner, trait_ref.args)) - .find_map(|t| { - let trait_id = t.def_id.0; - let assoc_type = trait_id.trait_items(db).associated_type_by_name(name)?; - Some((t, assoc_type)) - }) -} - -pub fn associated_type_shorthand_candidates( - db: &dyn HirDatabase, - def: GenericDefId, - res: TypeNs, - mut cb: impl FnMut(&Name, TypeAliasId) -> bool, -) -> Option { - let interner = DbInterner::new_no_crate(db); - named_associated_type_shorthand_candidates(interner, def, res, None, |name, _, id| { - cb(name, id).then_some(id) - }) -} - -#[tracing::instrument(skip(interner, check_alias))] -fn named_associated_type_shorthand_candidates<'db, R>( - interner: DbInterner<'db>, - // If the type parameter is defined in an impl and we're in a method, there - // might be additional where clauses to consider - def: GenericDefId, - res: TypeNs, - assoc_name: Option, - mut check_alias: impl FnMut(&Name, TraitRef<'db>, TypeAliasId) -> Option, -) -> Option { - let db = interner.db; - let mut search = |t: TraitRef<'db>| -> Option { - let mut checked_traits = FxHashSet::default(); - let mut check_trait = |trait_ref: TraitRef<'db>| { - let trait_id = trait_ref.def_id.0; - let name = &db.trait_signature(trait_id).name; - tracing::debug!(?trait_id, ?name); - if !checked_traits.insert(trait_id) { - return None; - } - let data = trait_id.trait_items(db); - - tracing::debug!(?data.items); - for (name, assoc_id) in &data.items { - if let &AssocItemId::TypeAliasId(alias) = assoc_id - && let Some(ty) = check_alias(name, trait_ref, alias) - { - return Some(ty); - } - } - None - }; - let mut stack: SmallVec<[_; 4]> = smallvec![t]; - while let Some(trait_ref) = stack.pop() { - if let Some(alias) = check_trait(trait_ref) { - return Some(alias); - } - let predicates = generic_predicates_filtered_by( - db, - GenericDefId::TraitId(trait_ref.def_id.0), - PredicateFilter::SelfTrait, - // We are likely in the midst of lowering generic predicates of `def`. - // So, if we allow `pred == def` we might fall into an infinite recursion. - // Actually, we have already checked for the case `pred == def` above as we started - // with a stack including `trait_id` - |pred| pred != def && pred == GenericDefId::TraitId(trait_ref.def_id.0), - ) - .0 - .predicates; - for pred in predicates.get().instantiate_identity() { - tracing::debug!(?pred); - let sup_trait_ref = match pred.kind().skip_binder() { - rustc_type_ir::ClauseKind::Trait(pred) => pred.trait_ref, - _ => continue, - }; - let sup_trait_ref = - EarlyBinder::bind(sup_trait_ref).instantiate(interner, trait_ref.args); - stack.push(sup_trait_ref); - } - tracing::debug!(?stack); - } - - None - }; - - match res { - TypeNs::SelfType(impl_id) => { - let trait_ref = db.impl_trait(impl_id)?; - - // FIXME(next-solver): same method in `lower` checks for impl or not - // Is that needed here? - - // we're _in_ the impl -- the binders get added back later. Correct, - // but it would be nice to make this more explicit - search(trait_ref.skip_binder()) - } - TypeNs::GenericParam(param_id) => { - // Handle `Self::Type` referring to own associated type in trait definitions - // This *must* be done first to avoid cycles with - // `generic_predicates_for_param`, but not sure that it's sufficient, - if let GenericDefId::TraitId(trait_id) = param_id.parent() { - let trait_name = &db.trait_signature(trait_id).name; - tracing::debug!(?trait_name); - let trait_generics = generics(db, trait_id.into()); - tracing::debug!(?trait_generics); - if trait_generics[param_id.local_id()].is_trait_self() { - let args = GenericArgs::identity_for_item(interner, trait_id.into()); - let trait_ref = TraitRef::new_from_args(interner, trait_id.into(), args); - tracing::debug!(?args, ?trait_ref); - return search(trait_ref); - } - } - - let predicates = - generic_predicates_for_param(db, def, param_id.into(), assoc_name.clone()); - predicates - .get() - .iter_identity() - .find_map(|pred| match pred.kind().skip_binder() { - rustc_type_ir::ClauseKind::Trait(trait_predicate) => Some(trait_predicate), - _ => None, - }) - .and_then(|trait_predicate| { - let trait_ref = trait_predicate.trait_ref; - assert!( - !trait_ref.has_escaping_bound_vars(), - "FIXME unexpected higher-ranked trait bound" - ); - search(trait_ref) - }) - } - _ => None, - } -} - -/// During lowering, elaborating supertraits can cause cycles. To avoid that, we have a separate query -/// to only collect supertraits. -/// -/// Technically, it is possible to avoid even more cycles by only collecting the `TraitId` of supertraits -/// without their args. However rustc doesn't do that, so we don't either. -pub(crate) fn all_supertraits_trait_refs( - db: &dyn HirDatabase, - trait_: TraitId, -) -> impl ExactSizeIterator>> { + name: Name, +) -> Option<(TypeAliasId, GenericArgs<'db>)> { + let assoc_type = resolve_type_param_assoc_type_shorthand( + db, + trait_ref.def_id.0.into(), + TypeParamId::trait_self(trait_ref.def_id.0), + name.clone(), + ) + .as_ref() + .ok()?; + let (assoc_type, trait_args) = assoc_type + .get_with(|(assoc_type, trait_args)| (*assoc_type, trait_args.as_ref())) + .skip_binder(); let interner = DbInterner::new_no_crate(db); - return all_supertraits_trait_refs_query(db, trait_).iter().map(move |trait_ref| { - trait_ref.get_with(|(trait_, args)| { - TraitRef::new_from_args(interner, (*trait_).into(), args.as_ref()) - }) - }); - - #[salsa_macros::tracked(returns(deref), cycle_result = all_supertraits_trait_refs_cycle_result)] - pub(crate) fn all_supertraits_trait_refs_query( - db: &dyn HirDatabase, - trait_: TraitId, - ) -> Box<[StoredEarlyBinder<(TraitId, StoredGenericArgs)>]> { - let resolver = trait_.resolver(db); - let signature = db.trait_signature(trait_); - let mut ctx = TyLoweringContext::new( - db, - &resolver, - &signature.store, - trait_.into(), - LifetimeElisionKind::AnonymousReportError, - ); - let interner = ctx.interner; - - let self_param_ty = Ty::new_param( - interner, - TypeParamId::from_unchecked(TypeOrConstParamId { - parent: trait_.into(), - local_id: Idx::from_raw(la_arena::RawIdx::from_u32(0)), - }), - 0, - ); - - let mut supertraits = FxHashSet::default(); - supertraits.insert(StoredEarlyBinder::bind(( - trait_, - GenericArgs::identity_for_item(interner, trait_.into()).store(), - ))); - - for pred in signature.generic_params.where_predicates() { - let WherePredicate::TypeBound { target, bound } = pred else { - continue; - }; - let target = &signature.store[*target]; - if let TypeRef::TypeParam(param_id) = target - && param_id.local_id().into_raw().into_u32() == 0 - { - // This is `Self`. - } else if let TypeRef::Path(path) = target - && path.is_self_type() - { - // Also `Self`. - } else { - // Not `Self`! - continue; - } - - ctx.lower_type_bound(bound, self_param_ty, true).for_each(|(clause, _)| { - if let ClauseKind::Trait(trait_ref) = clause.kind().skip_binder() { - supertraits.extend( - all_supertraits_trait_refs(db, trait_ref.trait_ref.def_id.0).map(|t| { - let trait_ref = t.instantiate(interner, trait_ref.trait_ref.args); - StoredEarlyBinder::bind((trait_ref.def_id.0, trait_ref.args.store())) - }), - ); - } - }); - } - - Box::from_iter(supertraits) - } - - pub(crate) fn all_supertraits_trait_refs_cycle_result( - db: &dyn HirDatabase, - _: salsa::Id, - trait_: TraitId, - ) -> Box<[StoredEarlyBinder<(TraitId, StoredGenericArgs)>]> { - let interner = DbInterner::new_no_crate(db); - Box::new([StoredEarlyBinder::bind(( - trait_, - GenericArgs::identity_for_item(interner, trait_.into()).store(), - ))]) - } + Some((assoc_type, EarlyBinder::bind(trait_args).instantiate(interner, trait_ref.args))) } 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 517f67b828a07..d47d696259d54 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 @@ -2,7 +2,7 @@ use either::Either; use hir_def::{ - GenericDefId, GenericParamId, Lookup, TraitId, TypeAliasId, + GenericDefId, GenericParamId, Lookup, TraitId, TypeParamId, expr_store::{ ExpressionStore, HygieneId, path::{ @@ -17,7 +17,6 @@ use hir_def::{ signatures::TraitFlags, type_ref::{TypeRef, TypeRefId}, }; -use hir_expand::name::Name; use rustc_type_ir::{ AliasTerm, AliasTy, AliasTyKind, inherent::{GenericArgs as _, Region as _, Ty as _}, @@ -31,13 +30,10 @@ use crate::{ consteval::{unknown_const, unknown_const_as_generic}, db::HirDatabase, generics::{Generics, generics}, - lower::{ - GenericPredicateSource, LifetimeElisionKind, PathDiagnosticCallbackData, - named_associated_type_shorthand_candidates, - }, + lower::{GenericPredicateSource, LifetimeElisionKind, PathDiagnosticCallbackData}, next_solver::{ - Binder, Clause, Const, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, Predicate, - ProjectionPredicate, Region, TraitRef, Ty, + Binder, Clause, Const, DbInterner, EarlyBinder, ErrorGuaranteed, GenericArg, GenericArgs, + Predicate, ProjectionPredicate, Region, TraitRef, Ty, }, }; @@ -479,43 +475,59 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { #[tracing::instrument(skip(self), ret)] fn select_associated_type(&mut self, res: Option, infer_args: bool) -> Ty<'db> { let interner = self.ctx.interner; - let Some(res) = res else { - return Ty::new_error(self.ctx.interner, ErrorGuaranteed); - }; + let db = self.ctx.db; let def = self.ctx.def; let segment = self.current_or_prev_segment; let assoc_name = segment.name; - let check_alias = |name: &Name, t: TraitRef<'db>, associated_ty: TypeAliasId| { - if name != assoc_name { - return None; + let error_ty = || Ty::new_error(self.ctx.interner, ErrorGuaranteed); + let (assoc_type, trait_args) = match res { + Some(TypeNs::GenericParam(param)) => { + let Ok(assoc_type) = super::resolve_type_param_assoc_type_shorthand( + db, + def, + param, + assoc_name.clone(), + ) else { + return error_ty(); + }; + assoc_type + .get_with(|(assoc_type, trait_args)| (*assoc_type, trait_args.as_ref())) + .skip_binder() } - - // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent - // generic params. It's inefficient to splice the `Substitution`s, so we may want - // that method to optionally take parent `Substitution` as we already know them at - // this point (`t.substitution`). - let substs = - self.substs_from_path_segment(associated_ty.into(), infer_args, None, true); - - let substs = GenericArgs::new_from_iter( - interner, - t.args.iter().chain(substs.iter().skip(t.args.len())), - ); - - Some(Ty::new_alias( - interner, - AliasTyKind::Projection, - AliasTy::new_from_args(interner, associated_ty.into(), substs), - )) + Some(TypeNs::SelfType(impl_)) => { + let Some(impl_trait) = db.impl_trait(impl_) else { + return error_ty(); + }; + let impl_trait = impl_trait.instantiate_identity(); + // Searching for `Self::Assoc` in `impl Trait for Type` is like searching for `Self::Assoc` in `Trait`. + let Ok(assoc_type) = super::resolve_type_param_assoc_type_shorthand( + db, + impl_trait.def_id.0.into(), + TypeParamId::trait_self(impl_trait.def_id.0), + assoc_name.clone(), + ) else { + return error_ty(); + }; + let (assoc_type, trait_args) = assoc_type + .get_with(|(assoc_type, trait_args)| (*assoc_type, trait_args.as_ref())) + .skip_binder(); + (assoc_type, EarlyBinder::bind(trait_args).instantiate(interner, impl_trait.args)) + } + _ => return error_ty(), }; - named_associated_type_shorthand_candidates( + + // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent + // generic params. It's inefficient to splice the `Substitution`s, so we may want + // that method to optionally take parent `Substitution` as we already know them at + // this point (`t.substitution`). + let substs = self.substs_from_path_segment(assoc_type.into(), infer_args, None, true); + + let substs = GenericArgs::new_from_iter( interner, - def, - res, - Some(assoc_name.clone()), - check_alias, - ) - .unwrap_or_else(|| Ty::new_error(interner, ErrorGuaranteed)) + trait_args.iter().chain(substs.iter().skip(trait_args.len())), + ); + + Ty::new_projection_from_args(interner, assoc_type.into(), substs) } fn lower_path_inner(&mut self, typeable: TyDefId, infer_args: bool) -> Ty<'db> { @@ -860,9 +872,9 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { let found = associated_type_by_name_including_super_traits( self.ctx.db, trait_ref, - &binding.name, + binding.name.clone(), ); - let (super_trait_ref, associated_ty) = match found { + let (associated_ty, super_trait_args) = match found { None => return SmallVec::new(), Some(t) => t, }; @@ -876,7 +888,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { binding.args.as_ref(), associated_ty.into(), false, // this is not relevant - Some(super_trait_ref.self_ty()), + Some(super_trait_args.type_at(0)), PathGenericsSource::AssocType { segment: this.current_segment_u32(), assoc_type: binding_idx as u32, @@ -887,7 +899,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { }); let args = GenericArgs::new_from_iter( interner, - super_trait_ref.args.iter().chain(args.iter().skip(super_trait_ref.args.len())), + super_trait_args.iter().chain(args.iter().skip(super_trait_args.len())), ); let projection_term = AliasTerm::new_from_args(interner, associated_ty.into(), args); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs index 9a1b476976e34..c175062bda37c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs @@ -13,13 +13,16 @@ use rustc_type_ir::{ solve::SizedTraitKind, }; -use crate::next_solver::{ - BoundConst, FxIndexMap, ParamEnv, Placeholder, PlaceholderConst, PlaceholderRegion, - PolyTraitRef, - infer::{ - InferCtxt, - traits::{Obligation, ObligationCause, PredicateObligation}, +use crate::{ + next_solver::{ + BoundConst, FxIndexMap, ParamEnv, Placeholder, PlaceholderConst, PlaceholderRegion, + PolyTraitRef, + infer::{ + InferCtxt, + traits::{Obligation, ObligationCause, PredicateObligation}, + }, }, + representability::Representability, }; use super::{ @@ -419,10 +422,18 @@ pub fn sizedness_constraint_for_ty<'db>( .next_back() .and_then(|ty| sizedness_constraint_for_ty(interner, sizedness, ty)), - Adt(adt, args) => adt.struct_tail_ty(interner).and_then(|tail_ty| { - let tail_ty = tail_ty.instantiate(interner, args); - sizedness_constraint_for_ty(interner, sizedness, tail_ty) - }), + Adt(adt, args) => { + if crate::representability::representability(interner.db, adt.def_id().0) + == Representability::Infinite + { + return None; + } + + adt.struct_tail_ty(interner).and_then(|tail_ty| { + let tail_ty = tail_ty.instantiate(interner, args); + sizedness_constraint_for_ty(interner, sizedness, tail_ty) + }) + } Placeholder(..) | Bound(..) | Infer(..) => { panic!("unexpected type `{ty:?}` in sizedness_constraint_for_ty") diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/representability.rs b/src/tools/rust-analyzer/crates/hir-ty/src/representability.rs new file mode 100644 index 0000000000000..7e40f2d7ac75f --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/representability.rs @@ -0,0 +1,131 @@ +//! Detecting whether a type is infinitely-sized. + +use hir_def::{AdtId, VariantId}; +use rustc_type_ir::inherent::{AdtDef, IntoKind}; + +use crate::{ + db::HirDatabase, + next_solver::{GenericArgKind, GenericArgs, Ty, TyKind}, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) enum Representability { + Representable, + Infinite, +} + +macro_rules! rtry { + ($e:expr) => { + match $e { + e @ Representability::Infinite => return e, + Representability::Representable => {} + } + }; +} + +#[salsa::tracked(cycle_result = representability_cycle)] +pub(crate) fn representability(db: &dyn HirDatabase, id: AdtId) -> Representability { + match id { + AdtId::StructId(id) => variant_representability(db, id.into()), + AdtId::UnionId(id) => variant_representability(db, id.into()), + AdtId::EnumId(id) => { + for &(variant, ..) in &id.enum_variants(db).variants { + rtry!(variant_representability(db, variant.into())); + } + Representability::Representable + } + } +} + +pub(crate) fn representability_cycle( + _db: &dyn HirDatabase, + _: salsa::Id, + _id: AdtId, +) -> Representability { + Representability::Infinite +} + +fn variant_representability(db: &dyn HirDatabase, id: VariantId) -> Representability { + for ty in db.field_types(id).values() { + rtry!(representability_ty(db, ty.get().instantiate_identity())); + } + Representability::Representable +} + +fn representability_ty<'db>(db: &'db dyn HirDatabase, ty: Ty<'db>) -> Representability { + match ty.kind() { + TyKind::Adt(adt_id, args) => representability_adt_ty(db, adt_id.def_id().0, args), + // FIXME(#11924) allow zero-length arrays? + TyKind::Array(ty, _) => representability_ty(db, ty), + TyKind::Tuple(tys) => { + for ty in tys { + rtry!(representability_ty(db, ty)); + } + Representability::Representable + } + _ => Representability::Representable, + } +} + +fn representability_adt_ty<'db>( + db: &'db dyn HirDatabase, + def_id: AdtId, + args: GenericArgs<'db>, +) -> Representability { + rtry!(representability(db, def_id)); + + // At this point, we know that the item of the ADT type is representable; + // but the type parameters may cause a cycle with an upstream type + let params_in_repr = params_in_repr(db, def_id); + for (i, arg) in args.iter().enumerate() { + if let GenericArgKind::Type(ty) = arg.kind() + && params_in_repr[i] + { + rtry!(representability_ty(db, ty)); + } + } + Representability::Representable +} + +fn params_in_repr(db: &dyn HirDatabase, def_id: AdtId) -> Box<[bool]> { + let generics = db.generic_params(def_id.into()); + let mut params_in_repr = (0..generics.len_lifetimes() + generics.len_type_or_consts()) + .map(|_| false) + .collect::>(); + let mut handle_variant = |variant| { + for field in db.field_types(variant).values() { + params_in_repr_ty(db, field.get().instantiate_identity(), &mut params_in_repr); + } + }; + match def_id { + AdtId::StructId(def_id) => handle_variant(def_id.into()), + AdtId::UnionId(def_id) => handle_variant(def_id.into()), + AdtId::EnumId(def_id) => { + for &(variant, ..) in &def_id.enum_variants(db).variants { + handle_variant(variant.into()); + } + } + } + params_in_repr +} + +fn params_in_repr_ty<'db>(db: &'db dyn HirDatabase, ty: Ty<'db>, params_in_repr: &mut [bool]) { + match ty.kind() { + TyKind::Adt(adt, args) => { + let inner_params_in_repr = self::params_in_repr(db, adt.def_id().0); + for (i, arg) in args.iter().enumerate() { + if let GenericArgKind::Type(ty) = arg.kind() + && inner_params_in_repr[i] + { + params_in_repr_ty(db, ty, params_in_repr); + } + } + } + TyKind::Array(ty, _) => params_in_repr_ty(db, ty, params_in_repr), + TyKind::Tuple(tys) => tys.iter().for_each(|ty| params_in_repr_ty(db, ty, params_in_repr)), + TyKind::Param(param) => { + params_in_repr[param.index as usize] = true; + } + _ => {} + } +} 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 5291bf80e8219..658c304aac012 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 @@ -2770,3 +2770,28 @@ unsafe extern "C" { "#, ); } + +#[test] +fn infinitely_sized_type() { + check_infer( + r#" +//- minicore: sized + +pub struct Recursive { + pub content: Recursive, +} + +fn is_sized() {} + +fn foo() { + is_sized::(); +} + "#, + expect![[r#" + 79..81 '{}': () + 92..124 '{ ...>(); }': () + 98..119 'is_siz...rsive>': fn is_sized() + 98..121 'is_siz...ive>()': () + "#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs index 148300deb875f..be64f55ea550e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs @@ -1,28 +1,19 @@ //! Helper functions for working with def, which don't need to be a separate //! query, but can't be computed directly from `*Data` (ie, which need a `db`). -use std::cell::LazyCell; - use base_db::target::{self, TargetData}; use hir_def::{ - EnumId, EnumVariantId, FunctionId, Lookup, TraitId, - attrs::AttrFlags, - db::DefDatabase, - hir::generics::WherePredicate, - lang_item::LangItems, - resolver::{HasResolver, TypeNs}, - type_ref::{TraitBoundModifier, TypeRef}, + EnumId, EnumVariantId, FunctionId, Lookup, TraitId, attrs::AttrFlags, lang_item::LangItems, }; use intern::sym; use rustc_abi::TargetDataLayout; -use smallvec::{SmallVec, smallvec}; use span::Edition; use crate::{ TargetFeatures, db::HirDatabase, layout::{Layout, TagEncoding}, - lower::all_supertraits_trait_refs, + lower::SupertraitsInfo, mir::pad16, }; @@ -51,55 +42,13 @@ pub(crate) fn fn_traits(lang_items: &LangItems) -> impl Iterator } /// Returns an iterator over the direct super traits (including the trait itself). -pub fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> SmallVec<[TraitId; 4]> { - let mut result = smallvec![trait_]; - direct_super_traits_cb(db, trait_, |tt| { - if !result.contains(&tt) { - result.push(tt); - } - }); - result -} - -/// Returns an iterator over the whole super trait hierarchy (including the -/// trait itself). -pub fn all_super_traits(db: &dyn HirDatabase, trait_: TraitId) -> SmallVec<[TraitId; 4]> { - let mut supertraits = all_supertraits_trait_refs(db, trait_) - .map(|trait_ref| trait_ref.skip_binder().def_id.0) - .collect::>(); - supertraits.sort_unstable(); - supertraits.dedup(); - supertraits +pub fn direct_super_traits(db: &dyn HirDatabase, trait_: TraitId) -> &[TraitId] { + &SupertraitsInfo::query(db, trait_).direct_supertraits } -fn direct_super_traits_cb(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(TraitId)) { - let resolver = LazyCell::new(|| trait_.resolver(db)); - let (generic_params, store) = db.generic_params_and_store(trait_.into()); - let trait_self = generic_params.trait_self_param(); - generic_params - .where_predicates() - .iter() - .filter_map(|pred| match pred { - WherePredicate::ForLifetime { target, bound, .. } - | WherePredicate::TypeBound { target, bound } => { - let is_trait = match &store[*target] { - TypeRef::Path(p) => p.is_self_type(), - TypeRef::TypeParam(p) => Some(p.local_id()) == trait_self, - _ => false, - }; - match is_trait { - true => bound.as_path(&store), - false => None, - } - } - WherePredicate::Lifetime { .. } => None, - }) - .filter(|(_, bound_modifier)| matches!(bound_modifier, TraitBoundModifier::None)) - .filter_map(|(path, _)| match resolver.resolve_path_in_type_ns_fully(db, path) { - Some(TypeNs::TraitId(t)) => Some(t), - _ => None, - }) - .for_each(cb); +/// Returns the whole super trait hierarchy (including the trait itself). +pub fn all_super_traits(db: &dyn HirDatabase, trait_: TraitId) -> &[TraitId] { + &SupertraitsInfo::query(db, trait_).all_supertraits } #[derive(Debug, Clone, Copy, PartialEq, Eq)] diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 5820a6714b023..9dbee16dae6b7 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -6167,6 +6167,7 @@ impl<'db> Type<'db> { self.autoderef_(db) .filter_map(|ty| ty.dyn_trait()) .flat_map(move |dyn_trait_id| hir_ty::all_super_traits(db, dyn_trait_id)) + .copied() .map(Trait::from) } @@ -6184,6 +6185,7 @@ impl<'db> Type<'db> { _ => None, }) .flat_map(|t| hir_ty::all_super_traits(db, t)) + .copied() }) .map(Trait::from) } 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 65ca1ceae11e9..afdced4215f9f 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 @@ -2534,6 +2534,86 @@ impl Test for () { ${0:todo!()} } } +"#, + ); + } + + #[test] + fn test_param_name_not_qualified() { + check_assist( + add_missing_impl_members, + r#" +mod ptr { + pub struct NonNull(T); +} +mod alloc { + use super::ptr::NonNull; + pub trait Allocator { + unsafe fn deallocate(&self, ptr: NonNull); + } +} + +struct System; + +unsafe impl alloc::Allocator for System { + $0 +} +"#, + r#" +mod ptr { + pub struct NonNull(T); +} +mod alloc { + use super::ptr::NonNull; + pub trait Allocator { + unsafe fn deallocate(&self, ptr: NonNull); + } +} + +struct System; + +unsafe impl alloc::Allocator for System { + unsafe fn deallocate(&self, ptr: ptr::NonNull) { + ${0:todo!()} + } +} +"#, + ); + } + + #[test] + fn test_param_name_shadows_module() { + check_assist( + add_missing_impl_members, + r#" +mod m { } +use m as p; + +pub trait Allocator { + fn deallocate(&self, p: u8); +} + +struct System; + +impl Allocator for System { + $0 +} +"#, + r#" +mod m { } +use m as p; + +pub trait Allocator { + fn deallocate(&self, p: u8); +} + +struct System; + +impl Allocator for System { + fn deallocate(&self, p: u8) { + ${0:todo!()} + } +} "#, ); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs index 91cee59ad8d00..d2c4ed9b5a2c3 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs @@ -102,6 +102,11 @@ pub(crate) fn convert_if_to_bool_then(acc: &mut Assists, ctx: &AssistContext<'_> ast::Expr::BlockExpr(block) => unwrap_trivial_block(block), e => e, }; + let cond = if invert_cond { + invert_boolean_expression(&make, cond) + } else { + cond.clone_for_update() + }; let parenthesize = matches!( cond, @@ -123,11 +128,7 @@ pub(crate) fn convert_if_to_bool_then(acc: &mut Assists, ctx: &AssistContext<'_> | ast::Expr::WhileExpr(_) | ast::Expr::YieldExpr(_) ); - let cond = if invert_cond { - invert_boolean_expression(&make, cond) - } else { - cond.clone_for_update() - }; + let cond = if parenthesize { make.expr_paren(cond).into() } else { cond }; let arg_list = make.arg_list(Some(make.expr_closure(None, closure_body).into())); let mcall = make.expr_method_call(cond, make.name_ref("then"), arg_list); @@ -588,6 +589,25 @@ fn main() { None } } +", + ); + } + #[test] + fn convert_if_to_bool_then_invert_method_call() { + check_assist( + convert_if_to_bool_then, + r" +//- minicore:option +fn main() { + let test = &[()]; + let value = if$0 test.is_empty() { None } else { Some(()) }; +} +", + r" +fn main() { + let test = &[()]; + let value = (!test.is_empty()).then(|| ()); +} ", ); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs index ea5c1637b7608..dc51bf4b5b8c1 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs @@ -934,6 +934,32 @@ fn foo() -> Option { None } +fn main() { + let Some(x) = foo() else { return }; +} +"#, + ); + } + + #[test] + fn convert_let_ref_stmt_inside_fn() { + check_assist( + convert_to_guarded_return, + r#" +//- minicore: option +fn foo() -> &'static Option { + &None +} + +fn main() { + let x$0 = foo(); +} +"#, + r#" +fn foo() -> &'static Option { + &None +} + fn main() { let Some(x) = foo() else { return }; } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs index ded3b0f5acb20..f62eccaf1952e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs @@ -147,7 +147,16 @@ fn gen_method(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { return None; } - let (impl_, file) = get_adt_source(ctx, &adt, fn_name.text().as_str())?; + let enclosing_impl = ctx.find_node_at_offset::(); + let cursor_impl = enclosing_impl.filter(|impl_| { + ctx.sema.to_def(impl_).map_or(false, |def| def.self_ty(ctx.sema.db).as_adt() == Some(adt)) + }); + + let (impl_, file) = if let Some(impl_) = cursor_impl { + (Some(impl_), ctx.vfs_file_id()) + } else { + get_adt_source(ctx, &adt, fn_name.text().as_str())? + }; let target = get_method_target(ctx, &impl_, &adt)?; let function_builder = FunctionBuilder::from_method_call( @@ -3206,4 +3215,44 @@ fn bar(arg: impl Fn(_) -> bool) { "#, ); } + #[test] + fn generate_method_uses_current_impl_block() { + check_assist( + generate_function, + r" +struct Foo; + +impl Foo { + fn new() -> Self { + Foo + } +} + +impl Foo { + fn method1(&self) { + self.method2$0(42) + } +} +", + r" +struct Foo; + +impl Foo { + fn new() -> Self { + Foo + } +} + +impl Foo { + fn method1(&self) { + self.method2(42) + } + + fn method2(&self, arg: i32) { + ${0:todo!()} + } +} +", + ) + } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs index 51b967437b568..92a654743b580 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs @@ -11,7 +11,7 @@ use syntax::{ use crate::{ AssistContext, AssistId, Assists, GroupLabel, - utils::{convert_reference_type, find_struct_impl}, + utils::{convert_reference_type, find_struct_impl, is_selected}, }; // Assist: generate_setter @@ -377,7 +377,7 @@ fn extract_and_parse_record_fields( let info_of_record_fields_in_selection = ele .fields() .filter_map(|record_field| { - if selection_range.contains_range(record_field.syntax().text_range()) { + if is_selected(&record_field, selection_range, false) { let record_field_info = parse_record_field(record_field, assist_type)?; field_names.push(record_field_info.fn_name.clone()); return Some(record_field_info); @@ -934,6 +934,37 @@ struct Context { count: usize, } +impl Context { + fn data(&self) -> &Data { + &self.data + } + + fn $0count(&self) -> &usize { + &self.count + } +} + "#, + ); + } + + #[test] + fn test_generate_multiple_getters_from_partial_selection() { + check_assist( + generate_getter, + r#" +struct Context { + data$0: Data, + count$0: usize, + other: usize, +} + "#, + r#" +struct Context { + data: Data, + count: usize, + other: usize, +} + impl Context { fn data(&self) -> &Data { &self.data diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs index 915dd3ffcaf0c..d2452f28c4d78 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs @@ -849,6 +849,31 @@ fn foo(x: Option) { ); } + #[test] + fn special_case_option_ref() { + check_assist( + replace_if_let_with_match, + r#" +//- minicore: option +fn foo(x: &Option) { + $0if let Some(x) = x { + println!("{}", x) + } else { + println!("none") + } +} +"#, + r#" +fn foo(x: &Option) { + match x { + Some(x) => println!("{}", x), + None => println!("none"), + } +} +"#, + ); + } + #[test] fn special_case_inverted_option() { check_assist( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs index 5a2307739cff5..d22e951b5dab0 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs @@ -1,6 +1,6 @@ use either::Either; use ide_db::syntax_helpers::suggest_name; -use syntax::ast::{self, AstNode, syntax_factory::SyntaxFactory}; +use syntax::ast::{self, AstNode, HasArgList, syntax_factory::SyntaxFactory}; use crate::{AssistContext, AssistId, Assists, utils::cover_let_chain}; @@ -34,8 +34,9 @@ pub(crate) fn replace_is_method_with_if_let_method( _ => return None, }; - let name_ref = call_expr.name_ref()?; - match name_ref.text().as_str() { + let token = call_expr.name_ref()?.ident_token()?; + let method_kind = token.text().strip_suffix("_and").unwrap_or(token.text()); + match method_kind { "is_some" | "is_ok" => { let receiver = call_expr.receiver()?; @@ -47,8 +48,9 @@ pub(crate) fn replace_is_method_with_if_let_method( } else { name_generator.for_variable(&receiver, &ctx.sema) }; + let (pat, predicate) = method_predicate(&call_expr).unzip(); - let (assist_id, message, text) = if name_ref.text() == "is_some" { + let (assist_id, message, text) = if method_kind == "is_some" { ("replace_is_some_with_if_let_some", "Replace `is_some` with `let Some`", "Some") } else { ("replace_is_ok_with_if_let_ok", "Replace `is_ok` with `let Ok`", "Ok") @@ -62,19 +64,29 @@ pub(crate) fn replace_is_method_with_if_let_method( let make = SyntaxFactory::with_mappings(); let mut editor = edit.make_editor(call_expr.syntax()); - let var_pat = make.ident_pat(false, false, make.name(&var_name)); - let pat = make.tuple_struct_pat(make.ident_path(text), [var_pat.into()]); - let let_expr = make.expr_let(pat.into(), receiver); + let var_pat = pat.unwrap_or_else(|| { + make.ident_pat(false, false, make.name(&var_name)).into() + }); + let pat = make.tuple_struct_pat(make.ident_path(text), [var_pat]).into(); + let let_expr = make.expr_let(pat, receiver); if let Some(cap) = ctx.config.snippet_cap && let Some(ast::Pat::TupleStructPat(pat)) = let_expr.pat() && let Some(first_var) = pat.fields().next() + && predicate.is_none() { let placeholder = edit.make_placeholder_snippet(cap); editor.add_annotation(first_var.syntax(), placeholder); } - editor.replace(call_expr.syntax(), let_expr.syntax()); + let new_expr = if let Some(predicate) = predicate { + let op = ast::BinaryOp::LogicOp(ast::LogicOp::And); + make.expr_bin(let_expr.into(), op, predicate).into() + } else { + ast::Expr::from(let_expr) + }; + editor.replace(call_expr.syntax(), new_expr.syntax()); + editor.add_mappings(make.finish_with_mappings()); edit.add_file_edits(ctx.vfs_file_id(), editor); }, @@ -84,6 +96,17 @@ pub(crate) fn replace_is_method_with_if_let_method( } } +fn method_predicate(call_expr: &ast::MethodCallExpr) -> Option<(ast::Pat, ast::Expr)> { + let argument = call_expr.arg_list()?.args().next()?; + match argument { + ast::Expr::ClosureExpr(it) => { + let pat = it.param_list()?.params().next()?.pat()?; + Some((pat, it.body()?)) + } + _ => None, + } +} + #[cfg(test)] mod tests { use crate::tests::{check_assist, check_assist_not_applicable}; @@ -194,6 +217,25 @@ fn main() { ); } + #[test] + fn replace_is_some_and_with_if_let_chain_some_works() { + check_assist( + replace_is_method_with_if_let_method, + r#" +fn main() { + let x = Some(1); + if x.is_som$0e_and(|it| it != 3) {} +} +"#, + r#" +fn main() { + let x = Some(1); + if let Some(it) = x && it != 3 {} +} +"#, + ); + } + #[test] fn replace_is_some_with_if_let_some_in_let_chain() { check_assist( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_let_with_if_let.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_let_with_if_let.rs index 15977c420e642..5587f1b59c542 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_let_with_if_let.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_let_with_if_let.rs @@ -101,6 +101,29 @@ mod tests { use super::*; + #[test] + fn replace_let_try_enum_ref() { + check_assist( + replace_let_with_if_let, + r" +//- minicore: option +fn main(action: Action) { + $0let x = compute(); +} + +fn compute() -> &'static Option { &None } + ", + r" +fn main(action: Action) { + if let Some(x) = compute() { + } +} + +fn compute() -> &'static Option { &None } + ", + ) + } + #[test] fn replace_let_unknown_enum() { check_assist( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_macro_delimiter.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_macro_delimiter.rs index 60b0797f028a9..15143575e7d84 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_macro_delimiter.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_macro_delimiter.rs @@ -1,6 +1,7 @@ use ide_db::assists::AssistId; use syntax::{ - AstNode, SyntaxToken, T, + AstNode, SyntaxKind, SyntaxToken, T, + algo::{previous_non_trivia_token, skip_trivia_token}, ast::{self, syntax_factory::SyntaxFactory}, }; @@ -36,15 +37,18 @@ pub(crate) fn toggle_macro_delimiter(acc: &mut Assists, ctx: &AssistContext<'_>) RCur, } - let makro = ctx.find_node_at_offset::()?; + let token_tree = ctx.find_node_at_offset::()?; let cursor_offset = ctx.offset(); - let semicolon = macro_semicolon(&makro); - let token_tree = makro.token_tree()?; + let semicolon = macro_semicolon(&token_tree); let ltoken = token_tree.left_delimiter_token()?; let rtoken = token_tree.right_delimiter_token()?; + if !is_macro_call(&token_tree)? { + return None; + } + if !ltoken.text_range().contains(cursor_offset) && !rtoken.text_range().contains(cursor_offset) { return None; @@ -70,7 +74,7 @@ pub(crate) fn toggle_macro_delimiter(acc: &mut Assists, ctx: &AssistContext<'_>) token_tree.syntax().text_range(), |builder| { let make = SyntaxFactory::with_mappings(); - let mut editor = builder.make_editor(makro.syntax()); + let mut editor = builder.make_editor(token_tree.syntax()); match token { MacroDelims::LPar | MacroDelims::RPar => { @@ -102,12 +106,21 @@ pub(crate) fn toggle_macro_delimiter(acc: &mut Assists, ctx: &AssistContext<'_>) ) } -fn macro_semicolon(makro: &ast::MacroCall) -> Option { - makro.semicolon_token().or_else(|| { - let macro_expr = ast::MacroExpr::cast(makro.syntax().parent()?)?; - let expr_stmt = ast::ExprStmt::cast(macro_expr.syntax().parent()?)?; - expr_stmt.semicolon_token() - }) +fn is_macro_call(token_tree: &ast::TokenTree) -> Option { + let parent = token_tree.syntax().parent()?; + if ast::MacroCall::can_cast(parent.kind()) { + return Some(true); + } + + let token_tree = ast::TokenTree::cast(parent)?; + let prev = previous_non_trivia_token(token_tree.syntax().clone())?; + let prev_prev = previous_non_trivia_token(prev.clone())?; + Some(prev.kind() == T![!] && prev_prev.kind() == SyntaxKind::IDENT) +} + +fn macro_semicolon(token_tree: &ast::TokenTree) -> Option { + let next_token = token_tree.syntax().last_token()?.next_token()?; + skip_trivia_token(next_token, syntax::Direction::Next).filter(|it| it.kind() == T![;]) } fn needs_semicolon(tt: ast::TokenTree) -> bool { @@ -402,10 +415,9 @@ prt!{(3 + 5)} ) } - // FIXME @alibektas : Inner macro_call is not seen as such. So this doesn't work. #[test] fn test_nested_macros() { - check_assist_not_applicable( + check_assist( toggle_macro_delimiter, r#" macro_rules! prt { @@ -420,7 +432,22 @@ macro_rules! abc { }}; } -prt!{abc!($03 + 5)}; +prt!{abc!$0(3 + 5)}; +"#, + r#" +macro_rules! prt { + ($e:expr) => {{ + println!("{}", stringify!{$e}); + }}; +} + +macro_rules! abc { + ($e:expr) => {{ + println!("{}", stringify!{$e}); + }}; +} + +prt!{abc!{3 + 5}}; "#, ) } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs index 34d25c9c67283..96dac66b8a199 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs @@ -4,9 +4,9 @@ use hir::HirDisplay; use ide_db::FxHashMap; use itertools::Either; use syntax::{ - AstNode, Direction, SyntaxKind, TextRange, TextSize, algo, + AstNode, Direction, SmolStr, SyntaxKind, TextRange, TextSize, ToSmolStr, algo, ast::{self, HasModuleItem}, - match_ast, + format_smolstr, match_ast, }; use crate::{ @@ -25,7 +25,7 @@ pub(crate) fn complete_fn_param( ctx: &CompletionContext<'_>, pattern_ctx: &PatternContext, ) -> Option<()> { - let (ParamContext { param_list, kind, .. }, impl_or_trait) = match pattern_ctx { + let (ParamContext { param_list, kind, param, .. }, impl_or_trait) = match pattern_ctx { PatternContext { param_ctx: Some(kind), impl_or_trait, .. } => (kind, impl_or_trait), _ => return None, }; @@ -46,13 +46,18 @@ pub(crate) fn complete_fn_param( match kind { ParamKind::Function(function) => { - fill_fn_params(ctx, function, param_list, impl_or_trait, add_new_item_to_acc); + fill_fn_params(ctx, function, param_list, param, impl_or_trait, add_new_item_to_acc); } ParamKind::Closure(closure) => { - let stmt_list = closure.syntax().ancestors().find_map(ast::StmtList::cast)?; - params_from_stmt_list_scope(ctx, stmt_list, |name, ty| { - add_new_item_to_acc(&format!("{}: {ty}", name.display(ctx.db, ctx.edition))); - }); + if is_simple_param(param) { + let stmt_list = closure.syntax().ancestors().find_map(ast::StmtList::cast)?; + params_from_stmt_list_scope(ctx, stmt_list, |name, ty| { + add_new_item_to_acc(&format_smolstr!( + "{}: {ty}", + name.display(ctx.db, ctx.edition) + )); + }); + } } } @@ -63,17 +68,20 @@ fn fill_fn_params( ctx: &CompletionContext<'_>, function: &ast::Fn, param_list: &ast::ParamList, + current_param: &ast::Param, impl_or_trait: &Option>, mut add_new_item_to_acc: impl FnMut(&str), ) { let mut file_params = FxHashMap::default(); let mut extract_params = |f: ast::Fn| { + if !is_simple_param(current_param) { + return; + } f.param_list().into_iter().flat_map(|it| it.params()).for_each(|param| { if let Some(pat) = param.pat() { - // FIXME: We should be able to turn these into SmolStr without having to allocate a String - let whole_param = param.syntax().text().to_string(); - let binding = pat.syntax().text().to_string(); + let whole_param = param.to_smolstr(); + let binding = pat.to_smolstr(); file_params.entry(whole_param).or_insert(binding); } }); @@ -99,11 +107,13 @@ fn fill_fn_params( }; } - if let Some(stmt_list) = function.syntax().parent().and_then(ast::StmtList::cast) { + if let Some(stmt_list) = function.syntax().parent().and_then(ast::StmtList::cast) + && is_simple_param(current_param) + { params_from_stmt_list_scope(ctx, stmt_list, |name, ty| { file_params - .entry(format!("{}: {ty}", name.display(ctx.db, ctx.edition))) - .or_insert(name.display(ctx.db, ctx.edition).to_string()); + .entry(format_smolstr!("{}: {ty}", name.display(ctx.db, ctx.edition))) + .or_insert(name.display(ctx.db, ctx.edition).to_smolstr()); }); } remove_duplicated(&mut file_params, param_list.params()); @@ -139,11 +149,11 @@ fn params_from_stmt_list_scope( } fn remove_duplicated( - file_params: &mut FxHashMap, + file_params: &mut FxHashMap, fn_params: ast::AstChildren, ) { fn_params.for_each(|param| { - let whole_param = param.syntax().text().to_string(); + let whole_param = param.to_smolstr(); file_params.remove(&whole_param); match param.pat() { @@ -151,7 +161,7 @@ fn remove_duplicated( // if the type is missing we are checking the current param to be completed // in which case this would find itself removing the suggestions due to itself Some(pattern) if param.ty().is_some() => { - let binding = pattern.syntax().text().to_string(); + let binding = pattern.to_smolstr(); file_params.retain(|_, v| v != &binding); } _ => (), @@ -173,7 +183,7 @@ fn should_add_self_completions( } } -fn comma_wrapper(ctx: &CompletionContext<'_>) -> Option<(impl Fn(&str) -> String, TextRange)> { +fn comma_wrapper(ctx: &CompletionContext<'_>) -> Option<(impl Fn(&str) -> SmolStr, TextRange)> { let param = ctx.original_token.parent_ancestors().find(|node| node.kind() == SyntaxKind::PARAM)?; @@ -196,5 +206,11 @@ fn comma_wrapper(ctx: &CompletionContext<'_>) -> Option<(impl Fn(&str) -> String matches!(prev_token_kind, SyntaxKind::COMMA | SyntaxKind::L_PAREN | SyntaxKind::PIPE); let leading = if has_leading_comma { "" } else { ", " }; - Some((move |label: &_| format!("{leading}{label}{trailing}"), param.text_range())) + Some((move |label: &_| format_smolstr!("{leading}{label}{trailing}"), param.text_range())) +} + +fn is_simple_param(param: &ast::Param) -> bool { + param + .pat() + .is_none_or(|pat| matches!(pat, ast::Pat::IdentPat(ident_pat) if ident_pat.pat().is_none())) } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs index cffc44f8afb33..a58592b1365b8 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs @@ -16,7 +16,7 @@ use itertools::Itertools; use stdx::never; use syntax::{ SmolStr, - SyntaxKind::{EXPR_STMT, STMT_LIST}, + SyntaxKind::{BLOCK_EXPR, EXPR_STMT, STMT_LIST}, T, TextRange, TextSize, ToSmolStr, ast::{self, AstNode, AstToken}, format_smolstr, match_ast, @@ -91,8 +91,7 @@ pub(crate) fn complete_postfix( // so it's better to consider references now to avoid breaking the compilation let (dot_receiver_including_refs, prefix) = include_references(dot_receiver); - let mut receiver_text = - get_receiver_text(&ctx.sema, dot_receiver, receiver_is_ambiguous_float_literal); + let mut receiver_text = receiver_text; receiver_text.insert_str(0, &prefix); let postfix_snippet = match build_postfix_snippet_builder(ctx, cap, &dot_receiver_including_refs) { @@ -111,7 +110,7 @@ pub(crate) fn complete_postfix( postfix_snippet("call", "function(expr)", &format!("${{1}}({receiver_text})")) .add_to(acc, ctx.db); - let try_enum = TryEnum::from_ty(&ctx.sema, &receiver_ty.strip_references()); + let try_enum = TryEnum::from_ty(&ctx.sema, receiver_ty); let mut is_in_cond = false; if let Some(parent) = dot_receiver_including_refs.syntax().parent() && let Some(second_ancestor) = parent.parent() @@ -155,12 +154,26 @@ pub(crate) fn complete_postfix( postfix_snippet("let", "let", &format!("let $1 = {receiver_text}")) .add_to(acc, ctx.db); } - _ if matches!(second_ancestor.kind(), STMT_LIST | EXPR_STMT) => { + _ if matches!(second_ancestor.kind(), STMT_LIST | EXPR_STMT | BLOCK_EXPR) => { postfix_snippet("let", "let", &format!("let $0 = {receiver_text};")) .add_to(acc, ctx.db); postfix_snippet("letm", "let mut", &format!("let mut $0 = {receiver_text};")) .add_to(acc, ctx.db); } + _ if ast::MatchArm::can_cast(second_ancestor.kind()) => { + postfix_snippet( + "let", + "let", + &format!("{{\n let $1 = {receiver_text};\n $0\n}}"), + ) + .add_to(acc, ctx.db); + postfix_snippet( + "letm", + "let mut", + &format!("{{\n let mut $1 = {receiver_text};\n $0\n}}"), + ) + .add_to(acc, ctx.db); + } _ => (), } } @@ -652,6 +665,87 @@ fn main() { baz.l$0 res } +"#, + expect![[r#" + sn box Box::new(expr) + sn call function(expr) + sn const const {} + sn dbg dbg!(expr) + sn dbgr dbg!(&expr) + sn deref *expr + sn if if expr {} + sn let let + sn letm let mut + sn match match expr {} + sn not !expr + sn ref &expr + sn refm &mut expr + sn return return expr + sn unsafe unsafe {} + sn while while expr {} + "#]], + ); + check( + r#" +fn main() { + &baz.l$0 + res +} +"#, + expect![[r#" + sn box Box::new(expr) + sn call function(expr) + sn const const {} + sn dbg dbg!(expr) + sn dbgr dbg!(&expr) + sn deref *expr + sn if if expr {} + sn let let + sn letm let mut + sn match match expr {} + sn not !expr + sn ref &expr + sn refm &mut expr + sn return return expr + sn unsafe unsafe {} + sn while while expr {} + "#]], + ); + } + + #[test] + fn let_tail_block() { + check( + r#" +fn main() { + baz.l$0 +} +"#, + expect![[r#" + sn box Box::new(expr) + sn call function(expr) + sn const const {} + sn dbg dbg!(expr) + sn dbgr dbg!(&expr) + sn deref *expr + sn if if expr {} + sn let let + sn letm let mut + sn match match expr {} + sn not !expr + sn ref &expr + sn refm &mut expr + sn return return expr + sn unsafe unsafe {} + sn while while expr {} + "#]], + ); + + check( + r#" +fn main() { + &baz.l$0 +} "#, expect![[r#" sn box Box::new(expr) @@ -795,6 +889,54 @@ fn main() { ); } + #[test] + fn match_arm_let_block() { + check( + r#" +fn main() { + match 2 { + bar => bar.$0 + } +} +"#, + expect![[r#" + sn box Box::new(expr) + sn call function(expr) + sn const const {} + sn dbg dbg!(expr) + sn dbgr dbg!(&expr) + sn deref *expr + sn let let + sn letm let mut + sn match match expr {} + sn ref &expr + sn refm &mut expr + sn return return expr + sn unsafe unsafe {} + "#]], + ); + check_edit( + "let", + r#" +fn main() { + match 2 { + bar => bar.$0 + } +} +"#, + r#" +fn main() { + match 2 { + bar => { + let $1 = bar; + $0 +} + } +} +"#, + ); + } + #[test] fn option_letelse() { check_edit( diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs index 1c8bc656ca251..4b0cc0c7cd98e 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs @@ -1501,7 +1501,7 @@ fn classify_name_ref<'db>( | SyntaxKind::RECORD_FIELD ) }) - .and_then(|_| nameref.as_ref()?.syntax().ancestors().find_map(ast::Adt::cast)) + .and_then(|_| find_node_at_offset::(original_file, original_offset)) .and_then(|adt| sema.derive_helpers_in_scope(&adt)) .unwrap_or_default(); Some(PathKind::Attr { attr_ctx: AttrCtx { kind, annotated_item_kind, derive_helpers } }) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs index 3701416dfc849..131911be91558 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs @@ -68,7 +68,71 @@ pub struct Foo(#[m$0] i32); kw crate:: kw self:: "#]], - ) + ); + check( + r#" +//- /mac.rs crate:mac +#![crate_type = "proc-macro"] + +#[proc_macro_derive(MyDerive, attributes(my_cool_helper_attribute))] +pub fn my_derive() {} + +//- /lib.rs crate:lib deps:mac +#[rustc_builtin_macro] +pub macro derive($item:item) {} + +#[derive(mac::MyDerive)] +pub struct Foo(#[$0] i32); +"#, + expect![[r#" + at allow(…) + at automatically_derived + at cfg(…) + at cfg_attr(…) + at cold + at deny(…) + at deprecated + at derive macro derive + at derive(…) + at diagnostic::do_not_recommend + at diagnostic::on_unimplemented + at doc = "…" + at doc = include_str!("…") + at doc(alias = "…") + at doc(hidden) + at expect(…) + at export_name = "…" + at forbid(…) + at global_allocator + at ignore = "…" + at inline + at link + at link_name = "…" + at link_section = "…" + at macro_export + at macro_use + at must_use + at my_cool_helper_attribute derive helper of `MyDerive` + at no_mangle + at non_exhaustive + at panic_handler + at path = "…" + at proc_macro + at proc_macro_attribute + at proc_macro_derive(…) + at repr(…) + at should_panic + at target_feature(enable = "…") + at test + at track_caller + at unsafe(…) + at used + at warn(…) + md mac + kw crate:: + kw self:: + "#]], + ); } #[test] diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs index df39591a33460..5fef8c44deb12 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs @@ -3268,6 +3268,8 @@ fn foo() { sn dbg dbg!(expr) sn dbgr dbg!(&expr) sn deref *expr + sn let let + sn letm let mut sn match match expr {} sn ref &expr sn refm &mut expr diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/fn_param.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/fn_param.rs index 02cba6b6467e5..d6d73da3f140b 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/fn_param.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/fn_param.rs @@ -292,6 +292,60 @@ fn bar(bar$0) {} ) } +#[test] +fn not_shows_fully_equal_inside_pattern_params() { + check( + r#" +fn foo(bar: u32) {} +fn bar((a, bar$0)) {} +"#, + expect![[r#" + kw mut + kw ref + "#]], + ) +} + +#[test] +fn not_shows_locals_inside_pattern_params() { + check( + r#" +fn outer() { + let foo = 3; + { + let bar = 3; + |($0)| {}; + let baz = 3; + let qux = 3; + } + let fez = 3; +} +"#, + expect![[r#" + kw mut + kw ref + "#]], + ); + check( + r#" +fn outer() { + let foo = 3; + { + let bar = 3; + fn inner(($0)) {} + let baz = 3; + let qux = 3; + } + let fez = 3; +} +"#, + expect![[r#" + kw mut + kw ref + "#]], + ); +} + #[test] fn completes_for_params_with_attributes() { check( diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs index f26952fa1535d..da8525d1fb72b 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs @@ -94,7 +94,7 @@ impl ImportScope { .item_list() .map(ImportScopeKind::Module) .map(|kind| ImportScope { kind, required_cfgs }); - } else if let Some(has_attrs) = ast::AnyHasAttrs::cast(syntax) { + } else if let Some(has_attrs) = ast::AnyHasAttrs::cast(syntax.clone()) { if block.is_none() && let Some(b) = ast::BlockExpr::cast(has_attrs.syntax().clone()) && let Some(b) = sema.original_ast_node(b) @@ -105,11 +105,34 @@ impl ImportScope { .attrs() .any(|attr| attr.as_simple_call().is_some_and(|(ident, _)| ident == "cfg")) { - if let Some(b) = block { - return Some(ImportScope { - kind: ImportScopeKind::Block(b), - required_cfgs, + if let Some(b) = block.clone() { + let current_cfgs = has_attrs.attrs().filter(|attr| { + attr.as_simple_call().is_some_and(|(ident, _)| ident == "cfg") }); + + let total_cfgs: Vec<_> = + required_cfgs.iter().cloned().chain(current_cfgs).collect(); + + let parent = syntax.parent(); + let mut can_merge = false; + if let Some(parent) = parent { + can_merge = parent.children().filter_map(ast::Use::cast).any(|u| { + let u_attrs = u.attrs().filter(|attr| { + attr.as_simple_call().is_some_and(|(ident, _)| ident == "cfg") + }); + crate::imports::merge_imports::eq_attrs( + u_attrs, + total_cfgs.iter().cloned(), + ) + }); + } + + if !can_merge { + return Some(ImportScope { + kind: ImportScopeKind::Block(b), + required_cfgs, + }); + } } required_cfgs.extend(has_attrs.attrs().filter(|attr| { attr.as_simple_call().is_some_and(|(ident, _)| ident == "cfg") @@ -546,7 +569,9 @@ fn insert_use_(scope: &ImportScope, use_item: ast::Use, group_imports: bool) { // skip the curly brace .skip(l_curly.is_some() as usize) .take_while(|child| match child { - NodeOrToken::Node(node) => is_inner_attribute(node.clone()), + NodeOrToken::Node(node) => { + is_inner_attribute(node.clone()) && ast::Item::cast(node.clone()).is_none() + } NodeOrToken::Token(token) => { [SyntaxKind::WHITESPACE, SyntaxKind::COMMENT, SyntaxKind::SHEBANG] .contains(&token.kind()) @@ -667,7 +692,9 @@ fn insert_use_with_editor_( // skip the curly brace .skip(l_curly.is_some() as usize) .take_while(|child| match child { - NodeOrToken::Node(node) => is_inner_attribute(node.clone()), + NodeOrToken::Node(node) => { + is_inner_attribute(node.clone()) && ast::Item::cast(node.clone()).is_none() + } NodeOrToken::Token(token) => { [SyntaxKind::WHITESPACE, SyntaxKind::COMMENT, SyntaxKind::SHEBANG] .contains(&token.kind()) diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs index 3350e1c3d207f..6c7b97458d208 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs @@ -1438,3 +1438,156 @@ fn check_guess(#[rust_analyzer::rust_fixture] ra_fixture: &str, expected: Import let file = ImportScope { kind: ImportScopeKind::File(syntax), required_cfgs: vec![] }; assert_eq!(super::guess_granularity_from_scope(&file), expected); } + +#[test] +fn insert_with_existing_imports_and_cfg_module() { + check( + "std::fmt", + r#" +use foo::bar; + +#[cfg(target_arch = "x86_64")] +pub mod api; +"#, + r#" +use std::fmt; + +use foo::bar; + +#[cfg(target_arch = "x86_64")] +pub mod api; +"#, + ImportGranularity::Crate, + ); +} + +#[test] +fn insert_before_cfg_module() { + check( + "std::fmt", + r#" +#[cfg(target_arch = "x86_64")] +pub mod api; +"#, + r#" +use std::fmt; + +#[cfg(target_arch = "x86_64")] +pub mod api; +"#, + ImportGranularity::Crate, + ); +} + +fn check_merge(ra_fixture0: &str, ra_fixture1: &str, last: &str, mb: MergeBehavior) { + let use0 = ast::SourceFile::parse(ra_fixture0, span::Edition::CURRENT) + .tree() + .syntax() + .descendants() + .find_map(ast::Use::cast) + .unwrap(); + + let use1 = ast::SourceFile::parse(ra_fixture1, span::Edition::CURRENT) + .tree() + .syntax() + .descendants() + .find_map(ast::Use::cast) + .unwrap(); + + let result = try_merge_imports(&use0, &use1, mb); + assert_eq!(result.map(|u| u.to_string().trim().to_owned()), Some(last.trim().to_owned())); +} + +#[test] +fn merge_gated_imports() { + check_merge( + r#"#[cfg(test)] use foo::bar;"#, + r#"#[cfg(test)] use foo::baz;"#, + r#"#[cfg(test)] use foo::{bar, baz};"#, + MergeBehavior::Crate, + ); +} + +#[test] +fn merge_gated_imports_with_different_values() { + let use0 = ast::SourceFile::parse(r#"#[cfg(a)] use foo::bar;"#, span::Edition::CURRENT) + .tree() + .syntax() + .descendants() + .find_map(ast::Use::cast) + .unwrap(); + + let use1 = ast::SourceFile::parse(r#"#[cfg(b)] use foo::baz;"#, span::Edition::CURRENT) + .tree() + .syntax() + .descendants() + .find_map(ast::Use::cast) + .unwrap(); + + let result = try_merge_imports(&use0, &use1, MergeBehavior::Crate); + assert_eq!(result, None); +} + +#[test] +fn merge_gated_imports_different_order() { + check_merge( + r#"#[cfg(a)] #[cfg(b)] use foo::bar;"#, + r#"#[cfg(b)] #[cfg(a)] use foo::baz;"#, + r#"#[cfg(a)] #[cfg(b)] use foo::{bar, baz};"#, + MergeBehavior::Crate, + ); +} + +#[test] +fn merge_into_existing_cfg_import() { + check( + r#"foo::Foo"#, + r#" +#[cfg(target_os = "windows")] +use bar::Baz; + +#[cfg(target_os = "windows")] +fn buzz() { + Foo$0; +} +"#, + r#" +#[cfg(target_os = "windows")] +use bar::Baz; +#[cfg(target_os = "windows")] +use foo::Foo; + +#[cfg(target_os = "windows")] +fn buzz() { + Foo; +} +"#, + ImportGranularity::Crate, + ); +} + +#[test] +fn reproduce_user_issue_missing_semicolon() { + check( + "std::fmt", + r#" +use { + foo +} + +#[cfg(target_arch = "x86_64")] +pub mod api; +"#, + r#" +use std::fmt; + +use { + foo +} + +#[cfg(target_arch = "x86_64")] +pub mod api; +"#, + ImportGranularity::Crate, + ); +} diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs index 635ed7368c4c0..3301719f5ce29 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs @@ -4,7 +4,7 @@ use std::cmp::Ordering; use itertools::{EitherOrBoth, Itertools}; use parser::T; use syntax::{ - Direction, SyntaxElement, algo, + Direction, SyntaxElement, ToSmolStr, algo, ast::{ self, AstNode, HasAttrs, HasName, HasVisibility, PathSegmentKind, edit_in_place::Removable, make, @@ -691,14 +691,12 @@ pub fn eq_attrs( attrs0: impl Iterator, attrs1: impl Iterator, ) -> bool { - // FIXME order of attributes should not matter - let attrs0 = attrs0 - .flat_map(|attr| attr.syntax().descendants_with_tokens()) - .flat_map(|it| it.into_token()); - let attrs1 = attrs1 - .flat_map(|attr| attr.syntax().descendants_with_tokens()) - .flat_map(|it| it.into_token()); - stdx::iter_eq_by(attrs0, attrs1, |tok, tok2| tok.text() == tok2.text()) + let mut attrs0: Vec<_> = attrs0.map(|attr| attr.syntax().text().to_smolstr()).collect(); + let mut attrs1: Vec<_> = attrs1.map(|attr| attr.syntax().text().to_smolstr()).collect(); + attrs0.sort_unstable(); + attrs1.sort_unstable(); + + attrs0 == attrs1 } fn path_is_self(path: &ast::Path) -> bool { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs index 48305c20823c1..01a326a0dc63b 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs @@ -553,6 +553,39 @@ impl Ctx<'_> { return None; } + // Similarly, modules cannot be used in pattern position. + if matches!(def, hir::ModuleDef::Module(_)) { + return None; + } + + if matches!( + def, + hir::ModuleDef::Function(_) + | hir::ModuleDef::Trait(_) + | hir::ModuleDef::TypeAlias(_) + ) { + return None; + } + + if let hir::ModuleDef::Adt(adt) = def { + match adt { + hir::Adt::Struct(s) + if s.kind(self.source_scope.db) != hir::StructKind::Unit => + { + return None; + } + hir::Adt::Union(_) => return None, + hir::Adt::Enum(_) => return None, + _ => (), + } + } + + if let hir::ModuleDef::Variant(v) = def + && v.kind(self.source_scope.db) != hir::StructKind::Unit + { + return None; + } + let cfg = FindPathConfig { prefer_no_std: false, prefer_prelude: true, @@ -632,3 +665,87 @@ fn find_trait_for_assoc_item( None } + +#[cfg(test)] +mod tests { + use crate::RootDatabase; + use crate::path_transform::PathTransform; + use hir::Semantics; + use syntax::{AstNode, ast::HasName}; + use test_fixture::WithFixture; + use test_utils::assert_eq_text; + + #[test] + fn test_transform_ident_pat() { + let (db, file_id) = RootDatabase::with_single_file( + r#" +mod foo { + pub struct UnitStruct; + pub struct RecordStruct {} + pub enum Enum { UnitVariant, RecordVariant {} } + pub fn function() {} + pub const CONST: i32 = 0; + pub static STATIC: i32 = 0; + pub type Alias = i32; + pub union Union { f: i32 } +} + +mod bar { + fn anchor() {} +} + +fn main() { + use foo::*; + use foo::Enum::*; + let UnitStruct = (); + let RecordStruct = (); + let Enum = (); + let UnitVariant = (); + let RecordVariant = (); + let function = (); + let CONST = (); + let STATIC = (); + let Alias = (); + let Union = (); +} +"#, + ); + let sema = Semantics::new(&db); + let source_file = sema.parse(file_id); + + let function = source_file + .syntax() + .descendants() + .filter_map(syntax::ast::Fn::cast) + .find(|it| it.name().unwrap().text() == "main") + .unwrap(); + let source_scope = sema.scope(function.body().unwrap().syntax()).unwrap(); + + let anchor = source_file + .syntax() + .descendants() + .filter_map(syntax::ast::Fn::cast) + .find(|it| it.name().unwrap().text() == "anchor") + .unwrap(); + let target_scope = sema.scope(anchor.body().unwrap().syntax()).unwrap(); + + let transform = PathTransform::generic_transformation(&target_scope, &source_scope); + let transformed = transform.apply(function.body().unwrap().syntax()); + + let expected = r#"{ + use crate::foo::*; + use crate::foo::Enum::*; + let crate::foo::UnitStruct = (); + let RecordStruct = (); + let Enum = (); + let crate::foo::Enum::UnitVariant = (); + let RecordVariant = (); + let function = (); + let crate::foo::CONST = (); + let crate::foo::STATIC = (); + let Alias = (); + let Union = (); +}"#; + assert_eq_text!(expected, &transformed.to_string()); + } +} diff --git a/src/tools/rust-analyzer/crates/ide-db/src/search.rs b/src/tools/rust-analyzer/crates/ide-db/src/search.rs index 1d865892a22b5..4196a13aa3fa7 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs @@ -1370,7 +1370,7 @@ fn is_name_ref_in_import(name_ref: &ast::NameRef) -> bool { } fn is_name_ref_in_test(sema: &Semantics<'_, RootDatabase>, name_ref: &ast::NameRef) -> bool { - name_ref.syntax().ancestors().any(|node| match ast::Fn::cast(node) { + sema.ancestors_with_macros(name_ref.syntax().clone()).any(|node| match ast::Fn::cast(node) { Some(it) => sema.to_def(&it).is_some_and(|func| func.is_test(sema.db)), None => false, }) diff --git a/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs b/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs index 095256d8294e2..b5c43b3b369bb 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs @@ -19,8 +19,16 @@ pub enum TryEnum { impl TryEnum { const ALL: [TryEnum; 2] = [TryEnum::Option, TryEnum::Result]; - /// Returns `Some(..)` if the provided type is an enum that implements `std::ops::Try`. + /// Returns `Some(..)` if the provided `ty.strip_references()` is an enum that implements `std::ops::Try`. pub fn from_ty(sema: &Semantics<'_, RootDatabase>, ty: &hir::Type<'_>) -> Option { + Self::from_ty_without_strip(sema, &ty.strip_references()) + } + + /// Returns `Some(..)` if the provided type is an enum that implements `std::ops::Try`. + pub fn from_ty_without_strip( + sema: &Semantics<'_, RootDatabase>, + ty: &hir::Type<'_>, + ) -> Option { let enum_ = match ty.as_adt() { Some(hir::Adt::Enum(it)) => it, _ => return None, diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs index 38ee09703398b..102eb91b74f76 100644 --- a/src/tools/rust-analyzer/crates/ide/src/references.rs +++ b/src/tools/rust-analyzer/crates/ide/src/references.rs @@ -513,26 +513,32 @@ fn test() { } #[test] - fn test_access() { + fn exclude_tests_macro_refs() { check( r#" -struct S { f$0: u32 } +macro_rules! my_macro { + ($e:expr) => { $e }; +} + +fn foo$0() -> i32 { 42 } + +fn bar() { + foo(); +} #[test] -fn test() { - let mut x = S { f: 92 }; - x.f = 92; +fn t2() { + my_macro!(foo()); } "#, expect![[r#" - f Field FileId(0) 11..17 11..12 + foo Function FileId(0) 52..74 55..58 - FileId(0) 61..62 read test - FileId(0) 76..77 write test + FileId(0) 91..94 + FileId(0) 133..136 test "#]], ); } - #[test] fn test_struct_literal_after_space() { check( diff --git a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs index f86974b4ec76c..9ab07565e9efc 100644 --- a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs +++ b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs @@ -1975,8 +1975,8 @@ trait Sub: Super + Super { fn f() -> impl Sub<$0 "#, expect![[r#" - trait Sub - ^^^^^^^^^^^ --------- + trait Sub + ^^^^^^^^^ ----------- "#]], ); } diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs index 70a00cf825162..654ff4f75b0e6 100644 --- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs +++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs @@ -612,6 +612,53 @@ impl ProcMacroExpander for Expander { Ok(SubResponse::ByteRangeResult { range: range.range.into() }) } + SubRequest::SpanSource { file_id, ast_id, start, end, ctx } => { + let span = Span { + range: TextRange::new(TextSize::from(start), TextSize::from(end)), + anchor: SpanAnchor { + file_id: span::EditionedFileId::from_raw(file_id), + ast_id: span::ErasedFileAstId::from_raw(ast_id), + }, + // SAFETY: We only receive spans from the server. If someone mess up the communication UB can happen, + // but that will be their problem. + ctx: unsafe { SyntaxContext::from_u32(ctx) }, + }; + + let mut current_span = span; + let mut current_ctx = span.ctx; + + while let Some(macro_call_id) = current_ctx.outer_expn(db) { + let macro_call_loc = db.lookup_intern_macro_call(macro_call_id.into()); + + let call_site_file = macro_call_loc.kind.file_id(); + + let resolved = db.resolve_span(current_span); + + current_ctx = macro_call_loc.ctxt; + current_span = Span { + range: resolved.range, + anchor: SpanAnchor { + file_id: resolved.file_id.editioned_file_id(db), + ast_id: span::ROOT_ERASED_FILE_AST_ID, + }, + ctx: current_ctx, + }; + + if call_site_file.file_id().is_some() { + break; + } + } + + let resolved = db.resolve_span(current_span); + + Ok(SubResponse::SpanSourceResult { + file_id: resolved.file_id.editioned_file_id(db).as_u32(), + ast_id: span::ROOT_ERASED_FILE_AST_ID.into_raw(), + start: u32::from(resolved.range.start()), + end: u32::from(resolved.range.end()), + ctx: current_span.ctx.into_u32(), + }) + } }; match self.0.expand( subtree.view(), 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 3f0422dc5bc83..10a8d66677ac4 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 @@ -21,6 +21,7 @@ pub enum SubRequest { LocalFilePath { file_id: u32 }, LineColumn { file_id: u32, ast_id: u32, offset: u32 }, ByteRange { file_id: u32, ast_id: u32, start: u32, end: u32 }, + SpanSource { file_id: u32, ast_id: u32, start: u32, end: u32, ctx: u32 }, } #[derive(Debug, Serialize, Deserialize)] @@ -42,6 +43,13 @@ pub enum SubResponse { ByteRangeResult { range: Range, }, + SpanSourceResult { + file_id: u32, + ast_id: u32, + start: u32, + end: u32, + ctx: u32, + }, Cancel { reason: String, }, diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs index 9be3199a3836a..2c54b18077bb0 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs @@ -273,6 +273,42 @@ impl proc_macro_srv::ProcMacroClientInterface for ProcMacroClientHandle<'_> { other => handle_failure(other), } } + + fn span_source( + &mut self, + proc_macro_srv::span::Span { range, anchor, ctx }: proc_macro_srv::span::Span, + ) -> proc_macro_srv::span::Span { + match self.roundtrip(bidirectional::SubRequest::SpanSource { + file_id: anchor.file_id.as_u32(), + ast_id: anchor.ast_id.into_raw(), + start: range.start().into(), + end: range.end().into(), + ctx: ctx.into_u32(), + }) { + Ok(bidirectional::SubResponse::SpanSourceResult { + file_id, + ast_id, + start, + end, + ctx, + }) => { + proc_macro_srv::span::Span { + range: proc_macro_srv::span::TextRange::new( + proc_macro_srv::span::TextSize::new(start), + proc_macro_srv::span::TextSize::new(end), + ), + anchor: proc_macro_srv::span::SpanAnchor { + file_id: proc_macro_srv::span::EditionedFileId::from_raw(file_id), + ast_id: proc_macro_srv::span::ErasedFileAstId::from_raw(ast_id), + }, + // SAFETY: We only receive spans from the server. If someone mess up the communication UB can happen, + // but that will be their problem. + ctx: unsafe { proc_macro_srv::span::SyntaxContext::from_u32(ctx) }, + } + } + other => handle_failure(other), + } + } } fn handle_expand_ra( 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 c548dc620ad13..6b770e440c7bb 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 @@ -120,6 +120,7 @@ pub trait ProcMacroClientInterface { fn line_column(&mut self, span: Span) -> Option<(u32, u32)>; fn byte_range(&mut self, span: Span) -> Range; + fn span_source(&mut self, span: Span) -> Span; } const EXPANDER_STACK_SIZE: usize = 8 * 1024 * 1024; diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs index d85deba75728e..5eb16c37ac292 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs @@ -169,7 +169,9 @@ impl server::Server for RaSpanServer<'_> { None } fn span_source(&mut self, span: Self::Span) -> Self::Span { - // FIXME requires db, returns the top level call site + if let Some(ref mut callback) = self.callback { + return callback.span_source(span); + } span } fn span_byte_range(&mut self, span: Self::Span) -> Range { diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs index b7c5c4fdd21f0..28d826d01ea73 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs @@ -142,6 +142,10 @@ impl ProcMacroClientInterface for MockCallback<'_> { fn byte_range(&mut self, span: Span) -> Range { Range { start: span.range.start().into(), end: span.range.end().into() } } + + fn span_source(&mut self, span: Span) -> Span { + span + } } pub fn assert_expand_with_callback( diff --git a/src/tools/rust-analyzer/crates/profile/src/google_cpu_profiler.rs b/src/tools/rust-analyzer/crates/profile/src/google_cpu_profiler.rs index cae6caeaa669c..d77c945f26319 100644 --- a/src/tools/rust-analyzer/crates/profile/src/google_cpu_profiler.rs +++ b/src/tools/rust-analyzer/crates/profile/src/google_cpu_profiler.rs @@ -9,7 +9,7 @@ use std::{ #[link(name = "profiler")] #[allow(non_snake_case)] -extern "C" { +unsafe extern "C" { fn ProfilerStart(fname: *const c_char) -> i32; fn ProfilerStop(); } diff --git a/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs b/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs index fedc6944f5f86..aff5391697414 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs @@ -22,8 +22,9 @@ use triomphe::Arc; use crate::{ CargoConfig, CargoFeatures, CargoWorkspace, InvocationStrategy, ManifestPath, Package, Sysroot, - TargetKind, cargo_config_file::make_lockfile_copy, - cargo_workspace::MINIMUM_TOOLCHAIN_VERSION_SUPPORTING_LOCKFILE_PATH, utf8_stdout, + TargetKind, + cargo_config_file::{LockfileCopy, LockfileUsage, make_lockfile_copy}, + utf8_stdout, }; /// Output of the build script and proc-macro building steps for a workspace. @@ -436,7 +437,7 @@ impl WorkspaceBuildScripts { current_dir: &AbsPath, sysroot: &Sysroot, toolchain: Option<&semver::Version>, - ) -> io::Result<(Option, Command)> { + ) -> io::Result<(Option, Command)> { match config.run_build_script_command.as_deref() { Some([program, args @ ..]) => { let mut cmd = toolchain::command(program, current_dir, &config.extra_env); @@ -461,17 +462,26 @@ impl WorkspaceBuildScripts { if let Some(target) = &config.target { cmd.args(["--target", target]); } - let mut temp_dir_guard = None; - if toolchain - .is_some_and(|v| *v >= MINIMUM_TOOLCHAIN_VERSION_SUPPORTING_LOCKFILE_PATH) - { + let mut lockfile_copy = None; + if let Some(toolchain) = toolchain { let lockfile_path = <_ as AsRef>::as_ref(manifest_path).with_extension("lock"); - if let Some((temp_dir, target_lockfile)) = make_lockfile_copy(&lockfile_path) { + lockfile_copy = make_lockfile_copy(toolchain, &lockfile_path); + if let Some(lockfile_copy) = &lockfile_copy { requires_unstable_options = true; - temp_dir_guard = Some(temp_dir); - cmd.arg("--lockfile-path"); - cmd.arg(target_lockfile.as_str()); + match lockfile_copy.usage { + LockfileUsage::WithFlag => { + cmd.arg("--lockfile-path"); + cmd.arg(lockfile_copy.path.as_str()); + } + LockfileUsage::WithEnvVar => { + cmd.arg("-Zlockfile-path"); + cmd.env( + "CARGO_RESOLVER_LOCKFILE_PATH", + lockfile_copy.path.as_os_str(), + ); + } + } } } match &config.features { @@ -542,7 +552,7 @@ impl WorkspaceBuildScripts { cmd.env("__CARGO_TEST_CHANNEL_OVERRIDE_DO_NOT_USE_THIS", "nightly"); cmd.arg("-Zunstable-options"); } - Ok((temp_dir_guard, cmd)) + Ok((lockfile_copy, cmd)) } } } diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_config_file.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_config_file.rs index 5d6e5fd648b38..ae36deb71f02a 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/cargo_config_file.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_config_file.rs @@ -132,25 +132,65 @@ impl<'a> CargoConfigFileReader<'a> { } } +pub(crate) struct LockfileCopy { + pub(crate) path: Utf8PathBuf, + pub(crate) usage: LockfileUsage, + _temp_dir: temp_dir::TempDir, +} + +pub(crate) enum LockfileUsage { + /// Rust [1.82.0, 1.95.0). `cargo --lockfile-path ` + WithFlag, + /// Rust >= 1.95.0. `CARGO_RESOLVER_LOCKFILE_PATH= cargo ` + WithEnvVar, +} + pub(crate) fn make_lockfile_copy( + toolchain_version: &semver::Version, lockfile_path: &Utf8Path, -) -> Option<(temp_dir::TempDir, Utf8PathBuf)> { +) -> Option { + const MINIMUM_TOOLCHAIN_VERSION_SUPPORTING_LOCKFILE_PATH_FLAG: semver::Version = + semver::Version { + major: 1, + minor: 82, + patch: 0, + pre: semver::Prerelease::EMPTY, + build: semver::BuildMetadata::EMPTY, + }; + + const MINIMUM_TOOLCHAIN_VERSION_SUPPORTING_LOCKFILE_PATH_ENV: semver::Version = + semver::Version { + major: 1, + minor: 95, + patch: 0, + pre: semver::Prerelease::EMPTY, + build: semver::BuildMetadata::EMPTY, + }; + + let usage = if *toolchain_version >= MINIMUM_TOOLCHAIN_VERSION_SUPPORTING_LOCKFILE_PATH_ENV { + LockfileUsage::WithEnvVar + } else if *toolchain_version >= MINIMUM_TOOLCHAIN_VERSION_SUPPORTING_LOCKFILE_PATH_FLAG { + LockfileUsage::WithFlag + } else { + return None; + }; + let temp_dir = temp_dir::TempDir::with_prefix("rust-analyzer").ok()?; - let target_lockfile = temp_dir.path().join("Cargo.lock").try_into().ok()?; - match std::fs::copy(lockfile_path, &target_lockfile) { + let path: Utf8PathBuf = temp_dir.path().join("Cargo.lock").try_into().ok()?; + let path = match std::fs::copy(lockfile_path, &path) { Ok(_) => { - tracing::debug!("Copied lock file from `{}` to `{}`", lockfile_path, target_lockfile); - Some((temp_dir, target_lockfile)) + tracing::debug!("Copied lock file from `{}` to `{}`", lockfile_path, path); + path } // lockfile does not yet exist, so we can just create a new one in the temp dir - Err(e) if e.kind() == std::io::ErrorKind::NotFound => Some((temp_dir, target_lockfile)), + Err(e) if e.kind() == std::io::ErrorKind::NotFound => path, Err(e) => { - tracing::warn!( - "Failed to copy lock file from `{lockfile_path}` to `{target_lockfile}`: {e}", - ); - None + tracing::warn!("Failed to copy lock file from `{lockfile_path}` to `{path}`: {e}",); + return None; } - } + }; + + Some(LockfileCopy { path, usage, _temp_dir: temp_dir }) } #[test] diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs index 483ab28450455..792206b74f849 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs @@ -16,18 +16,10 @@ use toolchain::{NO_RUSTUP_AUTO_INSTALL_ENV, Tool}; use triomphe::Arc; use crate::{ - CfgOverrides, InvocationStrategy, ManifestPath, Sysroot, cargo_config_file::make_lockfile_copy, + CfgOverrides, InvocationStrategy, ManifestPath, Sysroot, + cargo_config_file::{LockfileCopy, LockfileUsage, make_lockfile_copy}, }; -pub(crate) const MINIMUM_TOOLCHAIN_VERSION_SUPPORTING_LOCKFILE_PATH: semver::Version = - semver::Version { - major: 1, - minor: 82, - patch: 0, - pre: semver::Prerelease::EMPTY, - build: semver::BuildMetadata::EMPTY, - }; - /// [`CargoWorkspace`] represents the logical structure of, well, a Cargo /// workspace. It pretty closely mirrors `cargo metadata` output. /// @@ -628,7 +620,7 @@ pub(crate) struct FetchMetadata { command: cargo_metadata::MetadataCommand, #[expect(dead_code)] manifest_path: ManifestPath, - lockfile_path: Option, + lockfile_copy: Option, #[expect(dead_code)] kind: &'static str, no_deps: bool, @@ -688,15 +680,14 @@ impl FetchMetadata { } } - let mut lockfile_path = None; + let mut lockfile_copy = None; if cargo_toml.is_rust_manifest() { other_options.push("-Zscript".to_owned()); - } else if config - .toolchain_version - .as_ref() - .is_some_and(|v| *v >= MINIMUM_TOOLCHAIN_VERSION_SUPPORTING_LOCKFILE_PATH) - { - lockfile_path = Some(<_ as AsRef>::as_ref(cargo_toml).with_extension("lock")); + } else if let Some(v) = config.toolchain_version.as_ref() { + lockfile_copy = make_lockfile_copy( + v, + &<_ as AsRef>::as_ref(cargo_toml).with_extension("lock"), + ); } if !config.targets.is_empty() { @@ -729,7 +720,7 @@ impl FetchMetadata { Self { manifest_path: cargo_toml.clone(), command, - lockfile_path, + lockfile_copy, kind: config.kind, no_deps, no_deps_result, @@ -749,7 +740,7 @@ impl FetchMetadata { let Self { mut command, manifest_path: _, - lockfile_path, + lockfile_copy, kind: _, no_deps, no_deps_result, @@ -761,13 +752,17 @@ impl FetchMetadata { } let mut using_lockfile_copy = false; - let mut _temp_dir_guard; - if let Some(lockfile) = lockfile_path - && let Some((temp_dir, target_lockfile)) = make_lockfile_copy(&lockfile) - { - _temp_dir_guard = temp_dir; - other_options.push("--lockfile-path".to_owned()); - other_options.push(target_lockfile.to_string()); + if let Some(lockfile_copy) = &lockfile_copy { + match lockfile_copy.usage { + LockfileUsage::WithFlag => { + other_options.push("--lockfile-path".to_owned()); + other_options.push(lockfile_copy.path.to_string()); + } + LockfileUsage::WithEnvVar => { + other_options.push("-Zlockfile-path".to_owned()); + command.env("CARGO_RESOLVER_LOCKFILE_PATH", lockfile_copy.path.as_os_str()); + } + } using_lockfile_copy = true; } if using_lockfile_copy || other_options.iter().any(|it| it.starts_with("-Z")) { diff --git a/src/tools/rust-analyzer/crates/project-model/src/project_json.rs b/src/tools/rust-analyzer/crates/project-model/src/project_json.rs index 6938010cbd708..9b9111012b541 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/project_json.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/project_json.rs @@ -391,7 +391,6 @@ struct CrateData { display_name: Option, root_module: Utf8PathBuf, edition: EditionData, - #[serde(default)] version: Option, deps: Vec, #[serde(default)] @@ -408,11 +407,8 @@ struct CrateData { source: Option, #[serde(default)] is_proc_macro: bool, - #[serde(default)] repository: Option, - #[serde(default)] build: Option, - #[serde(default)] proc_macro_cwd: Option, } 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 47f7a57f72eca..cdaf944bbad42 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs @@ -382,6 +382,7 @@ enum FlycheckCommandOrigin { ProjectJsonRunnable, } +#[derive(Debug)] enum StateChange { Restart { generation: DiagnosticsGeneration, @@ -435,6 +436,7 @@ enum DiagnosticsReceived { } #[allow(clippy::large_enum_variant)] +#[derive(Debug)] enum Event { RequestStateChange(StateChange), CheckEvent(Option), @@ -445,6 +447,7 @@ const SAVED_FILE_PLACEHOLDER_DOLLAR: &str = "$saved_file"; const LABEL_INLINE: &str = "{label}"; const SAVED_FILE_INLINE: &str = "{saved_file}"; +#[derive(Debug)] struct Substitutions<'a> { label: Option<&'a str>, saved_file: Option<&'a str>, @@ -556,17 +559,37 @@ impl FlycheckActor { self.cancel_check_process(); } Event::RequestStateChange(StateChange::Restart { - generation, - scope, - saved_file, - target, + mut generation, + mut scope, + mut saved_file, + mut target, }) => { // Cancel the previously spawned process self.cancel_check_process(); + + // Debounce by briefly waiting for other state changes. while let Ok(restart) = inbox.recv_timeout(Duration::from_millis(50)) { - // restart chained with a stop, so just cancel - if let StateChange::Cancel = restart { - continue 'event; + match restart { + StateChange::Cancel => { + // We got a cancel straight after this restart request, so + // don't do anything. + continue 'event; + } + StateChange::Restart { + generation: g, + scope: s, + saved_file: sf, + target: t, + } => { + // We got another restart request. Take the parameters + // from the last restart request in this time window, + // because the most recent request is probably the most + // relevant to the user. + generation = g; + scope = s; + saved_file = sf; + target = t; + } } } @@ -950,6 +973,7 @@ impl FlycheckActor { } #[allow(clippy::large_enum_variant)] +#[derive(Debug)] enum CheckMessage { /// A message from `cargo check`, including details like the path /// to the relevant `Cargo.toml`. diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/flycheck.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/flycheck.rs new file mode 100644 index 0000000000000..c1d53fb33ab60 --- /dev/null +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/flycheck.rs @@ -0,0 +1,112 @@ +use test_utils::skip_slow_tests; + +use crate::support::Project; + +#[test] +fn test_flycheck_diagnostics_for_unused_variable() { + if skip_slow_tests() { + return; + } + + let server = Project::with_fixture( + r#" +//- /Cargo.toml +[package] +name = "foo" +version = "0.0.0" + +//- /src/main.rs +fn main() { + let x = 1; +} +"#, + ) + .with_config(serde_json::json!({ + "checkOnSave": true, + })) + .server() + .wait_until_workspace_is_loaded(); + + let diagnostics = server.wait_for_diagnostics(); + assert!( + diagnostics.diagnostics.iter().any(|d| d.message.contains("unused variable")), + "expected unused variable diagnostic, got: {:?}", + diagnostics.diagnostics, + ); +} + +#[test] +fn test_flycheck_diagnostic_cleared_after_fix() { + if skip_slow_tests() { + return; + } + + let server = Project::with_fixture( + r#" +//- /Cargo.toml +[package] +name = "foo" +version = "0.0.0" + +//- /src/main.rs +fn main() { + let x = 1; +} +"#, + ) + .with_config(serde_json::json!({ + "checkOnSave": true, + })) + .server() + .wait_until_workspace_is_loaded(); + + // Wait for the unused variable diagnostic to appear. + let diagnostics = server.wait_for_diagnostics(); + assert!( + diagnostics.diagnostics.iter().any(|d| d.message.contains("unused variable")), + "expected unused variable diagnostic, got: {:?}", + diagnostics.diagnostics, + ); + + // Fix the code by removing the unused variable. + server.write_file_and_save("src/main.rs", "fn main() {}\n".to_owned()); + + // Wait for diagnostics to be cleared. + server.wait_for_diagnostics_cleared(); +} + +#[test] +fn test_flycheck_diagnostic_with_override_command() { + if skip_slow_tests() { + return; + } + + let server = Project::with_fixture( + r#" +//- /Cargo.toml +[package] +name = "foo" +version = "0.0.0" + +//- /src/main.rs +fn main() {} +"#, + ) + .with_config(serde_json::json!({ + "checkOnSave": true, + "check": { + "overrideCommand": ["rustc", "--error-format=json", "$saved_file"] + } + })) + .server() + .wait_until_workspace_is_loaded(); + + server.write_file_and_save("src/main.rs", "fn main() {\n let x = 1;\n}\n".to_owned()); + + let diagnostics = server.wait_for_diagnostics(); + assert!( + diagnostics.diagnostics.iter().any(|d| d.message.contains("unused variable")), + "expected unused variable diagnostic, got: {:?}", + diagnostics.diagnostics, + ); +} 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 b4a7b44d165ac..26ba549a29be1 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 @@ -15,6 +15,7 @@ extern crate rustc_driver as _; mod cli; +mod flycheck; mod ratoml; mod support; mod testdir; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs index 195ad226ae0c5..7ee31f3d53eab 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs @@ -8,7 +8,9 @@ use std::{ use crossbeam_channel::{Receiver, after, select}; use itertools::Itertools; use lsp_server::{Connection, Message, Notification, Request}; -use lsp_types::{TextDocumentIdentifier, Url, notification::Exit, request::Shutdown}; +use lsp_types::{ + PublishDiagnosticsParams, TextDocumentIdentifier, Url, notification::Exit, request::Shutdown, +}; use parking_lot::{Mutex, MutexGuard}; use paths::{Utf8Path, Utf8PathBuf}; use rust_analyzer::{ @@ -407,6 +409,53 @@ impl Server { .unwrap_or_else(|Timeout| panic!("timeout while waiting for ws to load")); self } + pub(crate) fn wait_for_diagnostics(&self) -> PublishDiagnosticsParams { + for msg in self.messages.borrow().iter() { + if let Message::Notification(n) = msg + && n.method == "textDocument/publishDiagnostics" + { + let params: PublishDiagnosticsParams = + serde_json::from_value(n.params.clone()).unwrap(); + if !params.diagnostics.is_empty() { + return params; + } + } + } + loop { + let msg = self + .recv() + .unwrap_or_else(|Timeout| panic!("timeout while waiting for diagnostics")) + .expect("connection closed while waiting for diagnostics"); + if let Message::Notification(n) = &msg + && n.method == "textDocument/publishDiagnostics" + { + let params: PublishDiagnosticsParams = + serde_json::from_value(n.params.clone()).unwrap(); + if !params.diagnostics.is_empty() { + return params; + } + } + } + } + + pub(crate) fn wait_for_diagnostics_cleared(&self) { + loop { + let msg = self + .recv() + .unwrap_or_else(|Timeout| panic!("timeout while waiting for diagnostics to clear")) + .expect("connection closed while waiting for diagnostics to clear"); + if let Message::Notification(n) = &msg + && n.method == "textDocument/publishDiagnostics" + { + let params: PublishDiagnosticsParams = + serde_json::from_value(n.params.clone()).unwrap(); + if params.diagnostics.is_empty() { + return; + } + } + } + } + fn wait_for_message_cond( &self, n: usize, diff --git a/src/tools/rust-analyzer/docs/book/src/non_cargo_based_projects.md b/src/tools/rust-analyzer/docs/book/src/non_cargo_based_projects.md index f1f10ae336534..9cc3292444980 100644 --- a/src/tools/rust-analyzer/docs/book/src/non_cargo_based_projects.md +++ b/src/tools/rust-analyzer/docs/book/src/non_cargo_based_projects.md @@ -135,7 +135,7 @@ interface Crate { cfg_groups?: string[]; /// The set of cfgs activated for a given crate, like /// `["unix", "feature=\"foo\"", "feature=\"bar\""]`. - cfg: string[]; + cfg?: string[]; /// Target tuple for this Crate. /// /// Used when running `rustc --print cfg` @@ -143,7 +143,7 @@ interface Crate { target?: string; /// Environment variables, used for /// the `env!` macro - env: { [key: string]: string; }; + env?: { [key: string]: string; }; /// Extra crate-level attributes applied to this crate. /// /// rust-analyzer will behave as if these attributes @@ -155,7 +155,8 @@ interface Crate { crate_attrs?: string[]; /// Whether the crate is a proc-macro crate. - is_proc_macro: boolean; + /// Defaults to `false` if unspecified. + is_proc_macro?: boolean; /// For proc-macro crates, path to compiled /// proc-macro (.so file). proc_macro_dylib_path?: string; diff --git a/src/tools/rust-analyzer/docs/book/src/vs_code.md b/src/tools/rust-analyzer/docs/book/src/vs_code.md index 75f940e69a885..69a96156b8261 100644 --- a/src/tools/rust-analyzer/docs/book/src/vs_code.md +++ b/src/tools/rust-analyzer/docs/book/src/vs_code.md @@ -98,12 +98,12 @@ some directories, `/usr/bin` will always be mounted under system-wide installation of Rust, or any other libraries you might want to link to. Some compilers and libraries can be acquired as Flatpak SDKs, such as `org.freedesktop.Sdk.Extension.rust-stable` or -`org.freedesktop.Sdk.Extension.llvm15`. +`org.freedesktop.Sdk.Extension.llvm21`. If you use a Flatpak SDK for Rust, it must be in your `PATH`: - * install the SDK extensions with `flatpak install org.freedesktop.Sdk.Extension.{llvm15,rust-stable}//23.08` - * enable SDK extensions in the editor with the environment variable `FLATPAK_ENABLE_SDK_EXT=llvm15,rust-stable` (this can be done using flatseal or `flatpak override`) + * install the SDK extensions with `flatpak install org.freedesktop.Sdk.Extension.{llvm21,rust-stable}//25.08` + * enable SDK extensions in the editor with the environment variable `FLATPAK_ENABLE_SDK_EXT=llvm21,rust-stable` (this can be done using flatseal or `flatpak override`) If you want to use Flatpak in combination with `rustup`, the following steps might help: diff --git a/src/tools/rust-analyzer/editors/code/package-lock.json b/src/tools/rust-analyzer/editors/code/package-lock.json index 84be0a666f9ca..d3fbea2336b0b 100644 --- a/src/tools/rust-analyzer/editors/code/package-lock.json +++ b/src/tools/rust-analyzer/editors/code/package-lock.json @@ -4650,9 +4650,9 @@ } }, "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", "dev": true, "license": "MIT" }, diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version index b22c6c3869c62..b6e1b2bc55df4 100644 --- a/src/tools/rust-analyzer/rust-version +++ b/src/tools/rust-analyzer/rust-version @@ -1 +1 @@ -139651428df86cf88443295542c12ea617cbb587 +c78a29473a68f07012904af11c92ecffa68fcc75 diff --git a/tests/pretty/delegation-inherit-attributes.pp b/tests/pretty/delegation-inherit-attributes.pp index 26ca5e99b885d..bfe5ba03c37d4 100644 --- a/tests/pretty/delegation-inherit-attributes.pp +++ b/tests/pretty/delegation-inherit-attributes.pp @@ -5,7 +5,7 @@ //@ pp-exact:delegation-inherit-attributes.pp #![allow(incomplete_features)] -#![feature(fn_delegation)] +#![attr = Feature([fn_delegation#0])] extern crate std; #[attr = PreludeImport] use std::prelude::rust_2021::*; diff --git a/tests/pretty/delegation-inline-attribute.pp b/tests/pretty/delegation-inline-attribute.pp index 9f362fa863f82..54442a210d937 100644 --- a/tests/pretty/delegation-inline-attribute.pp +++ b/tests/pretty/delegation-inline-attribute.pp @@ -3,7 +3,7 @@ //@ pp-exact:delegation-inline-attribute.pp #![allow(incomplete_features)] -#![feature(fn_delegation)] +#![attr = Feature([fn_delegation#0])] extern crate std; #[attr = PreludeImport] use ::std::prelude::rust_2015::*; diff --git a/tests/pretty/hir-delegation.pp b/tests/pretty/hir-delegation.pp index 59491b6ebd7c1..efa643313e6b4 100644 --- a/tests/pretty/hir-delegation.pp +++ b/tests/pretty/hir-delegation.pp @@ -3,7 +3,7 @@ //@ pp-exact:hir-delegation.pp #![allow(incomplete_features)] -#![feature(fn_delegation)] +#![attr = Feature([fn_delegation#0])] extern crate std; #[attr = PreludeImport] use ::std::prelude::rust_2015::*; diff --git a/tests/pretty/hir-fn-variadic.pp b/tests/pretty/hir-fn-variadic.pp index 3837b260cc5d6..30423349241b7 100644 --- a/tests/pretty/hir-fn-variadic.pp +++ b/tests/pretty/hir-fn-variadic.pp @@ -1,11 +1,11 @@ +#![attr = Feature([c_variadic#0])] +extern crate std; +#[attr = PreludeImport] +use ::std::prelude::rust_2015::*; //@ pretty-compare-only //@ pretty-mode:hir //@ pp-exact:hir-fn-variadic.pp -#![feature(c_variadic)] -extern crate std; -#[attr = PreludeImport] -use ::std::prelude::rust_2015::*; extern "C" { unsafe fn foo(x: i32, va1: ...); diff --git a/tests/pretty/pin-ergonomics-hir.pp b/tests/pretty/pin-ergonomics-hir.pp index e422edf54e0c5..6c9dec2bfb1fb 100644 --- a/tests/pretty/pin-ergonomics-hir.pp +++ b/tests/pretty/pin-ergonomics-hir.pp @@ -2,8 +2,8 @@ //@ pretty-mode:hir //@ pp-exact:pin-ergonomics-hir.pp -#![feature(pin_ergonomics)] #![allow(dead_code, incomplete_features)] +#![attr = Feature([pin_ergonomics#0])] extern crate std; #[attr = PreludeImport] use ::std::prelude::rust_2015::*; diff --git a/tests/rustdoc-html/impl/empty-impl-block.rs b/tests/rustdoc-html/impl/empty-impl-block.rs index 91fd4a64ef939..7ca5813aae2ef 100644 --- a/tests/rustdoc-html/impl/empty-impl-block.rs +++ b/tests/rustdoc-html/impl/empty-impl-block.rs @@ -4,7 +4,7 @@ pub struct Foo; //@ has - '//*[@class="docblock"]' 'Hello empty impl block!' -//@ has - '//*[@class="item-info"]' 'This impl block contains no items.' +//@ has - '//*[@class="item-info"]' 'This impl block contains no public items.' /// Hello empty impl block! impl Foo {} // We ensure that this empty impl block without doc isn't rendered. diff --git a/tests/ui/attributes/attr-mix-new.rs b/tests/ui/attributes/attr-mix-new.rs index c4f080eb8c302..3ddb1d0d7335c 100644 --- a/tests/ui/attributes/attr-mix-new.rs +++ b/tests/ui/attributes/attr-mix-new.rs @@ -5,7 +5,7 @@ #[rustc_dummy(bar)] mod foo { #![feature(globs)] - //~^ WARN crate-level attribute should be in the root module + //~^ WARN the `#![feature]` attribute can only be used at the crate root } fn main() {} diff --git a/tests/ui/attributes/attr-mix-new.stderr b/tests/ui/attributes/attr-mix-new.stderr index c1bb8a550bcca..628d93ff534e4 100644 --- a/tests/ui/attributes/attr-mix-new.stderr +++ b/tests/ui/attributes/attr-mix-new.stderr @@ -1,4 +1,4 @@ -warning: crate-level attribute should be in the root module +warning: the `#![feature]` attribute can only be used at the crate root --> $DIR/attr-mix-new.rs:7:3 | LL | #![feature(globs)] diff --git a/tests/ui/coherence/orphan-check-alias.classic.stderr b/tests/ui/coherence/orphan-check-alias.classic.stderr index 25fde6ee1d23d..06b6bd4eb0fd5 100644 --- a/tests/ui/coherence/orphan-check-alias.classic.stderr +++ b/tests/ui/coherence/orphan-check-alias.classic.stderr @@ -4,10 +4,10 @@ warning[E0210]: type parameter `T` must be covered by another type when it appea LL | impl foreign::Trait2 for ::Assoc { | ^ type parameter `T` must be covered by another type when it appears before the first local type (`B`) | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #124559 = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, where `T0` is the first and `Tn` is the last + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #124559 = note: `#[warn(uncovered_param_in_projection)]` (part of `#[warn(future_incompatible)]`) on by default warning: 1 warning emitted diff --git a/tests/ui/coherence/orphan-check-alias.next.stderr b/tests/ui/coherence/orphan-check-alias.next.stderr index 25fde6ee1d23d..06b6bd4eb0fd5 100644 --- a/tests/ui/coherence/orphan-check-alias.next.stderr +++ b/tests/ui/coherence/orphan-check-alias.next.stderr @@ -4,10 +4,10 @@ warning[E0210]: type parameter `T` must be covered by another type when it appea LL | impl foreign::Trait2 for ::Assoc { | ^ type parameter `T` must be covered by another type when it appears before the first local type (`B`) | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #124559 = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, where `T0` is the first and `Tn` is the last + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #124559 = note: `#[warn(uncovered_param_in_projection)]` (part of `#[warn(future_incompatible)]`) on by default warning: 1 warning emitted diff --git a/tests/ui/coherence/orphan-check-projections-not-covering-ambiguity.classic.stderr b/tests/ui/coherence/orphan-check-projections-not-covering-ambiguity.classic.stderr index 464413e9f38c8..a000fc2f0bc11 100644 --- a/tests/ui/coherence/orphan-check-projections-not-covering-ambiguity.classic.stderr +++ b/tests/ui/coherence/orphan-check-projections-not-covering-ambiguity.classic.stderr @@ -4,10 +4,10 @@ warning[E0210]: type parameter `T` must be covered by another type when it appea LL | impl foreign::Trait1 for ::Output {} | ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`) | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #124559 = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, where `T0` is the first and `Tn` is the last + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #124559 = note: `#[warn(uncovered_param_in_projection)]` (part of `#[warn(future_incompatible)]`) on by default warning: 1 warning emitted diff --git a/tests/ui/coherence/orphan-check-projections-not-covering-ambiguity.next.stderr b/tests/ui/coherence/orphan-check-projections-not-covering-ambiguity.next.stderr index 464413e9f38c8..a000fc2f0bc11 100644 --- a/tests/ui/coherence/orphan-check-projections-not-covering-ambiguity.next.stderr +++ b/tests/ui/coherence/orphan-check-projections-not-covering-ambiguity.next.stderr @@ -4,10 +4,10 @@ warning[E0210]: type parameter `T` must be covered by another type when it appea LL | impl foreign::Trait1 for ::Output {} | ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`) | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #124559 = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, where `T0` is the first and `Tn` is the last + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #124559 = note: `#[warn(uncovered_param_in_projection)]` (part of `#[warn(future_incompatible)]`) on by default warning: 1 warning emitted diff --git a/tests/ui/coherence/orphan-check-projections-not-covering-multiple-params.classic.stderr b/tests/ui/coherence/orphan-check-projections-not-covering-multiple-params.classic.stderr index 0465fad21194f..1d71966b18cb7 100644 --- a/tests/ui/coherence/orphan-check-projections-not-covering-multiple-params.classic.stderr +++ b/tests/ui/coherence/orphan-check-projections-not-covering-multiple-params.classic.stderr @@ -4,10 +4,10 @@ warning[E0210]: type parameter `T` must be covered by another type when it appea LL | impl foreign::Trait0 for <() as Trait>::Assoc {} | ^ type parameter `T` must be covered by another type when it appears before the first local type (`LocalTy`) | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #124559 = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, where `T0` is the first and `Tn` is the last + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #124559 = note: `#[warn(uncovered_param_in_projection)]` (part of `#[warn(future_incompatible)]`) on by default warning[E0210]: type parameter `U` must be covered by another type when it appears before the first local type (`LocalTy`) @@ -16,10 +16,10 @@ warning[E0210]: type parameter `U` must be covered by another type when it appea LL | impl foreign::Trait0 for <() as Trait>::Assoc {} | ^ type parameter `U` must be covered by another type when it appears before the first local type (`LocalTy`) | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #124559 = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, where `T0` is the first and `Tn` is the last + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #124559 warning: 2 warnings emitted diff --git a/tests/ui/coherence/orphan-check-projections-not-covering-multiple-params.next.stderr b/tests/ui/coherence/orphan-check-projections-not-covering-multiple-params.next.stderr index 0465fad21194f..1d71966b18cb7 100644 --- a/tests/ui/coherence/orphan-check-projections-not-covering-multiple-params.next.stderr +++ b/tests/ui/coherence/orphan-check-projections-not-covering-multiple-params.next.stderr @@ -4,10 +4,10 @@ warning[E0210]: type parameter `T` must be covered by another type when it appea LL | impl foreign::Trait0 for <() as Trait>::Assoc {} | ^ type parameter `T` must be covered by another type when it appears before the first local type (`LocalTy`) | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #124559 = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, where `T0` is the first and `Tn` is the last + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #124559 = note: `#[warn(uncovered_param_in_projection)]` (part of `#[warn(future_incompatible)]`) on by default warning[E0210]: type parameter `U` must be covered by another type when it appears before the first local type (`LocalTy`) @@ -16,10 +16,10 @@ warning[E0210]: type parameter `U` must be covered by another type when it appea LL | impl foreign::Trait0 for <() as Trait>::Assoc {} | ^ type parameter `U` must be covered by another type when it appears before the first local type (`LocalTy`) | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #124559 = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, where `T0` is the first and `Tn` is the last + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #124559 warning: 2 warnings emitted diff --git a/tests/ui/coherence/orphan-check-projections-not-covering.classic.stderr b/tests/ui/coherence/orphan-check-projections-not-covering.classic.stderr index de34ef7cfd3a1..8ea6496a42d70 100644 --- a/tests/ui/coherence/orphan-check-projections-not-covering.classic.stderr +++ b/tests/ui/coherence/orphan-check-projections-not-covering.classic.stderr @@ -4,10 +4,10 @@ warning[E0210]: type parameter `T` must be covered by another type when it appea LL | impl foreign::Trait0 for ::Output {} | ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`) | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #124559 = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, where `T0` is the first and `Tn` is the last + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #124559 = note: `#[warn(uncovered_param_in_projection)]` (part of `#[warn(future_incompatible)]`) on by default warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`) @@ -16,10 +16,10 @@ warning[E0210]: type parameter `T` must be covered by another type when it appea LL | impl foreign::Trait0<::Output, Local, T> for Option {} | ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`) | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #124559 = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, where `T0` is the first and `Tn` is the last + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #124559 warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`) --> $DIR/orphan-check-projections-not-covering.rs:40:6 @@ -27,10 +27,10 @@ warning[E0210]: type parameter `T` must be covered by another type when it appea LL | impl foreign::Trait1 for ::Output {} | ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`) | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #124559 = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, where `T0` is the first and `Tn` is the last + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #124559 warning: 3 warnings emitted diff --git a/tests/ui/coherence/orphan-check-projections-not-covering.next.stderr b/tests/ui/coherence/orphan-check-projections-not-covering.next.stderr index de34ef7cfd3a1..8ea6496a42d70 100644 --- a/tests/ui/coherence/orphan-check-projections-not-covering.next.stderr +++ b/tests/ui/coherence/orphan-check-projections-not-covering.next.stderr @@ -4,10 +4,10 @@ warning[E0210]: type parameter `T` must be covered by another type when it appea LL | impl foreign::Trait0 for ::Output {} | ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`) | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #124559 = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, where `T0` is the first and `Tn` is the last + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #124559 = note: `#[warn(uncovered_param_in_projection)]` (part of `#[warn(future_incompatible)]`) on by default warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`) @@ -16,10 +16,10 @@ warning[E0210]: type parameter `T` must be covered by another type when it appea LL | impl foreign::Trait0<::Output, Local, T> for Option {} | ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`) | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #124559 = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, where `T0` is the first and `Tn` is the last + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #124559 warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`) --> $DIR/orphan-check-projections-not-covering.rs:40:6 @@ -27,10 +27,10 @@ warning[E0210]: type parameter `T` must be covered by another type when it appea LL | impl foreign::Trait1 for ::Output {} | ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`) | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #124559 = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, where `T0` is the first and `Tn` is the last + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #124559 warning: 3 warnings emitted diff --git a/tests/ui/coherence/orphan-check-projections-unsat-bounds.classic.stderr b/tests/ui/coherence/orphan-check-projections-unsat-bounds.classic.stderr index e729bcf225eb1..1289c65b40d06 100644 --- a/tests/ui/coherence/orphan-check-projections-unsat-bounds.classic.stderr +++ b/tests/ui/coherence/orphan-check-projections-unsat-bounds.classic.stderr @@ -4,10 +4,10 @@ warning[E0210]: type parameter `T` must be covered by another type when it appea LL | impl foreign::Trait1 for as Discard>::Output | ^ type parameter `T` must be covered by another type when it appears before the first local type (`LocalTy`) | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #124559 = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, where `T0` is the first and `Tn` is the last + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #124559 = note: `#[warn(uncovered_param_in_projection)]` (part of `#[warn(future_incompatible)]`) on by default warning: 1 warning emitted diff --git a/tests/ui/coherence/orphan-check-projections-unsat-bounds.next.stderr b/tests/ui/coherence/orphan-check-projections-unsat-bounds.next.stderr index e729bcf225eb1..1289c65b40d06 100644 --- a/tests/ui/coherence/orphan-check-projections-unsat-bounds.next.stderr +++ b/tests/ui/coherence/orphan-check-projections-unsat-bounds.next.stderr @@ -4,10 +4,10 @@ warning[E0210]: type parameter `T` must be covered by another type when it appea LL | impl foreign::Trait1 for as Discard>::Output | ^ type parameter `T` must be covered by another type when it appears before the first local type (`LocalTy`) | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #124559 = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, where `T0` is the first and `Tn` is the last + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #124559 = note: `#[warn(uncovered_param_in_projection)]` (part of `#[warn(future_incompatible)]`) on by default warning: 1 warning emitted diff --git a/tests/ui/consts/const-block-items/hir.stdout b/tests/ui/consts/const-block-items/hir.stdout index 2b7f0818556ff..d031818fdf65b 100644 --- a/tests/ui/consts/const-block-items/hir.stdout +++ b/tests/ui/consts/const-block-items/hir.stdout @@ -1,10 +1,10 @@ -//@ build-pass -//@ compile-flags: -Zunpretty=hir - -#![feature(const_block_items)] +#![attr = Feature([const_block_items#0])] extern crate std; #[attr = PreludeImport] use ::std::prelude::rust_2015::*; +//@ build-pass +//@ compile-flags: -Zunpretty=hir + const _: () = { diff --git a/tests/ui/editions/never-type-fallback-breaking.e2021.stderr b/tests/ui/editions/never-type-fallback-breaking.e2021.stderr index a910b19d9bf76..17dc5fc8795bc 100644 --- a/tests/ui/editions/never-type-fallback-breaking.e2021.stderr +++ b/tests/ui/editions/never-type-fallback-breaking.e2021.stderr @@ -4,14 +4,14 @@ error: this function depends on never type fallback being `()` LL | fn m() { | ^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! - = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `!: Default` will fail --> $DIR/never-type-fallback-breaking.rs:24:17 | LL | true => Default::default(), | ^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see = note: `#[deny(dependency_on_unit_never_type_fallback)]` (part of `#[deny(rust_2024_compatibility)]`) on by default help: use `()` annotations to avoid fallback changes | @@ -24,14 +24,14 @@ error: this function depends on never type fallback being `()` LL | fn q() -> Option<()> { | ^^^^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! - = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `!: Default` will fail --> $DIR/never-type-fallback-breaking.rs:39:5 | LL | deserialize()?; | ^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see help: use `()` annotations to avoid fallback changes | LL | deserialize::<()>()?; @@ -43,14 +43,14 @@ error: this function depends on never type fallback being `()` LL | fn meow() -> Result<(), ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! - = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `(): From` will fail --> $DIR/never-type-fallback-breaking.rs:52:5 | LL | help(1)?; | ^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see help: use `()` annotations to avoid fallback changes | LL | help::<(), _>(1)?; @@ -62,14 +62,14 @@ error: this function depends on never type fallback being `()` LL | pub fn fallback_return() -> Result<(), ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! - = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `!: Default` will fail --> $DIR/never-type-fallback-breaking.rs:64:19 | LL | takes_apit(|| Default::default())?; | ^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see help: use `()` annotations to avoid fallback changes | LL | takes_apit::<()>(|| Default::default())?; @@ -81,14 +81,14 @@ error: this function depends on never type fallback being `()` LL | fn fully_apit() -> Result<(), ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! - = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `!: Default` will fail --> $DIR/never-type-fallback-breaking.rs:78:17 | LL | takes_apit2(mk()?); | ^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see help: use `()` annotations to avoid fallback changes | LL | takes_apit2(mk::<()>()?); @@ -103,14 +103,14 @@ error: this function depends on never type fallback being `()` LL | fn m() { | ^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! - = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `!: Default` will fail --> $DIR/never-type-fallback-breaking.rs:24:17 | LL | true => Default::default(), | ^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see = note: `#[deny(dependency_on_unit_never_type_fallback)]` (part of `#[deny(rust_2024_compatibility)]`) on by default help: use `()` annotations to avoid fallback changes | @@ -124,14 +124,14 @@ error: this function depends on never type fallback being `()` LL | fn q() -> Option<()> { | ^^^^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! - = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `!: Default` will fail --> $DIR/never-type-fallback-breaking.rs:39:5 | LL | deserialize()?; | ^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see = note: `#[deny(dependency_on_unit_never_type_fallback)]` (part of `#[deny(rust_2024_compatibility)]`) on by default help: use `()` annotations to avoid fallback changes | @@ -145,14 +145,14 @@ error: this function depends on never type fallback being `()` LL | fn meow() -> Result<(), ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! - = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `(): From` will fail --> $DIR/never-type-fallback-breaking.rs:52:5 | LL | help(1)?; | ^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see = note: `#[deny(dependency_on_unit_never_type_fallback)]` (part of `#[deny(rust_2024_compatibility)]`) on by default help: use `()` annotations to avoid fallback changes | @@ -166,14 +166,14 @@ error: this function depends on never type fallback being `()` LL | pub fn fallback_return() -> Result<(), ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! - = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `!: Default` will fail --> $DIR/never-type-fallback-breaking.rs:64:19 | LL | takes_apit(|| Default::default())?; | ^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see = note: `#[deny(dependency_on_unit_never_type_fallback)]` (part of `#[deny(rust_2024_compatibility)]`) on by default help: use `()` annotations to avoid fallback changes | @@ -187,14 +187,14 @@ error: this function depends on never type fallback being `()` LL | fn fully_apit() -> Result<(), ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! - = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `!: Default` will fail --> $DIR/never-type-fallback-breaking.rs:78:17 | LL | takes_apit2(mk()?); | ^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see = note: `#[deny(dependency_on_unit_never_type_fallback)]` (part of `#[deny(rust_2024_compatibility)]`) on by default help: use `()` annotations to avoid fallback changes | diff --git a/tests/ui/empty/empty-attributes.stderr b/tests/ui/empty/empty-attributes.stderr index 41dc790737dd1..146a9af946d6c 100644 --- a/tests/ui/empty/empty-attributes.stderr +++ b/tests/ui/empty/empty-attributes.stderr @@ -43,14 +43,6 @@ LL | #![forbid()] | = note: attribute `forbid` with an empty list has no effect -error: unused attribute - --> $DIR/empty-attributes.rs:7:1 - | -LL | #![feature()] - | ^^^^^^^^^^^^^ help: remove this attribute - | - = note: attribute `feature` with an empty list has no effect - error: unused attribute --> $DIR/empty-attributes.rs:9:1 | @@ -67,5 +59,13 @@ LL | #[target_feature()] | = note: using `target_feature` with an empty list has no effect +error: unused attribute + --> $DIR/empty-attributes.rs:7:1 + | +LL | #![feature()] + | ^^^^^^^^^^^^^ help: remove this attribute + | + = note: using `feature` with an empty list has no effect + error: aborting due to 8 previous errors diff --git a/tests/ui/feature-gates/feature-gate-feature-gate.rs b/tests/ui/feature-gates/feature-gate-feature-gate.rs index 3c98e16a136a8..b5b6a8da91bd7 100644 --- a/tests/ui/feature-gates/feature-gate-feature-gate.rs +++ b/tests/ui/feature-gates/feature-gate-feature-gate.rs @@ -1,4 +1,4 @@ #![forbid(unstable_features)] #![feature(intrinsics)] //~ ERROR unstable feature -fn main() { } +fn main() {} diff --git a/tests/ui/feature-gates/gated-bad-feature.stderr b/tests/ui/feature-gates/gated-bad-feature.stderr index e0e84d842352d..afcc6b6f11c49 100644 --- a/tests/ui/feature-gates/gated-bad-feature.stderr +++ b/tests/ui/feature-gates/gated-bad-feature.stderr @@ -1,15 +1,3 @@ -error[E0556]: malformed `feature` attribute input - --> $DIR/gated-bad-feature.rs:1:25 - | -LL | #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)] - | ^^^^^^^^ help: expected just one word: `foo` - -error[E0556]: malformed `feature` attribute input - --> $DIR/gated-bad-feature.rs:1:35 - | -LL | #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)] - | ^^^^^^^^^^^ help: expected just one word: `foo` - error[E0557]: feature has been removed --> $DIR/gated-bad-feature.rs:8:12 | @@ -18,17 +6,41 @@ LL | #![feature(test_removed_feature)] | = note: removed in 1.0.0 -error: malformed `feature` attribute input +error[E0565]: malformed `feature` attribute input + --> $DIR/gated-bad-feature.rs:1:1 + | +LL | #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^ + | | | + | | didn't expect any arguments here + | help: must be of the form: `#![feature(feature1, feature2, ...)]` + +error[E0565]: malformed `feature` attribute input + --> $DIR/gated-bad-feature.rs:1:1 + | +LL | #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------^^^^^^^ + | | | + | | didn't expect any arguments here + | help: must be of the form: `#![feature(feature1, feature2, ...)]` + +error[E0539]: malformed `feature` attribute input --> $DIR/gated-bad-feature.rs:6:1 | LL | #![feature] - | ^^^^^^^^^^^ help: must be of the form: `#![feature(name1, name2, ...)]` + | ^^^^^^^^^^^ + | | + | expected this to be a list + | help: must be of the form: `#![feature(feature1, feature2, ...)]` -error: malformed `feature` attribute input +error[E0539]: malformed `feature` attribute input --> $DIR/gated-bad-feature.rs:7:1 | LL | #![feature = "foo"] - | ^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![feature(name1, name2, ...)]` + | ^^^^^^^^^^^-------^ + | | | + | | expected this to be a list + | help: must be of the form: `#![feature(feature1, feature2, ...)]` error[E0635]: unknown feature `foo_bar_baz` --> $DIR/gated-bad-feature.rs:1:12 @@ -44,5 +56,5 @@ LL | #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)] error: aborting due to 7 previous errors -Some errors have detailed explanations: E0556, E0557, E0635. -For more information about an error, try `rustc --explain E0556`. +Some errors have detailed explanations: E0539, E0557, E0565, E0635. +For more information about an error, try `rustc --explain E0539`. diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs index 83debd17777ae..294cdf659744a 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs @@ -859,26 +859,26 @@ mod crate_type { #[feature(x0600)] //~^ WARN crate-level attribute should be an inner attribute -//~| HELP add a `!` mod feature { +//~^ NOTE this attribute does not have an `!`, which means it is applied to this module mod inner { #![feature(x0600)] } -//~^ WARN crate-level attribute should be in the root module + //~^ WARN the `#![feature]` attribute can only be used at the crate root #[feature(x0600)] fn f() { } //~^ WARN crate-level attribute should be an inner attribute - //~| HELP add a `!` + //~| NOTE this attribute does not have an `!`, which means it is applied to this function #[feature(x0600)] struct S; //~^ WARN crate-level attribute should be an inner attribute - //~| HELP add a `!` + //~| NOTE this attribute does not have an `!`, which means it is applied to this struct #[feature(x0600)] type T = S; //~^ WARN crate-level attribute should be an inner attribute - //~| HELP add a `!` + //~| NOTE this attribute does not have an `!`, which means it is applied to this type alias #[feature(x0600)] impl S { } //~^ WARN crate-level attribute should be an inner attribute - //~| HELP add a `!` + //~| NOTE this attribute does not have an `!`, which means it is applied to this implementation block } diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr index 482980dde3bf5..b282bcef8960a 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr @@ -207,17 +207,6 @@ note: the lint level is defined here LL | #![warn(unused_attributes, unknown_lints)] | ^^^^^^^^^^^^^^^^^ -warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:860:1 - | -LL | #[feature(x0600)] - | ^^^^^^^^^^^^^^^^^ - | -help: add a `!` - | -LL | #![feature(x0600)] - | + - warning: attribute should be applied to an `extern` block with non-Rust ABI --> $DIR/issue-43106-gating-of-builtin-attrs.rs:71:1 | @@ -282,56 +271,6 @@ LL | #[link(name = "x")] extern "Rust" {} | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:864:17 - | -LL | mod inner { #![feature(x0600)] } - | ^^^^^^^^^^^^^^^^^^ - -warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:867:5 - | -LL | #[feature(x0600)] fn f() { } - | ^^^^^^^^^^^^^^^^^ - | -help: add a `!` - | -LL | #![feature(x0600)] fn f() { } - | + - -warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:871:5 - | -LL | #[feature(x0600)] struct S; - | ^^^^^^^^^^^^^^^^^ - | -help: add a `!` - | -LL | #![feature(x0600)] struct S; - | + - -warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:875:5 - | -LL | #[feature(x0600)] type T = S; - | ^^^^^^^^^^^^^^^^^ - | -help: add a `!` - | -LL | #![feature(x0600)] type T = S; - | + - -warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:879:5 - | -LL | #[feature(x0600)] impl S { } - | ^^^^^^^^^^^^^^^^^ - | -help: add a `!` - | -LL | #![feature(x0600)] impl S { } - | + - warning: `#[macro_use]` attribute cannot be used on functions --> $DIR/issue-43106-gating-of-builtin-attrs.rs:190:5 | @@ -1303,6 +1242,76 @@ note: this attribute does not have an `!`, which means it is applied to this imp LL | #[crate_type = "0800"] impl S { } | ^^^^^^^^^^ +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![feature]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:860:1 + | +LL | #[feature(x0600)] + | ^^^^^^^^^^^^^^^^^ + | +note: this attribute does not have an `!`, which means it is applied to this module + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:862:1 + | +LL | / mod feature { +LL | | +LL | | mod inner { #![feature(x0600)] } +... | +LL | | } + | |_^ + +warning: the `#![feature]` attribute can only be used at the crate root + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:864:17 + | +LL | mod inner { #![feature(x0600)] } + | ^^^^^^^^^^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![feature]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:867:5 + | +LL | #[feature(x0600)] fn f() { } + | ^^^^^^^^^^^^^^^^^ + | +note: this attribute does not have an `!`, which means it is applied to this function + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:867:23 + | +LL | #[feature(x0600)] fn f() { } + | ^^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![feature]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:871:5 + | +LL | #[feature(x0600)] struct S; + | ^^^^^^^^^^^^^^^^^ + | +note: this attribute does not have an `!`, which means it is applied to this struct + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:871:23 + | +LL | #[feature(x0600)] struct S; + | ^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![feature]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:875:5 + | +LL | #[feature(x0600)] type T = S; + | ^^^^^^^^^^^^^^^^^ + | +note: this attribute does not have an `!`, which means it is applied to this type alias + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:875:23 + | +LL | #[feature(x0600)] type T = S; + | ^^^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![feature]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:879:5 + | +LL | #[feature(x0600)] impl S { } + | ^^^^^^^^^^^^^^^^^ + | +note: this attribute does not have an `!`, which means it is applied to this implementation block + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:879:23 + | +LL | #[feature(x0600)] impl S { } + | ^^^^^^^^^^ + warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_main]` --> $DIR/issue-43106-gating-of-builtin-attrs.rs:885:1 | diff --git a/tests/ui/limits/vtable-try-as-dyn.full-debuginfo.stderr b/tests/ui/limits/vtable-try-as-dyn.full-debuginfo.stderr index a3772e509ed67..700083069cb05 100644 --- a/tests/ui/limits/vtable-try-as-dyn.full-debuginfo.stderr +++ b/tests/ui/limits/vtable-try-as-dyn.full-debuginfo.stderr @@ -1,4 +1,20 @@ -error: values of the type `[u8; usize::MAX]` are too big for the target architecture +error[E0080]: values of the type `[u8; usize::MAX]` are too big for the target architecture + --> $SRC_DIR/core/src/any.rs:LL:COL + | + = note: evaluation of `std::any::try_as_dyn::<[u8; usize::MAX], dyn Trait>::{constant#0}` failed inside this call +note: inside `TypeId::trait_info_of::` + --> $SRC_DIR/core/src/any.rs:LL:COL +note: inside `TypeId::trait_info_of_trait_type_id` + --> $SRC_DIR/core/src/any.rs:LL:COL +note: inside `type_info::::info` + --> $SRC_DIR/core/src/mem/type_info.rs:LL:COL + +note: the above error was encountered while instantiating `fn try_as_dyn::<[u8; usize::MAX], dyn Trait>` + --> $DIR/vtable-try-as-dyn.rs:14:13 + | +LL | let _ = std::any::try_as_dyn::<[u8; usize::MAX], dyn Trait>(x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/limits/vtable-try-as-dyn.no-debuginfo.stderr b/tests/ui/limits/vtable-try-as-dyn.no-debuginfo.stderr index a3772e509ed67..700083069cb05 100644 --- a/tests/ui/limits/vtable-try-as-dyn.no-debuginfo.stderr +++ b/tests/ui/limits/vtable-try-as-dyn.no-debuginfo.stderr @@ -1,4 +1,20 @@ -error: values of the type `[u8; usize::MAX]` are too big for the target architecture +error[E0080]: values of the type `[u8; usize::MAX]` are too big for the target architecture + --> $SRC_DIR/core/src/any.rs:LL:COL + | + = note: evaluation of `std::any::try_as_dyn::<[u8; usize::MAX], dyn Trait>::{constant#0}` failed inside this call +note: inside `TypeId::trait_info_of::` + --> $SRC_DIR/core/src/any.rs:LL:COL +note: inside `TypeId::trait_info_of_trait_type_id` + --> $SRC_DIR/core/src/any.rs:LL:COL +note: inside `type_info::::info` + --> $SRC_DIR/core/src/mem/type_info.rs:LL:COL + +note: the above error was encountered while instantiating `fn try_as_dyn::<[u8; usize::MAX], dyn Trait>` + --> $DIR/vtable-try-as-dyn.rs:14:13 + | +LL | let _ = std::any::try_as_dyn::<[u8; usize::MAX], dyn Trait>(x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/never_type/dependency-on-fallback-to-unit.stderr b/tests/ui/never_type/dependency-on-fallback-to-unit.stderr index 0b8d9657c7b0a..bb9de45637a09 100644 --- a/tests/ui/never_type/dependency-on-fallback-to-unit.stderr +++ b/tests/ui/never_type/dependency-on-fallback-to-unit.stderr @@ -4,14 +4,14 @@ error: this function depends on never type fallback being `()` LL | fn def() { | ^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! - = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `!: Default` will fail --> $DIR/dependency-on-fallback-to-unit.rs:10:19 | LL | false => <_>::default(), | ^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see = note: `#[deny(dependency_on_unit_never_type_fallback)]` (part of `#[deny(rust_2024_compatibility)]`) on by default help: use `()` annotations to avoid fallback changes | @@ -25,14 +25,14 @@ error: this function depends on never type fallback being `()` LL | fn question_mark() -> Result<(), ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! - = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `!: Default` will fail --> $DIR/dependency-on-fallback-to-unit.rs:20:5 | LL | deserialize()?; | ^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see help: use `()` annotations to avoid fallback changes | LL | deserialize::<()>()?; @@ -47,14 +47,14 @@ error: this function depends on never type fallback being `()` LL | fn def() { | ^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! - = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `!: Default` will fail --> $DIR/dependency-on-fallback-to-unit.rs:10:19 | LL | false => <_>::default(), | ^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see = note: `#[deny(dependency_on_unit_never_type_fallback)]` (part of `#[deny(rust_2024_compatibility)]`) on by default help: use `()` annotations to avoid fallback changes | @@ -69,14 +69,14 @@ error: this function depends on never type fallback being `()` LL | fn question_mark() -> Result<(), ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! - = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `!: Default` will fail --> $DIR/dependency-on-fallback-to-unit.rs:20:5 | LL | deserialize()?; | ^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see = note: `#[deny(dependency_on_unit_never_type_fallback)]` (part of `#[deny(rust_2024_compatibility)]`) on by default help: use `()` annotations to avoid fallback changes | diff --git a/tests/ui/never_type/diverging-fallback-unconstrained-return.e2021.stderr b/tests/ui/never_type/diverging-fallback-unconstrained-return.e2021.stderr index eb79cf5dd1559..40e7e30274be8 100644 --- a/tests/ui/never_type/diverging-fallback-unconstrained-return.e2021.stderr +++ b/tests/ui/never_type/diverging-fallback-unconstrained-return.e2021.stderr @@ -4,14 +4,14 @@ error: this function depends on never type fallback being `()` LL | fn main() { | ^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! - = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `!: UnitReturn` will fail --> $DIR/diverging-fallback-unconstrained-return.rs:37:23 | LL | let _ = if true { unconstrained_return() } else { panic!() }; | ^^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see = note: `#[deny(dependency_on_unit_never_type_fallback)]` (part of `#[deny(rust_2024_compatibility)]`) on by default help: use `()` annotations to avoid fallback changes | @@ -27,14 +27,14 @@ error: this function depends on never type fallback being `()` LL | fn main() { | ^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! - = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `!: UnitReturn` will fail --> $DIR/diverging-fallback-unconstrained-return.rs:37:23 | LL | let _ = if true { unconstrained_return() } else { panic!() }; | ^^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see = note: `#[deny(dependency_on_unit_never_type_fallback)]` (part of `#[deny(rust_2024_compatibility)]`) on by default help: use `()` annotations to avoid fallback changes | diff --git a/tests/ui/never_type/dont-suggest-turbofish-from-expansion.stderr b/tests/ui/never_type/dont-suggest-turbofish-from-expansion.stderr index 9795acffe7058..73c2a5bd3907e 100644 --- a/tests/ui/never_type/dont-suggest-turbofish-from-expansion.stderr +++ b/tests/ui/never_type/dont-suggest-turbofish-from-expansion.stderr @@ -4,14 +4,14 @@ error: this function depends on never type fallback being `()` LL | fn main() -> Result<(), ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! - = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `!: Default` will fail --> $DIR/dont-suggest-turbofish-from-expansion.rs:12:23 | LL | let created = create_ok_default()?; | ^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see = note: `#[deny(dependency_on_unit_never_type_fallback)]` (part of `#[deny(rust_2024_compatibility)]`) on by default help: use `()` annotations to avoid fallback changes | @@ -27,14 +27,14 @@ error: this function depends on never type fallback being `()` LL | fn main() -> Result<(), ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! - = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `!: Default` will fail --> $DIR/dont-suggest-turbofish-from-expansion.rs:12:23 | LL | let created = create_ok_default()?; | ^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see = note: `#[deny(dependency_on_unit_never_type_fallback)]` (part of `#[deny(rust_2024_compatibility)]`) on by default help: use `()` annotations to avoid fallback changes | diff --git a/tests/ui/never_type/lint-breaking-2024-assign-underscore.stderr b/tests/ui/never_type/lint-breaking-2024-assign-underscore.stderr index 96749de1195eb..a0a300aae6af7 100644 --- a/tests/ui/never_type/lint-breaking-2024-assign-underscore.stderr +++ b/tests/ui/never_type/lint-breaking-2024-assign-underscore.stderr @@ -4,14 +4,14 @@ error: this function depends on never type fallback being `()` LL | fn test() -> Result<(), ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! - = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `!: Default` will fail --> $DIR/lint-breaking-2024-assign-underscore.rs:11:9 | LL | _ = foo()?; | ^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see = note: `#[deny(dependency_on_unit_never_type_fallback)]` (part of `#[deny(rust_2024_compatibility)]`) on by default help: use `()` annotations to avoid fallback changes | @@ -27,14 +27,14 @@ error: this function depends on never type fallback being `()` LL | fn test() -> Result<(), ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! - = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `!: Default` will fail --> $DIR/lint-breaking-2024-assign-underscore.rs:11:9 | LL | _ = foo()?; | ^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see = note: `#[deny(dependency_on_unit_never_type_fallback)]` (part of `#[deny(rust_2024_compatibility)]`) on by default help: use `()` annotations to avoid fallback changes | diff --git a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2015.stderr b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2015.stderr index 84e143b024acc..730e449704859 100644 --- a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2015.stderr +++ b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2015.stderr @@ -4,9 +4,9 @@ error: never type fallback affects this call to an `unsafe` function LL | unsafe { mem::zeroed() } | ^^^^^^^^^^^^^ | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` (part of `#[deny(rust_2024_compatibility)]`) on by default help: use `()` annotations to avoid fallback changes | @@ -19,9 +19,9 @@ error: never type fallback affects this call to an `unsafe` function LL | core::mem::transmute(Zst) | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly help: use `()` annotations to avoid fallback changes | LL | core::mem::transmute::<_, ()>(Zst) @@ -33,9 +33,9 @@ error: never type fallback affects this union access LL | unsafe { Union { a: () }.b } | ^^^^^^^^^^^^^^^^^ | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly error: never type fallback affects this raw pointer dereference --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:55:18 @@ -43,9 +43,9 @@ error: never type fallback affects this raw pointer dereference LL | unsafe { *ptr::from_ref(&()).cast() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly help: use `()` annotations to avoid fallback changes | LL | unsafe { *ptr::from_ref(&()).cast::<()>() } @@ -57,9 +57,9 @@ error: never type fallback affects this call to an `unsafe` function LL | unsafe { internally_create(x) } | ^^^^^^^^^^^^^^^^^^^^ | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly help: use `()` annotations to avoid fallback changes | LL | unsafe { internally_create::<()>(x) } @@ -71,9 +71,9 @@ error: never type fallback affects this call to an `unsafe` function LL | unsafe { zeroed() } | ^^^^^^^^ | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly help: use `()` annotations to avoid fallback changes | LL | let zeroed = mem::zeroed::<()>; @@ -85,9 +85,9 @@ error: never type fallback affects this `unsafe` function LL | let zeroed = mem::zeroed; | ^^^^^^^^^^^ | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly help: use `()` annotations to avoid fallback changes | LL | let zeroed = mem::zeroed::<()>; @@ -99,9 +99,9 @@ error: never type fallback affects this `unsafe` function LL | let f = internally_create; | ^^^^^^^^^^^^^^^^^ | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly help: use `()` annotations to avoid fallback changes | LL | let f = internally_create::<()>; @@ -113,9 +113,9 @@ error: never type fallback affects this call to an `unsafe` method LL | S(marker::PhantomData).create_out_of_thin_air() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly error: never type fallback affects this call to an `unsafe` function --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:155:19 @@ -126,9 +126,9 @@ LL | match send_message::<_ /* ?0 */>() { LL | msg_send!(); | ----------- in this macro invocation | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly = note: this error originates in the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 10 previous errors @@ -140,9 +140,9 @@ error: never type fallback affects this call to an `unsafe` function LL | unsafe { mem::zeroed() } | ^^^^^^^^^^^^^ | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` (part of `#[deny(rust_2024_compatibility)]`) on by default help: use `()` annotations to avoid fallback changes | @@ -156,9 +156,9 @@ error: never type fallback affects this call to an `unsafe` function LL | core::mem::transmute(Zst) | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` (part of `#[deny(rust_2024_compatibility)]`) on by default help: use `()` annotations to avoid fallback changes | @@ -172,9 +172,9 @@ error: never type fallback affects this union access LL | unsafe { Union { a: () }.b } | ^^^^^^^^^^^^^^^^^ | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` (part of `#[deny(rust_2024_compatibility)]`) on by default Future breakage diagnostic: @@ -184,9 +184,9 @@ error: never type fallback affects this raw pointer dereference LL | unsafe { *ptr::from_ref(&()).cast() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` (part of `#[deny(rust_2024_compatibility)]`) on by default help: use `()` annotations to avoid fallback changes | @@ -200,9 +200,9 @@ error: never type fallback affects this call to an `unsafe` function LL | unsafe { internally_create(x) } | ^^^^^^^^^^^^^^^^^^^^ | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` (part of `#[deny(rust_2024_compatibility)]`) on by default help: use `()` annotations to avoid fallback changes | @@ -216,9 +216,9 @@ error: never type fallback affects this call to an `unsafe` function LL | unsafe { zeroed() } | ^^^^^^^^ | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` (part of `#[deny(rust_2024_compatibility)]`) on by default help: use `()` annotations to avoid fallback changes | @@ -232,9 +232,9 @@ error: never type fallback affects this `unsafe` function LL | let zeroed = mem::zeroed; | ^^^^^^^^^^^ | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` (part of `#[deny(rust_2024_compatibility)]`) on by default help: use `()` annotations to avoid fallback changes | @@ -248,9 +248,9 @@ error: never type fallback affects this `unsafe` function LL | let f = internally_create; | ^^^^^^^^^^^^^^^^^ | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` (part of `#[deny(rust_2024_compatibility)]`) on by default help: use `()` annotations to avoid fallback changes | @@ -264,9 +264,9 @@ error: never type fallback affects this call to an `unsafe` method LL | S(marker::PhantomData).create_out_of_thin_air() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` (part of `#[deny(rust_2024_compatibility)]`) on by default Future breakage diagnostic: @@ -279,9 +279,9 @@ LL | match send_message::<_ /* ?0 */>() { LL | msg_send!(); | ----------- in this macro invocation | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` (part of `#[deny(rust_2024_compatibility)]`) on by default = note: this error originates in the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr index 09e4d02384e92..631b6dae92942 100644 --- a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr +++ b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr @@ -4,9 +4,9 @@ error: never type fallback affects this call to an `unsafe` function LL | unsafe { mem::zeroed() } | ^^^^^^^^^^^^^ | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` (part of `#[deny(rust_2024_compatibility)]`) on by default help: use `()` annotations to avoid fallback changes | @@ -19,9 +19,9 @@ error: never type fallback affects this call to an `unsafe` function LL | core::mem::transmute(Zst) | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly help: use `()` annotations to avoid fallback changes | LL | core::mem::transmute::<_, ()>(Zst) @@ -33,9 +33,9 @@ error: never type fallback affects this union access LL | unsafe { Union { a: () }.b } | ^^^^^^^^^^^^^^^^^ | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly error: never type fallback affects this raw pointer dereference --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:55:18 @@ -43,9 +43,9 @@ error: never type fallback affects this raw pointer dereference LL | unsafe { *ptr::from_ref(&()).cast() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly help: use `()` annotations to avoid fallback changes | LL | unsafe { *ptr::from_ref(&()).cast::<()>() } @@ -57,9 +57,9 @@ error: never type fallback affects this call to an `unsafe` function LL | unsafe { internally_create(x) } | ^^^^^^^^^^^^^^^^^^^^ | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly help: use `()` annotations to avoid fallback changes | LL | unsafe { internally_create::<()>(x) } @@ -71,9 +71,9 @@ error: never type fallback affects this call to an `unsafe` function LL | unsafe { zeroed() } | ^^^^^^^^ | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly help: use `()` annotations to avoid fallback changes | LL | let zeroed = mem::zeroed::<()>; @@ -85,9 +85,9 @@ error: never type fallback affects this `unsafe` function LL | let zeroed = mem::zeroed; | ^^^^^^^^^^^ | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly help: use `()` annotations to avoid fallback changes | LL | let zeroed = mem::zeroed::<()>; @@ -99,9 +99,9 @@ error: never type fallback affects this `unsafe` function LL | let f = internally_create; | ^^^^^^^^^^^^^^^^^ | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly help: use `()` annotations to avoid fallback changes | LL | let f = internally_create::<()>; @@ -113,9 +113,9 @@ error: never type fallback affects this call to an `unsafe` method LL | S(marker::PhantomData).create_out_of_thin_air() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly error: never type fallback affects this call to an `unsafe` function --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:155:19 @@ -126,9 +126,9 @@ LL | match send_message::<_ /* ?0 */>() { LL | msg_send!(); | ----------- in this macro invocation | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly = note: this error originates in the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info) warning: the type `!` does not permit zero-initialization @@ -149,9 +149,9 @@ error: never type fallback affects this call to an `unsafe` function LL | unsafe { mem::zeroed() } | ^^^^^^^^^^^^^ | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` (part of `#[deny(rust_2024_compatibility)]`) on by default help: use `()` annotations to avoid fallback changes | @@ -165,9 +165,9 @@ error: never type fallback affects this call to an `unsafe` function LL | core::mem::transmute(Zst) | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` (part of `#[deny(rust_2024_compatibility)]`) on by default help: use `()` annotations to avoid fallback changes | @@ -181,9 +181,9 @@ error: never type fallback affects this union access LL | unsafe { Union { a: () }.b } | ^^^^^^^^^^^^^^^^^ | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` (part of `#[deny(rust_2024_compatibility)]`) on by default Future breakage diagnostic: @@ -193,9 +193,9 @@ error: never type fallback affects this raw pointer dereference LL | unsafe { *ptr::from_ref(&()).cast() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` (part of `#[deny(rust_2024_compatibility)]`) on by default help: use `()` annotations to avoid fallback changes | @@ -209,9 +209,9 @@ error: never type fallback affects this call to an `unsafe` function LL | unsafe { internally_create(x) } | ^^^^^^^^^^^^^^^^^^^^ | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` (part of `#[deny(rust_2024_compatibility)]`) on by default help: use `()` annotations to avoid fallback changes | @@ -225,9 +225,9 @@ error: never type fallback affects this call to an `unsafe` function LL | unsafe { zeroed() } | ^^^^^^^^ | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` (part of `#[deny(rust_2024_compatibility)]`) on by default help: use `()` annotations to avoid fallback changes | @@ -241,9 +241,9 @@ error: never type fallback affects this `unsafe` function LL | let zeroed = mem::zeroed; | ^^^^^^^^^^^ | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` (part of `#[deny(rust_2024_compatibility)]`) on by default help: use `()` annotations to avoid fallback changes | @@ -257,9 +257,9 @@ error: never type fallback affects this `unsafe` function LL | let f = internally_create; | ^^^^^^^^^^^^^^^^^ | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` (part of `#[deny(rust_2024_compatibility)]`) on by default help: use `()` annotations to avoid fallback changes | @@ -273,9 +273,9 @@ error: never type fallback affects this call to an `unsafe` method LL | S(marker::PhantomData).create_out_of_thin_air() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` (part of `#[deny(rust_2024_compatibility)]`) on by default Future breakage diagnostic: @@ -288,9 +288,9 @@ LL | match send_message::<_ /* ?0 */>() { LL | msg_send!(); | ----------- in this macro invocation | + = help: specify the type explicitly = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see - = help: specify the type explicitly = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` (part of `#[deny(rust_2024_compatibility)]`) on by default = note: this error originates in the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/parser/inner-attr.stderr b/tests/ui/parser/inner-attr.stderr index 3fb2d60ee5b66..0f9c7561490a9 100644 --- a/tests/ui/parser/inner-attr.stderr +++ b/tests/ui/parser/inner-attr.stderr @@ -11,17 +11,18 @@ LL | fn main() {} | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files -warning: crate-level attribute should be an inner attribute +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![feature]` --> $DIR/inner-attr.rs:1:1 | LL | #[feature(lang_items)] | ^^^^^^^^^^^^^^^^^^^^^^ | - = note: requested on the command line with `-W unused-attributes` -help: add a `!` +note: this attribute does not have an `!`, which means it is applied to this function + --> $DIR/inner-attr.rs:4:1 | -LL | #![feature(lang_items)] - | + +LL | fn main() {} + | ^^^^^^^^^^^^ + = note: requested on the command line with `-W unused-attributes` error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/reflection/trait_info_of_too_big.rs b/tests/ui/reflection/trait_info_of_too_big.rs new file mode 100644 index 0000000000000..0d5224e788ac7 --- /dev/null +++ b/tests/ui/reflection/trait_info_of_too_big.rs @@ -0,0 +1,20 @@ +//@ normalize-stderr: "\[u8; [0-9]+\]" -> "[u8; N]" +//! Test for https://github.com/rust-lang/rust/pull/152003 + +#![feature(type_info)] + +use std::any::TypeId; + +trait Trait {} +impl Trait for [u8; usize::MAX] {} + +fn main() {} + +const _: () = const { + TypeId::of::<[u8; usize::MAX]>().trait_info_of_trait_type_id(TypeId::of::()); + //~^ ERROR values of the type `[u8; usize::MAX]` are too big for the target architecture +}; +const _: () = const { + TypeId::of::<[u8; usize::MAX]>().trait_info_of::(); + //~^ ERROR values of the type `[u8; usize::MAX]` are too big for the target architecture +}; diff --git a/tests/ui/reflection/trait_info_of_too_big.stderr b/tests/ui/reflection/trait_info_of_too_big.stderr new file mode 100644 index 0000000000000..fa41d3c9ec90e --- /dev/null +++ b/tests/ui/reflection/trait_info_of_too_big.stderr @@ -0,0 +1,27 @@ +error[E0080]: values of the type `[u8; usize::MAX]` are too big for the target architecture + --> $DIR/trait_info_of_too_big.rs:14:5 + | +LL | TypeId::of::<[u8; usize::MAX]>().trait_info_of_trait_type_id(TypeId::of::()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_::{constant#0}` failed inside this call + | +note: inside `TypeId::trait_info_of_trait_type_id` + --> $SRC_DIR/core/src/any.rs:LL:COL +note: inside `type_info::::info` + --> $SRC_DIR/core/src/mem/type_info.rs:LL:COL + +error[E0080]: values of the type `[u8; usize::MAX]` are too big for the target architecture + --> $DIR/trait_info_of_too_big.rs:18:5 + | +LL | TypeId::of::<[u8; usize::MAX]>().trait_info_of::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_::{constant#0}` failed inside this call + | +note: inside `TypeId::trait_info_of::` + --> $SRC_DIR/core/src/any.rs:LL:COL +note: inside `TypeId::trait_info_of_trait_type_id` + --> $SRC_DIR/core/src/any.rs:LL:COL +note: inside `type_info::::info` + --> $SRC_DIR/core/src/mem/type_info.rs:LL:COL + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/type-alias-impl-trait/issue-60662.stdout b/tests/ui/type-alias-impl-trait/issue-60662.stdout index dff748b43119d..99aa6caa30dbd 100644 --- a/tests/ui/type-alias-impl-trait/issue-60662.stdout +++ b/tests/ui/type-alias-impl-trait/issue-60662.stdout @@ -1,11 +1,11 @@ +#![attr = Feature([type_alias_impl_trait#0])] +extern crate std; +#[attr = PreludeImport] +use ::std::prelude::rust_2015::*; //@ check-pass //@ compile-flags: -Z unpretty=hir //@ edition: 2015 -#![feature(type_alias_impl_trait)] -extern crate std; -#[attr = PreludeImport] -use ::std::prelude::rust_2015::*; trait Animal { } diff --git a/tests/ui/unpretty/exhaustive.hir.stdout b/tests/ui/unpretty/exhaustive.hir.stdout index 7ee848491d6e5..78403e1704dca 100644 --- a/tests/ui/unpretty/exhaustive.hir.stdout +++ b/tests/ui/unpretty/exhaustive.hir.stdout @@ -8,28 +8,13 @@ // Note: the HIR revision includes a `.stderr` file because there are some // errors that only occur once we get past the AST. -#![feature(auto_traits)] -#![feature(box_patterns)] -#![feature(builtin_syntax)] -#![feature(const_trait_impl)] -#![feature(coroutines)] -#![feature(decl_macro)] -#![feature(deref_patterns)] -#![feature(explicit_tail_calls)] -#![feature(gen_blocks)] -#![feature(more_qualified_paths)] -#![feature(never_patterns)] -#![feature(never_type)] -#![feature(pattern_types)] -#![feature(pattern_type_macro)] -#![feature(prelude_import)] -#![feature(specialization)] -#![feature(trace_macros)] -#![feature(trait_alias)] -#![feature(try_blocks)] -#![feature(try_blocks_heterogeneous)] -#![feature(yeet_expr)] #![allow(incomplete_features)] +#![attr = Feature([auto_traits#0, box_patterns#0, builtin_syntax#0, +const_trait_impl#0, coroutines#0, decl_macro#0, deref_patterns#0, +explicit_tail_calls#0, gen_blocks#0, more_qualified_paths#0, never_patterns#0, +never_type#0, pattern_types#0, pattern_type_macro#0, prelude_import#0, +specialization#0, trace_macros#0, trait_alias#0, try_blocks#0, +try_blocks_heterogeneous#0, yeet_expr#0])] extern crate std; #[attr = PreludeImport] use std::prelude::rust_2024::*; diff --git a/tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.stdout b/tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.stdout index c990837d2138a..8c016f5083d24 100644 --- a/tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.stdout +++ b/tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.stdout @@ -1,9 +1,9 @@ //@ compile-flags: -Zunpretty=hir //@ check-pass -#![feature(min_generic_const_args, adt_const_params)] #![expect(incomplete_features)] #![allow(dead_code)] +#![attr = Feature([min_generic_const_args#0, adt_const_params#0])] extern crate std; #[attr = PreludeImport] use ::std::prelude::rust_2015::*; diff --git a/tests/ui/use/use-super-in-middle.rs b/tests/ui/use/use-super-in-middle.rs new file mode 100644 index 0000000000000..be9f3675c323f --- /dev/null +++ b/tests/ui/use/use-super-in-middle.rs @@ -0,0 +1,14 @@ +pub mod x { + pub use crate::x::super::{self as crate1}; //~ ERROR `super` in paths can only be used in start position + pub use crate::x::self::super::{self as crate2}; //~ ERROR `super` in paths can only be used in start position + + pub fn foo() {} +} + +fn main() { + x::crate1::x::foo(); //~ ERROR cannot find `crate1` in `x` + x::crate2::x::foo(); //~ ERROR cannot find `crate2` in `x` + + crate::x::super::x::foo(); //~ ERROR `super` in paths can only be used in start position + crate::x::self::super::x::foo(); //~ ERROR `self` in paths can only be used in start position +} diff --git a/tests/ui/use/use-super-in-middle.stderr b/tests/ui/use/use-super-in-middle.stderr new file mode 100644 index 0000000000000..276b1274f6a89 --- /dev/null +++ b/tests/ui/use/use-super-in-middle.stderr @@ -0,0 +1,39 @@ +error: `super` in paths can only be used in start position, after `self`, or after another `super` + --> $DIR/use-super-in-middle.rs:2:23 + | +LL | pub use crate::x::super::{self as crate1}; + | ^^^^^ + +error: `super` in paths can only be used in start position, after `self`, or after another `super` + --> $DIR/use-super-in-middle.rs:3:29 + | +LL | pub use crate::x::self::super::{self as crate2}; + | ^^^^^ + +error[E0433]: cannot find `crate1` in `x` + --> $DIR/use-super-in-middle.rs:9:8 + | +LL | x::crate1::x::foo(); + | ^^^^^^ could not find `crate1` in `x` + +error[E0433]: cannot find `crate2` in `x` + --> $DIR/use-super-in-middle.rs:10:8 + | +LL | x::crate2::x::foo(); + | ^^^^^^ could not find `crate2` in `x` + +error[E0433]: `super` in paths can only be used in start position + --> $DIR/use-super-in-middle.rs:12:15 + | +LL | crate::x::super::x::foo(); + | ^^^^^ can only be used in path start position + +error[E0433]: `self` in paths can only be used in start position + --> $DIR/use-super-in-middle.rs:13:15 + | +LL | crate::x::self::super::x::foo(); + | ^^^^ can only be used in path start position + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0433`.