From 29ae6174710f85878b98ccaf8f6304d893e3346a Mon Sep 17 00:00:00 2001 From: beetrees Date: Sat, 17 Aug 2024 05:32:09 +0100 Subject: [PATCH 01/17] Pass end position of span through inline ASM cookie --- compiler/rustc_codegen_llvm/src/asm.rs | 21 +- compiler/rustc_codegen_llvm/src/back/write.rs | 23 +- .../rustc_codegen_llvm/src/llvm/diagnostic.rs | 2 +- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 2 +- compiler/rustc_codegen_ssa/src/back/write.rs | 21 +- .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 2 +- compiler/rustc_span/src/lib.rs | 6 + tests/ui/asm/aarch64/srcloc.new.stderr | 320 +++++++++++++++++ .../{srcloc.stderr => srcloc.old.stderr} | 48 +-- tests/ui/asm/aarch64/srcloc.rs | 3 + tests/ui/asm/inline-syntax.arm.stderr | 24 +- tests/ui/asm/inline-syntax.arm_llvm_18.stderr | 90 +++++ tests/ui/asm/inline-syntax.rs | 16 +- tests/ui/asm/inline-syntax.x86_64.stderr | 14 +- tests/ui/asm/x86_64/srcloc.new.stderr | 332 ++++++++++++++++++ .../{srcloc.stderr => srcloc.old.stderr} | 50 +-- tests/ui/asm/x86_64/srcloc.rs | 3 + 17 files changed, 874 insertions(+), 103 deletions(-) create mode 100644 tests/ui/asm/aarch64/srcloc.new.stderr rename tests/ui/asm/aarch64/{srcloc.stderr => srcloc.old.stderr} (88%) create mode 100644 tests/ui/asm/inline-syntax.arm_llvm_18.stderr create mode 100644 tests/ui/asm/x86_64/srcloc.new.stderr rename tests/ui/asm/x86_64/{srcloc.stderr => srcloc.old.stderr} (90%) diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 82ca3f519f740..ee76082984952 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -487,14 +487,13 @@ pub(crate) fn inline_asm_call<'ll>( let key = "srcloc"; let kind = llvm::LLVMGetMDKindIDInContext( bx.llcx, - key.as_ptr() as *const c_char, + key.as_ptr().cast::(), key.len() as c_uint, ); - // srcloc contains one integer for each line of assembly code. - // Unfortunately this isn't enough to encode a full span so instead - // we just encode the start position of each line. - // FIXME: Figure out a way to pass the entire line spans. + // `srcloc` contains one 64-bit integer for each line of assembly code, + // where the lower 32 bits hold the lo byte position and the upper 32 bits + // hold the hi byte position. let mut srcloc = vec![]; if dia == llvm::AsmDialect::Intel && line_spans.len() > 1 { // LLVM inserts an extra line to add the ".intel_syntax", so add @@ -504,13 +503,13 @@ pub(crate) fn inline_asm_call<'ll>( // due to the asm template string coming from a macro. LLVM will // default to the first srcloc for lines that don't have an // associated srcloc. - srcloc.push(llvm::LLVMValueAsMetadata(bx.const_i32(0))); + srcloc.push(llvm::LLVMValueAsMetadata(bx.const_u64(0))); } - srcloc.extend( - line_spans - .iter() - .map(|span| llvm::LLVMValueAsMetadata(bx.const_i32(span.lo().to_u32() as i32))), - ); + srcloc.extend(line_spans.iter().map(|span| { + llvm::LLVMValueAsMetadata(bx.const_u64( + u64::from(span.lo().to_u32()) | (u64::from(span.hi().to_u32()) << 32), + )) + })); let md = llvm::LLVMMDNodeInContext2(bx.llcx, srcloc.as_ptr(), srcloc.len()); let md = llvm::LLVMMetadataAsValue(&bx.llcx, md); llvm::LLVMSetMetadata(call, kind, md); diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index afdd2b581b86e..4376876a11307 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -24,8 +24,8 @@ use rustc_session::Session; use rustc_session::config::{ self, Lto, OutputType, Passes, RemapPathScopeComponents, SplitDwarfKind, SwitchWithOptPath, }; -use rustc_span::InnerSpan; use rustc_span::symbol::sym; +use rustc_span::{BytePos, InnerSpan, Pos, SpanData, SyntaxContext}; use rustc_target::spec::{CodeModel, RelocModel, SanitizerSet, SplitDebuginfo, TlsModel}; use tracing::debug; @@ -411,21 +411,32 @@ fn report_inline_asm( cgcx: &CodegenContext, msg: String, level: llvm::DiagnosticLevel, - mut cookie: u64, + cookie: u64, source: Option<(String, Vec)>, ) { // In LTO build we may get srcloc values from other crates which are invalid // since they use a different source map. To be safe we just suppress these // in LTO builds. - if matches!(cgcx.lto, Lto::Fat | Lto::Thin) { - cookie = 0; - } + let span = if cookie == 0 || matches!(cgcx.lto, Lto::Fat | Lto::Thin) { + SpanData::default() + } else { + let lo = BytePos::from_u32(cookie as u32); + let hi = BytePos::from_u32((cookie >> 32) as u32); + SpanData { + lo, + // LLVM version < 19 silently truncates the cookie to 32 bits in some situations. + hi: if hi.to_u32() != 0 { hi } else { lo }, + ctxt: SyntaxContext::root(), + parent: None, + } + }; let level = match level { llvm::DiagnosticLevel::Error => Level::Error, llvm::DiagnosticLevel::Warning => Level::Warning, llvm::DiagnosticLevel::Note | llvm::DiagnosticLevel::Remark => Level::Note, }; - cgcx.diag_emitter.inline_asm_error(cookie.try_into().unwrap(), msg, level, source); + let msg = msg.strip_prefix("error: ").unwrap_or(&msg).to_string(); + cgcx.diag_emitter.inline_asm_error(span, msg, level, source); } unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void) { diff --git a/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs index a4cb5a25d1b36..11043b664f526 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs @@ -151,7 +151,7 @@ impl InlineAsmDiagnostic { unsafe { SrcMgrDiagnostic::unpack(super::LLVMRustGetSMDiagnostic(di, &mut cookie)) }; InlineAsmDiagnostic { level: smdiag.level, - cookie: cookie.into(), + cookie, message: smdiag.message, source: smdiag.source, } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 661debbb9f126..c9f89b9cf3f9b 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2271,7 +2271,7 @@ unsafe extern "C" { pub fn LLVMRustGetSMDiagnostic<'a>( DI: &'a DiagnosticInfo, - cookie_out: &mut c_uint, + cookie_out: &mut u64, ) -> &'a SMDiagnostic; #[allow(improper_ctypes)] diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index e3d11cfaf4fe3..8265dbfb73f6d 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -34,7 +34,7 @@ use rustc_session::config::{ }; use rustc_span::source_map::SourceMap; use rustc_span::symbol::sym; -use rustc_span::{BytePos, FileName, InnerSpan, Pos, Span}; +use rustc_span::{FileName, InnerSpan, Span, SpanData}; use rustc_target::spec::{MergeFunctions, SanitizerSet}; use tracing::debug; @@ -1852,7 +1852,7 @@ fn spawn_work<'a, B: ExtraBackendMethods>( enum SharedEmitterMessage { Diagnostic(Diagnostic), - InlineAsmError(u32, String, Level, Option<(String, Vec)>), + InlineAsmError(SpanData, String, Level, Option<(String, Vec)>), Fatal(String), } @@ -1874,12 +1874,12 @@ impl SharedEmitter { pub fn inline_asm_error( &self, - cookie: u32, + span: SpanData, msg: String, level: Level, source: Option<(String, Vec)>, ) { - drop(self.sender.send(SharedEmitterMessage::InlineAsmError(cookie, msg, level, source))); + drop(self.sender.send(SharedEmitterMessage::InlineAsmError(span, msg, level, source))); } fn fatal(&self, msg: &str) { @@ -1964,17 +1964,12 @@ impl SharedEmitterMain { dcx.emit_diagnostic(d); sess.dcx().abort_if_errors(); } - Ok(SharedEmitterMessage::InlineAsmError(cookie, msg, level, source)) => { + Ok(SharedEmitterMessage::InlineAsmError(span, msg, level, source)) => { assert_matches!(level, Level::Error | Level::Warning | Level::Note); - let msg = msg.strip_prefix("error: ").unwrap_or(&msg).to_string(); let mut err = Diag::<()>::new(sess.dcx(), level, msg); - - // If the cookie is 0 then we don't have span information. - if cookie != 0 { - let pos = BytePos::from_u32(cookie); - let span = Span::with_root_ctxt(pos, pos); - err.span(span); - }; + if !span.is_dummy() { + err.span(span.span()); + } // Point to the generated assembly if it is available. if let Some((buffer, spans)) = source { diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 72b03fa0560e6..200bdd57ed6a9 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1445,7 +1445,7 @@ extern "C" LLVMTypeKind LLVMRustGetTypeKind(LLVMTypeRef Ty) { DEFINE_SIMPLE_CONVERSION_FUNCTIONS(SMDiagnostic, LLVMSMDiagnosticRef) extern "C" LLVMSMDiagnosticRef LLVMRustGetSMDiagnostic(LLVMDiagnosticInfoRef DI, - unsigned *Cookie) { + uint64_t *Cookie) { llvm::DiagnosticInfoSrcMgr *SM = static_cast(unwrap(DI)); *Cookie = SM->getLocCookie(); diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 5b1be5bca0593..693ce7762b536 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -521,6 +521,12 @@ impl SpanData { } } +impl Default for SpanData { + fn default() -> Self { + Self { lo: BytePos(0), hi: BytePos(0), ctxt: SyntaxContext::root(), parent: None } + } +} + // The interner is pointed to by a thread local value which is only set on the main thread // with parallelization is disabled. So we don't allow `Span` to transfer between threads // to avoid panics and other errors, even though it would be memory safe to do so. diff --git a/tests/ui/asm/aarch64/srcloc.new.stderr b/tests/ui/asm/aarch64/srcloc.new.stderr new file mode 100644 index 0000000000000..b92a07e5fb131 --- /dev/null +++ b/tests/ui/asm/aarch64/srcloc.new.stderr @@ -0,0 +1,320 @@ +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:15:15 + | +LL | asm!("invalid_instruction"); + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:19:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :2:13 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:24:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :2:13 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:30:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :3:13 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:37:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :3:13 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:42:14 + | +LL | asm!(concat!("invalid", "_", "instruction")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:46:14 + | +LL | "invalid_instruction", + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:52:14 + | +LL | "invalid_instruction", + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :2:1 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:59:14 + | +LL | "invalid_instruction", + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :3:1 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:66:13 + | +LL | concat!("invalid", "_", "instruction"), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :2:1 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:73:13 + | +LL | concat!("invalid", "_", "instruction"), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :2:1 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:80:14 + | +LL | "invalid_instruction1", + | ^^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | invalid_instruction1 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:81:14 + | +LL | "invalid_instruction2", + | ^^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :2:1 + | +LL | invalid_instruction2 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:87:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction1", "\n", +LL | | "invalid", "_", "instruction2", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | invalid_instruction1 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:87:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction1", "\n", +LL | | "invalid", "_", "instruction2", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :2:1 + | +LL | invalid_instruction2 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:96:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction1", "\n", +LL | | "invalid", "_", "instruction2", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | invalid_instruction1 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:96:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction1", "\n", +LL | | "invalid", "_", "instruction2", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :2:1 + | +LL | invalid_instruction2 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:100:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction3", "\n", +LL | | "invalid", "_", "instruction4", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :3:1 + | +LL | invalid_instruction3 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:100:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction3", "\n", +LL | | "invalid", "_", "instruction4", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :4:1 + | +LL | invalid_instruction4 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:111:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction1", "\n", +LL | | "invalid", "_", "instruction2", "\n", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | invalid_instruction1 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:111:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction1", "\n", +LL | | "invalid", "_", "instruction2", "\n", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :2:1 + | +LL | invalid_instruction2 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:115:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction3", "\n", +LL | | "invalid", "_", "instruction4", "\n", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :4:1 + | +LL | invalid_instruction3 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:115:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction3", "\n", +LL | | "invalid", "_", "instruction4", "\n", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :5:1 + | +LL | invalid_instruction4 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:128:14 + | +LL | "invalid_instruction" + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :4:1 + | +LL | invalid_instruction + | ^ + +error: aborting due to 24 previous errors + diff --git a/tests/ui/asm/aarch64/srcloc.stderr b/tests/ui/asm/aarch64/srcloc.old.stderr similarity index 88% rename from tests/ui/asm/aarch64/srcloc.stderr rename to tests/ui/asm/aarch64/srcloc.old.stderr index 2e17b60b91243..2a15e48f0256d 100644 --- a/tests/ui/asm/aarch64/srcloc.stderr +++ b/tests/ui/asm/aarch64/srcloc.old.stderr @@ -1,5 +1,5 @@ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:12:15 + --> $DIR/srcloc.rs:15:15 | LL | asm!("invalid_instruction"); | ^ @@ -11,7 +11,7 @@ LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:16:13 + --> $DIR/srcloc.rs:19:13 | LL | invalid_instruction | ^ @@ -23,7 +23,7 @@ LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:21:13 + --> $DIR/srcloc.rs:24:13 | LL | invalid_instruction | ^ @@ -35,7 +35,7 @@ LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:27:13 + --> $DIR/srcloc.rs:30:13 | LL | invalid_instruction | ^ @@ -47,7 +47,7 @@ LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:34:13 + --> $DIR/srcloc.rs:37:13 | LL | invalid_instruction | ^ @@ -59,7 +59,7 @@ LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:39:14 + --> $DIR/srcloc.rs:42:14 | LL | asm!(concat!("invalid", "_", "instruction")); | ^ @@ -71,7 +71,7 @@ LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:43:14 + --> $DIR/srcloc.rs:46:14 | LL | "invalid_instruction", | ^ @@ -83,7 +83,7 @@ LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:49:14 + --> $DIR/srcloc.rs:52:14 | LL | "invalid_instruction", | ^ @@ -95,7 +95,7 @@ LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:56:14 + --> $DIR/srcloc.rs:59:14 | LL | "invalid_instruction", | ^ @@ -107,7 +107,7 @@ LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:63:13 + --> $DIR/srcloc.rs:66:13 | LL | concat!("invalid", "_", "instruction"), | ^ @@ -119,7 +119,7 @@ LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:70:13 + --> $DIR/srcloc.rs:73:13 | LL | concat!("invalid", "_", "instruction"), | ^ @@ -131,7 +131,7 @@ LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:77:14 + --> $DIR/srcloc.rs:80:14 | LL | "invalid_instruction1", | ^ @@ -143,7 +143,7 @@ LL | invalid_instruction1 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:78:14 + --> $DIR/srcloc.rs:81:14 | LL | "invalid_instruction2", | ^ @@ -155,7 +155,7 @@ LL | invalid_instruction2 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:84:13 + --> $DIR/srcloc.rs:87:13 | LL | concat!( | ^ @@ -167,7 +167,7 @@ LL | invalid_instruction1 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:84:13 + --> $DIR/srcloc.rs:87:13 | LL | concat!( | ^ @@ -179,7 +179,7 @@ LL | invalid_instruction2 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:93:13 + --> $DIR/srcloc.rs:96:13 | LL | concat!( | ^ @@ -191,7 +191,7 @@ LL | invalid_instruction1 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:93:13 + --> $DIR/srcloc.rs:96:13 | LL | concat!( | ^ @@ -203,7 +203,7 @@ LL | invalid_instruction2 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:97:13 + --> $DIR/srcloc.rs:100:13 | LL | concat!( | ^ @@ -215,7 +215,7 @@ LL | invalid_instruction3 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:97:13 + --> $DIR/srcloc.rs:100:13 | LL | concat!( | ^ @@ -227,7 +227,7 @@ LL | invalid_instruction4 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:108:13 + --> $DIR/srcloc.rs:111:13 | LL | concat!( | ^ @@ -239,7 +239,7 @@ LL | invalid_instruction1 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:108:13 + --> $DIR/srcloc.rs:111:13 | LL | concat!( | ^ @@ -251,7 +251,7 @@ LL | invalid_instruction2 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:112:13 + --> $DIR/srcloc.rs:115:13 | LL | concat!( | ^ @@ -263,7 +263,7 @@ LL | invalid_instruction3 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:112:13 + --> $DIR/srcloc.rs:115:13 | LL | concat!( | ^ @@ -275,7 +275,7 @@ LL | invalid_instruction4 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:125:14 + --> $DIR/srcloc.rs:128:14 | LL | "invalid_instruction" | ^ diff --git a/tests/ui/asm/aarch64/srcloc.rs b/tests/ui/asm/aarch64/srcloc.rs index c635fa6ba700a..9b92dfef056d0 100644 --- a/tests/ui/asm/aarch64/srcloc.rs +++ b/tests/ui/asm/aarch64/srcloc.rs @@ -1,7 +1,10 @@ +//@ revisions: old new //@ only-aarch64 //@ build-fail //@ needs-asm-support //@ compile-flags: -Ccodegen-units=1 +//@[old] ignore-llvm-version: 19 - 99 +//@[new] min-llvm-version: 19 use std::arch::asm; diff --git a/tests/ui/asm/inline-syntax.arm.stderr b/tests/ui/asm/inline-syntax.arm.stderr index 61e5078d6d9b4..e36ec125d13f2 100644 --- a/tests/ui/asm/inline-syntax.arm.stderr +++ b/tests/ui/asm/inline-syntax.arm.stderr @@ -15,10 +15,10 @@ LL | .intel_syntax noprefix | ^ error: unknown directive - --> $DIR/inline-syntax.rs:29:15 + --> $DIR/inline-syntax.rs:35:15 | LL | asm!(".intel_syntax noprefix", "nop"); - | ^ + | ^^^^^^^^^^^^^^^^^^^^^^ | note: instantiated into assembly here --> :1:2 @@ -27,10 +27,10 @@ LL | .intel_syntax noprefix | ^ error: unknown directive - --> $DIR/inline-syntax.rs:32:15 + --> $DIR/inline-syntax.rs:39:15 | LL | asm!(".intel_syntax aaa noprefix", "nop"); - | ^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: instantiated into assembly here --> :1:2 @@ -39,10 +39,10 @@ LL | .intel_syntax aaa noprefix | ^ error: unknown directive - --> $DIR/inline-syntax.rs:35:15 + --> $DIR/inline-syntax.rs:43:15 | LL | asm!(".att_syntax noprefix", "nop"); - | ^ + | ^^^^^^^^^^^^^^^^^^^^ | note: instantiated into assembly here --> :1:2 @@ -51,10 +51,10 @@ LL | .att_syntax noprefix | ^ error: unknown directive - --> $DIR/inline-syntax.rs:38:15 + --> $DIR/inline-syntax.rs:47:15 | LL | asm!(".att_syntax bbb noprefix", "nop"); - | ^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ | note: instantiated into assembly here --> :1:2 @@ -63,10 +63,10 @@ LL | .att_syntax bbb noprefix | ^ error: unknown directive - --> $DIR/inline-syntax.rs:41:15 + --> $DIR/inline-syntax.rs:51:15 | LL | asm!(".intel_syntax noprefix; nop"); - | ^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: instantiated into assembly here --> :1:2 @@ -75,10 +75,10 @@ LL | .intel_syntax noprefix; nop | ^ error: unknown directive - --> $DIR/inline-syntax.rs:47:13 + --> $DIR/inline-syntax.rs:58:13 | LL | .intel_syntax noprefix - | ^ + | ^^^^^^^^^^^^^^^^^^^^^^ | note: instantiated into assembly here --> :2:13 diff --git a/tests/ui/asm/inline-syntax.arm_llvm_18.stderr b/tests/ui/asm/inline-syntax.arm_llvm_18.stderr new file mode 100644 index 0000000000000..ada3f4891d3ac --- /dev/null +++ b/tests/ui/asm/inline-syntax.arm_llvm_18.stderr @@ -0,0 +1,90 @@ +error: unknown directive + | +note: instantiated into assembly here + --> :1:1 + | +LL | .intel_syntax noprefix + | ^ + +error: unknown directive + | +note: instantiated into assembly here + --> :1:1 + | +LL | .intel_syntax noprefix + | ^ + +error: unknown directive + --> $DIR/inline-syntax.rs:35:15 + | +LL | asm!(".intel_syntax noprefix", "nop"); + | ^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | .intel_syntax noprefix + | ^ + +error: unknown directive + --> $DIR/inline-syntax.rs:39:15 + | +LL | asm!(".intel_syntax aaa noprefix", "nop"); + | ^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | .intel_syntax aaa noprefix + | ^ + +error: unknown directive + --> $DIR/inline-syntax.rs:43:15 + | +LL | asm!(".att_syntax noprefix", "nop"); + | ^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | .att_syntax noprefix + | ^ + +error: unknown directive + --> $DIR/inline-syntax.rs:47:15 + | +LL | asm!(".att_syntax bbb noprefix", "nop"); + | ^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | .att_syntax bbb noprefix + | ^ + +error: unknown directive + --> $DIR/inline-syntax.rs:51:15 + | +LL | asm!(".intel_syntax noprefix; nop"); + | ^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | .intel_syntax noprefix; nop + | ^ + +error: unknown directive + --> $DIR/inline-syntax.rs:58:13 + | +LL | .intel_syntax noprefix + | ^ + | +note: instantiated into assembly here + --> :2:13 + | +LL | .intel_syntax noprefix + | ^ + +error: aborting due to 8 previous errors + diff --git a/tests/ui/asm/inline-syntax.rs b/tests/ui/asm/inline-syntax.rs index b8486527e6fd6..fda79b2afa388 100644 --- a/tests/ui/asm/inline-syntax.rs +++ b/tests/ui/asm/inline-syntax.rs @@ -1,10 +1,16 @@ -//@ revisions: x86_64 arm +//@ revisions: x86_64 arm_llvm_18 arm //@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu //@[x86_64] check-pass //@[x86_64] needs-llvm-components: x86 +//@[arm_llvm_18] compile-flags: --target armv7-unknown-linux-gnueabihf +//@[arm_llvm_18] build-fail +//@[arm_llvm_18] needs-llvm-components: arm +//@[arm_llvm_18] ignore-llvm-version: 19 - 99 +// LLVM 19+ has full support for 64-bit cookies. //@[arm] compile-flags: --target armv7-unknown-linux-gnueabihf //@[arm] build-fail //@[arm] needs-llvm-components: arm +//@[arm] min-llvm-version: 19 //@ needs-asm-support #![feature(no_core, lang_items, rustc_attrs)] @@ -29,18 +35,23 @@ pub fn main() { asm!(".intel_syntax noprefix", "nop"); //[x86_64]~^ WARN avoid using `.intel_syntax` //[arm]~^^ ERROR unknown directive + //[arm_llvm_18]~^^^ ERROR unknown directive asm!(".intel_syntax aaa noprefix", "nop"); //[x86_64]~^ WARN avoid using `.intel_syntax` //[arm]~^^ ERROR unknown directive + //[arm_llvm_18]~^^^ ERROR unknown directive asm!(".att_syntax noprefix", "nop"); //[x86_64]~^ WARN avoid using `.att_syntax` //[arm]~^^ ERROR unknown directive + //[arm_llvm_18]~^^^ ERROR unknown directive asm!(".att_syntax bbb noprefix", "nop"); //[x86_64]~^ WARN avoid using `.att_syntax` //[arm]~^^ ERROR unknown directive + //[arm_llvm_18]~^^^ ERROR unknown directive asm!(".intel_syntax noprefix; nop"); //[x86_64]~^ WARN avoid using `.intel_syntax` //[arm]~^^ ERROR unknown directive + //[arm_llvm_18]~^^^ ERROR unknown directive asm!( r" @@ -49,9 +60,10 @@ pub fn main() { ); //[x86_64]~^^^ WARN avoid using `.intel_syntax` //[arm]~^^^^ ERROR unknown directive + //[arm_llvm_18]~^^^^^ ERROR unknown directive } } global_asm!(".intel_syntax noprefix", "nop"); //[x86_64]~^ WARN avoid using `.intel_syntax` -// Assembler errors don't have line numbers, so no error on ARM +// Global assembly errors don't have line numbers, so no error on ARM. diff --git a/tests/ui/asm/inline-syntax.x86_64.stderr b/tests/ui/asm/inline-syntax.x86_64.stderr index 59c95194322aa..66dc37f3089e1 100644 --- a/tests/ui/asm/inline-syntax.x86_64.stderr +++ b/tests/ui/asm/inline-syntax.x86_64.stderr @@ -1,5 +1,5 @@ warning: avoid using `.intel_syntax`, Intel syntax is the default - --> $DIR/inline-syntax.rs:55:14 + --> $DIR/inline-syntax.rs:67:14 | LL | global_asm!(".intel_syntax noprefix", "nop"); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -7,37 +7,37 @@ LL | global_asm!(".intel_syntax noprefix", "nop"); = note: `#[warn(bad_asm_style)]` on by default warning: avoid using `.intel_syntax`, Intel syntax is the default - --> $DIR/inline-syntax.rs:29:15 + --> $DIR/inline-syntax.rs:35:15 | LL | asm!(".intel_syntax noprefix", "nop"); | ^^^^^^^^^^^^^^^^^^^^^^ warning: avoid using `.intel_syntax`, Intel syntax is the default - --> $DIR/inline-syntax.rs:32:15 + --> $DIR/inline-syntax.rs:39:15 | LL | asm!(".intel_syntax aaa noprefix", "nop"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: avoid using `.att_syntax`, prefer using `options(att_syntax)` instead - --> $DIR/inline-syntax.rs:35:15 + --> $DIR/inline-syntax.rs:43:15 | LL | asm!(".att_syntax noprefix", "nop"); | ^^^^^^^^^^^^^^^^^^^^ warning: avoid using `.att_syntax`, prefer using `options(att_syntax)` instead - --> $DIR/inline-syntax.rs:38:15 + --> $DIR/inline-syntax.rs:47:15 | LL | asm!(".att_syntax bbb noprefix", "nop"); | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: avoid using `.intel_syntax`, Intel syntax is the default - --> $DIR/inline-syntax.rs:41:15 + --> $DIR/inline-syntax.rs:51:15 | LL | asm!(".intel_syntax noprefix; nop"); | ^^^^^^^^^^^^^^^^^^^^^^ warning: avoid using `.intel_syntax`, Intel syntax is the default - --> $DIR/inline-syntax.rs:47:13 + --> $DIR/inline-syntax.rs:58:13 | LL | .intel_syntax noprefix | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/asm/x86_64/srcloc.new.stderr b/tests/ui/asm/x86_64/srcloc.new.stderr new file mode 100644 index 0000000000000..7211f1ab69dc0 --- /dev/null +++ b/tests/ui/asm/x86_64/srcloc.new.stderr @@ -0,0 +1,332 @@ +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:14:15 + | +LL | asm!("invalid_instruction"); + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :2:2 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:18:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :3:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:23:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :3:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:29:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :4:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:36:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :4:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:41:14 + | +LL | asm!(concat!("invalid", "_", "instruction")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :2:2 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +warning: scale factor without index register is ignored + --> $DIR/srcloc.rs:44:15 + | +LL | asm!("movaps %xmm3, (%esi, 2)", options(att_syntax)); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :1:23 + | +LL | movaps %xmm3, (%esi, 2) + | ^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:48:14 + | +LL | "invalid_instruction", + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :2:2 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:54:14 + | +LL | "invalid_instruction", + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :3:1 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:61:14 + | +LL | "invalid_instruction", + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :4:1 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:68:13 + | +LL | concat!("invalid", "_", "instruction"), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :3:1 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:75:13 + | +LL | concat!("invalid", "_", "instruction"), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :3:1 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction1' + --> $DIR/srcloc.rs:82:14 + | +LL | "invalid_instruction1", + | ^^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :2:2 + | +LL | invalid_instruction1 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction2' + --> $DIR/srcloc.rs:83:14 + | +LL | "invalid_instruction2", + | ^^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :3:1 + | +LL | invalid_instruction2 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction1' + --> $DIR/srcloc.rs:89:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction1", "\n", +LL | | "invalid", "_", "instruction2", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :2:2 + | +LL | invalid_instruction1 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction2' + --> $DIR/srcloc.rs:89:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction1", "\n", +LL | | "invalid", "_", "instruction2", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :3:1 + | +LL | invalid_instruction2 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction1' + --> $DIR/srcloc.rs:98:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction1", "\n", +LL | | "invalid", "_", "instruction2", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :2:2 + | +LL | invalid_instruction1 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction2' + --> $DIR/srcloc.rs:98:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction1", "\n", +LL | | "invalid", "_", "instruction2", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :3:1 + | +LL | invalid_instruction2 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction3' + --> $DIR/srcloc.rs:102:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction3", "\n", +LL | | "invalid", "_", "instruction4", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :4:1 + | +LL | invalid_instruction3 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction4' + --> $DIR/srcloc.rs:102:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction3", "\n", +LL | | "invalid", "_", "instruction4", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :5:1 + | +LL | invalid_instruction4 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction1' + --> $DIR/srcloc.rs:113:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction1", "\n", +LL | | "invalid", "_", "instruction2", "\n", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :2:2 + | +LL | invalid_instruction1 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction2' + --> $DIR/srcloc.rs:113:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction1", "\n", +LL | | "invalid", "_", "instruction2", "\n", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :3:1 + | +LL | invalid_instruction2 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction3' + --> $DIR/srcloc.rs:117:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction3", "\n", +LL | | "invalid", "_", "instruction4", "\n", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :5:1 + | +LL | invalid_instruction3 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction4' + --> $DIR/srcloc.rs:117:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction3", "\n", +LL | | "invalid", "_", "instruction4", "\n", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :6:1 + | +LL | invalid_instruction4 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:130:14 + | +LL | "invalid_instruction" + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :5:1 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 24 previous errors; 1 warning emitted + diff --git a/tests/ui/asm/x86_64/srcloc.stderr b/tests/ui/asm/x86_64/srcloc.old.stderr similarity index 90% rename from tests/ui/asm/x86_64/srcloc.stderr rename to tests/ui/asm/x86_64/srcloc.old.stderr index 8899c1b916bd0..edb9ee46812f8 100644 --- a/tests/ui/asm/x86_64/srcloc.stderr +++ b/tests/ui/asm/x86_64/srcloc.old.stderr @@ -1,5 +1,5 @@ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:11:15 + --> $DIR/srcloc.rs:14:15 | LL | asm!("invalid_instruction"); | ^ @@ -11,7 +11,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:15:13 + --> $DIR/srcloc.rs:18:13 | LL | invalid_instruction | ^ @@ -23,7 +23,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:20:13 + --> $DIR/srcloc.rs:23:13 | LL | invalid_instruction | ^ @@ -35,7 +35,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:26:13 + --> $DIR/srcloc.rs:29:13 | LL | invalid_instruction | ^ @@ -47,7 +47,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:33:13 + --> $DIR/srcloc.rs:36:13 | LL | invalid_instruction | ^ @@ -59,7 +59,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:38:14 + --> $DIR/srcloc.rs:41:14 | LL | asm!(concat!("invalid", "_", "instruction")); | ^ @@ -71,7 +71,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ warning: scale factor without index register is ignored - --> $DIR/srcloc.rs:41:15 + --> $DIR/srcloc.rs:44:15 | LL | asm!("movaps %xmm3, (%esi, 2)", options(att_syntax)); | ^ @@ -83,7 +83,7 @@ LL | movaps %xmm3, (%esi, 2) | ^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:45:14 + --> $DIR/srcloc.rs:48:14 | LL | "invalid_instruction", | ^ @@ -95,7 +95,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:51:14 + --> $DIR/srcloc.rs:54:14 | LL | "invalid_instruction", | ^ @@ -107,7 +107,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:58:14 + --> $DIR/srcloc.rs:61:14 | LL | "invalid_instruction", | ^ @@ -119,7 +119,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:65:13 + --> $DIR/srcloc.rs:68:13 | LL | concat!("invalid", "_", "instruction"), | ^ @@ -131,7 +131,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:72:13 + --> $DIR/srcloc.rs:75:13 | LL | concat!("invalid", "_", "instruction"), | ^ @@ -143,7 +143,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction1' - --> $DIR/srcloc.rs:79:14 + --> $DIR/srcloc.rs:82:14 | LL | "invalid_instruction1", | ^ @@ -155,7 +155,7 @@ LL | invalid_instruction1 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction2' - --> $DIR/srcloc.rs:80:14 + --> $DIR/srcloc.rs:83:14 | LL | "invalid_instruction2", | ^ @@ -167,7 +167,7 @@ LL | invalid_instruction2 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction1' - --> $DIR/srcloc.rs:86:13 + --> $DIR/srcloc.rs:89:13 | LL | concat!( | ^ @@ -179,7 +179,7 @@ LL | invalid_instruction1 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction2' - --> $DIR/srcloc.rs:86:13 + --> $DIR/srcloc.rs:89:13 | LL | concat!( | ^ @@ -191,7 +191,7 @@ LL | invalid_instruction2 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction1' - --> $DIR/srcloc.rs:95:13 + --> $DIR/srcloc.rs:98:13 | LL | concat!( | ^ @@ -203,7 +203,7 @@ LL | invalid_instruction1 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction2' - --> $DIR/srcloc.rs:95:13 + --> $DIR/srcloc.rs:98:13 | LL | concat!( | ^ @@ -215,7 +215,7 @@ LL | invalid_instruction2 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction3' - --> $DIR/srcloc.rs:99:13 + --> $DIR/srcloc.rs:102:13 | LL | concat!( | ^ @@ -227,7 +227,7 @@ LL | invalid_instruction3 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction4' - --> $DIR/srcloc.rs:99:13 + --> $DIR/srcloc.rs:102:13 | LL | concat!( | ^ @@ -239,7 +239,7 @@ LL | invalid_instruction4 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction1' - --> $DIR/srcloc.rs:110:13 + --> $DIR/srcloc.rs:113:13 | LL | concat!( | ^ @@ -251,7 +251,7 @@ LL | invalid_instruction1 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction2' - --> $DIR/srcloc.rs:110:13 + --> $DIR/srcloc.rs:113:13 | LL | concat!( | ^ @@ -263,7 +263,7 @@ LL | invalid_instruction2 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction3' - --> $DIR/srcloc.rs:114:13 + --> $DIR/srcloc.rs:117:13 | LL | concat!( | ^ @@ -275,7 +275,7 @@ LL | invalid_instruction3 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction4' - --> $DIR/srcloc.rs:114:13 + --> $DIR/srcloc.rs:117:13 | LL | concat!( | ^ @@ -287,7 +287,7 @@ LL | invalid_instruction4 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:127:14 + --> $DIR/srcloc.rs:130:14 | LL | "invalid_instruction" | ^ diff --git a/tests/ui/asm/x86_64/srcloc.rs b/tests/ui/asm/x86_64/srcloc.rs index 2938bafe5e70c..40fc66cbc929c 100644 --- a/tests/ui/asm/x86_64/srcloc.rs +++ b/tests/ui/asm/x86_64/srcloc.rs @@ -1,6 +1,9 @@ +//@ revisions: old new //@ only-x86_64 //@ build-fail //@ compile-flags: -Ccodegen-units=1 +//@[old] ignore-llvm-version: 19 - 99 +//@[new] min-llvm-version: 19 use std::arch::asm; From 73fc00ff8c497af386cce222fe467371dc335885 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 14 Oct 2024 17:51:08 +0200 Subject: [PATCH 02/17] Delay ambiguous intra-doc link resolution after `Cache` has been populated --- src/librustdoc/clean/types.rs | 13 +- src/librustdoc/core.rs | 24 +- .../passes/calculate_doc_coverage.rs | 2 +- .../passes/check_doc_test_visibility.rs | 2 +- .../passes/collect_intra_doc_links.rs | 260 +++++++++++++++--- src/librustdoc/passes/collect_trait_impls.rs | 2 +- src/librustdoc/passes/lint.rs | 2 +- src/librustdoc/passes/mod.rs | 2 +- src/librustdoc/passes/propagate_doc_cfg.rs | 2 +- src/librustdoc/passes/propagate_stability.rs | 2 +- .../passes/strip_aliased_non_local.rs | 2 +- src/librustdoc/passes/strip_hidden.rs | 2 +- src/librustdoc/passes/strip_priv_imports.rs | 2 +- src/librustdoc/passes/strip_private.rs | 2 +- 14 files changed, 263 insertions(+), 56 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index bc5bf4c05838a..44d9a5fdbe8ad 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1228,15 +1228,14 @@ impl Attributes { for attr in self.other_attrs.lists(sym::doc).filter(|a| a.has_name(sym::alias)) { if let Some(values) = attr.meta_item_list() { for l in values { - match l.lit().unwrap().kind { - ast::LitKind::Str(s, _) => { - aliases.insert(s); - } - _ => unreachable!(), + if let Some(lit) = l.lit() + && let ast::LitKind::Str(s, _) = lit.kind + { + aliases.insert(s); } } - } else { - aliases.insert(attr.value_str().unwrap()); + } else if let Some(value) = attr.value_str() { + aliases.insert(value); } } aliases.into_iter().collect::>().into() diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index aaf4c80f99763..9bebe1fb4c1d7 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -29,8 +29,9 @@ use crate::clean::inline::build_external_trait; use crate::clean::{self, ItemId}; use crate::config::{Options as RustdocOptions, OutputFormat, RenderOptions}; use crate::formats::cache::Cache; +use crate::passes; use crate::passes::Condition::*; -use crate::passes::{self}; +use crate::passes::collect_intra_doc_links::LinkCollector; pub(crate) struct DocContext<'tcx> { pub(crate) tcx: TyCtxt<'tcx>, @@ -427,6 +428,9 @@ pub(crate) fn run_global_ctxt( info!("Executing passes"); + let mut visited = FxHashMap::default(); + let mut ambiguous = FxIndexMap::default(); + for p in passes::defaults(show_coverage) { let run = match p.condition { Always => true, @@ -436,18 +440,30 @@ pub(crate) fn run_global_ctxt( }; if run { debug!("running pass {}", p.pass.name); - krate = tcx.sess.time(p.pass.name, || (p.pass.run)(krate, &mut ctxt)); + if let Some(run_fn) = p.pass.run { + krate = tcx.sess.time(p.pass.name, || run_fn(krate, &mut ctxt)); + } else { + let (k, LinkCollector { visited_links, ambiguous_links, .. }) = + passes::collect_intra_doc_links::collect_intra_doc_links(krate, &mut ctxt); + krate = k; + visited = visited_links; + ambiguous = ambiguous_links; + } } } tcx.sess.time("check_lint_expectations", || tcx.check_expectations(Some(sym::rustdoc))); + krate = tcx.sess.time("create_format_cache", || Cache::populate(&mut ctxt, krate)); + + let mut collector = + LinkCollector { cx: &mut ctxt, visited_links: visited, ambiguous_links: ambiguous }; + collector.resolve_ambiguities(); + if let Some(guar) = tcx.dcx().has_errors() { return Err(guar); } - krate = tcx.sess.time("create_format_cache", || Cache::populate(&mut ctxt, krate)); - Ok((krate, ctxt.render_options, ctxt.cache)) } diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index abea5bcbc51ea..d27e737764dcf 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -20,7 +20,7 @@ use crate::visit::DocVisitor; pub(crate) const CALCULATE_DOC_COVERAGE: Pass = Pass { name: "calculate-doc-coverage", - run: calculate_doc_coverage, + run: Some(calculate_doc_coverage), description: "counts the number of items with and without documentation", }; diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs index 1dc9af7ebe591..f4579d8553150 100644 --- a/src/librustdoc/passes/check_doc_test_visibility.rs +++ b/src/librustdoc/passes/check_doc_test_visibility.rs @@ -20,7 +20,7 @@ use crate::visit::DocVisitor; pub(crate) const CHECK_DOC_TEST_VISIBILITY: Pass = Pass { name: "check_doc_test_visibility", - run: check_doc_test_visibility, + run: Some(check_doc_test_visibility), description: "run various visibility-related lints on doctests", }; diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index db235786cf49a..81e7bcbd7d877 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -9,12 +9,12 @@ use std::ops::Range; use pulldown_cmark::LinkType; use rustc_ast::util::comments::may_have_doc_links; -use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_errors::{Applicability, Diag, DiagMessage}; use rustc_hir::def::Namespace::*; use rustc_hir::def::{DefKind, Namespace, PerNS}; -use rustc_hir::def_id::{CRATE_DEF_ID, DefId}; +use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LOCAL_CRATE}; use rustc_hir::{Mutability, Safety}; use rustc_middle::ty::{Ty, TyCtxt}; use rustc_middle::{bug, span_bug, ty}; @@ -30,23 +30,27 @@ use smallvec::{SmallVec, smallvec}; use tracing::{debug, info, instrument, trace}; use crate::clean::utils::find_nearest_parent_module; -use crate::clean::{self, Crate, Item, ItemLink, PrimitiveType}; +use crate::clean::{self, Crate, Item, ItemId, ItemLink, PrimitiveType}; use crate::core::DocContext; use crate::html::markdown::{MarkdownLink, MarkdownLinkRange, markdown_links}; use crate::lint::{BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS}; use crate::passes::Pass; use crate::visit::DocVisitor; -pub(crate) const COLLECT_INTRA_DOC_LINKS: Pass = Pass { - name: "collect-intra-doc-links", - run: collect_intra_doc_links, - description: "resolves intra-doc links", -}; +pub(crate) const COLLECT_INTRA_DOC_LINKS: Pass = + Pass { name: "collect-intra-doc-links", run: None, description: "resolves intra-doc links" }; -fn collect_intra_doc_links(krate: Crate, cx: &mut DocContext<'_>) -> Crate { - let mut collector = LinkCollector { cx, visited_links: FxHashMap::default() }; +pub(crate) fn collect_intra_doc_links<'a, 'tcx>( + krate: Crate, + cx: &'a mut DocContext<'tcx>, +) -> (Crate, LinkCollector<'a, 'tcx>) { + let mut collector = LinkCollector { + cx, + visited_links: FxHashMap::default(), + ambiguous_links: FxIndexMap::default(), + }; collector.visit_crate(&krate); - krate + (krate, collector) } fn filter_assoc_items_by_name_and_namespace<'a>( @@ -61,7 +65,7 @@ fn filter_assoc_items_by_name_and_namespace<'a>( } #[derive(Copy, Clone, Debug, Hash, PartialEq)] -enum Res { +pub(crate) enum Res { Def(DefKind, DefId), Primitive(PrimitiveType), } @@ -234,7 +238,7 @@ impl UrlFragment { } #[derive(Clone, Debug, Hash, PartialEq, Eq)] -struct ResolutionInfo { +pub(crate) struct ResolutionInfo { item_id: DefId, module_id: DefId, dis: Option, @@ -243,18 +247,63 @@ struct ResolutionInfo { } #[derive(Clone)] -struct DiagnosticInfo<'a> { +pub(crate) struct DiagnosticInfo<'a> { item: &'a Item, dox: &'a str, ori_link: &'a str, link_range: MarkdownLinkRange, } -struct LinkCollector<'a, 'tcx> { - cx: &'a mut DocContext<'tcx>, +pub(crate) struct OwnedDiagnosticInfo { + item: Item, + dox: String, + ori_link: String, + link_range: MarkdownLinkRange, +} + +impl From> for OwnedDiagnosticInfo { + fn from(f: DiagnosticInfo<'_>) -> Self { + Self { + item: f.item.clone(), + dox: f.dox.to_string(), + ori_link: f.ori_link.to_string(), + link_range: f.link_range.clone(), + } + } +} + +impl OwnedDiagnosticInfo { + pub(crate) fn into_info(&self) -> DiagnosticInfo<'_> { + DiagnosticInfo { + item: &self.item, + ori_link: &self.ori_link, + dox: &self.dox, + link_range: self.link_range.clone(), + } + } +} + +pub(crate) struct LinkCollector<'a, 'tcx> { + pub(crate) cx: &'a mut DocContext<'tcx>, /// Cache the resolved links so we can avoid resolving (and emitting errors for) the same link. /// The link will be `None` if it could not be resolved (i.e. the error was cached). - visited_links: FxHashMap)>>, + pub(crate) visited_links: FxHashMap)>>, + /// These links are ambiguous. We need for the cache to have its paths filled. Unfortunately, + /// if we run the `LinkCollector` pass after `Cache::populate`, a lot of items that we need + /// to go through will be removed, making a lot of intra-doc links to not be inferred. + /// + /// So instead, we store the ambiguous links and we wait for cache paths to be filled before + /// inferring them (if possible). + /// + /// Key is `(item ID, path str)`. + pub(crate) ambiguous_links: FxIndexMap<(ItemId, String), Vec>, +} + +pub(crate) struct AmbiguousLinks { + disambiguator: Option, + link_text: Box, + diag_info: OwnedDiagnosticInfo, + resolved: Vec<(Res, Option)>, } impl<'a, 'tcx> LinkCollector<'a, 'tcx> { @@ -1001,6 +1050,10 @@ impl LinkCollector<'_, '_> { } } + pub(crate) fn save_link(&mut self, item_id: ItemId, link: ItemLink) { + self.cx.cache.intra_doc_links.entry(item_id).or_default().insert(link); + } + /// This is the entry point for resolving an intra-doc link. /// /// FIXME(jynelson): this is way too many arguments @@ -1024,7 +1077,7 @@ impl LinkCollector<'_, '_> { pp_link.as_ref().map_err(|err| err.report(self.cx, diag_info.clone())).ok()?; let disambiguator = *disambiguator; - let (mut res, fragment) = self.resolve_with_disambiguator_cached( + let mut resolved = self.resolve_with_disambiguator_cached( ResolutionInfo { item_id, module_id, @@ -1040,6 +1093,142 @@ impl LinkCollector<'_, '_> { false, )?; + if resolved.len() > 1 { + let links = AmbiguousLinks { + disambiguator, + link_text: link_text.clone(), + diag_info: diag_info.into(), + resolved, + }; + + self.ambiguous_links + .entry((item.item_id, path_str.to_string())) + .or_default() + .push(links); + None + } else if let Some((res, fragment)) = resolved.pop() { + self.compute_link(res, fragment, path_str, disambiguator, diag_info, link_text) + } else { + None + } + } + + /// Returns `true` if a link could be generated from the given intra-doc information. + /// + /// This is a very light version of `format::href_with_root_path` since we're only interested + /// about whether we can generate a link to an item or not. + /// + /// * If `original_did` is local, then we check if the item is reexported or public. + /// * If `original_did` is not local, then we check if the crate it comes from is a direct + /// public dependency. + fn validate_link(&self, original_did: DefId) -> bool { + let tcx = self.cx.tcx; + let def_kind = tcx.def_kind(original_did); + let did = match def_kind { + DefKind::AssocTy | DefKind::AssocFn | DefKind::AssocConst | DefKind::Variant => { + // documented on their parent's page + tcx.parent(original_did) + } + // If this a constructor, we get the parent (either a struct or a variant) and then + // generate the link for this item. + DefKind::Ctor(..) => return self.validate_link(tcx.parent(original_did)), + DefKind::ExternCrate => { + // Link to the crate itself, not the `extern crate` item. + if let Some(local_did) = original_did.as_local() { + tcx.extern_mod_stmt_cnum(local_did).unwrap_or(LOCAL_CRATE).as_def_id() + } else { + original_did + } + } + _ => original_did, + }; + + let cache = &self.cx.cache; + if !original_did.is_local() + && !cache.effective_visibilities.is_directly_public(tcx, did) + && !cache.document_private + && !cache.primitive_locations.values().any(|&id| id == did) + { + return false; + } + + cache.paths.get(&did).is_some() + || cache.external_paths.get(&did).is_some() + || !did.is_local() + } + + #[allow(rustc::potential_query_instability)] + pub(crate) fn resolve_ambiguities(&mut self) { + let mut ambiguous_links = mem::take(&mut self.ambiguous_links); + + for ((item_id, path_str), info_items) in ambiguous_links.iter_mut() { + for info in info_items { + info.resolved.retain(|(res, _)| match res { + Res::Def(_, def_id) => self.validate_link(*def_id), + // Primitive types are always valid. + Res::Primitive(_) => true, + }); + let diag_info = info.diag_info.into_info(); + match info.resolved.len() { + 1 => { + let (res, fragment) = info.resolved.pop().unwrap(); + if let Some(link) = self.compute_link( + res, + fragment, + path_str, + info.disambiguator, + diag_info, + &info.link_text, + ) { + self.save_link(*item_id, link); + } + } + 0 => { + report_diagnostic( + self.cx.tcx, + BROKEN_INTRA_DOC_LINKS, + format!( + "all items matching `{path_str}` are either private or doc(hidden)" + ), + &diag_info, + |diag, sp, _| { + if let Some(sp) = sp { + diag.span_label(sp, "unresolved link"); + } else { + diag.note("unresolved link"); + } + }, + ); + } + _ => { + let candidates = info + .resolved + .iter() + .map(|(res, fragment)| { + let def_id = if let Some(UrlFragment::Item(def_id)) = fragment { + Some(*def_id) + } else { + None + }; + (*res, def_id) + }) + .collect::>(); + ambiguity_error(self.cx, &diag_info, path_str, &candidates, true); + } + } + } + } + } + + fn compute_link( + &mut self, + mut res: Res, + fragment: Option, + path_str: &str, + disambiguator: Option, + diag_info: DiagnosticInfo<'_>, + link_text: &Box, + ) -> Option { // Check for a primitive which might conflict with a module // Report the ambiguity and require that the user specify which one they meant. // FIXME: could there ever be a primitive not in the type namespace? @@ -1055,7 +1244,7 @@ impl LinkCollector<'_, '_> { } else { // `[char]` when a `char` module is in scope let candidates = &[(res, res.def_id(self.cx.tcx)), (prim, None)]; - ambiguity_error(self.cx, &diag_info, path_str, candidates); + ambiguity_error(self.cx, &diag_info, path_str, candidates, true); return None; } } @@ -1085,7 +1274,7 @@ impl LinkCollector<'_, '_> { } res.def_id(self.cx.tcx).map(|page_id| ItemLink { - link: Box::::from(&*ori_link.link), + link: Box::::from(&*diag_info.ori_link), link_text: link_text.clone(), page_id, fragment, @@ -1107,7 +1296,7 @@ impl LinkCollector<'_, '_> { let page_id = clean::register_res(self.cx, rustc_hir::def::Res::Def(kind, id)); Some(ItemLink { - link: Box::::from(&*ori_link.link), + link: Box::::from(&*diag_info.ori_link), link_text: link_text.clone(), page_id, fragment, @@ -1220,10 +1409,10 @@ impl LinkCollector<'_, '_> { // If this call is intended to be recoverable, then pass true to silence. // This is only recoverable when path is failed to resolved. recoverable: bool, - ) -> Option<(Res, Option)> { + ) -> Option)>> { if let Some(res) = self.visited_links.get(&key) { if res.is_some() || cache_errors { - return res.clone(); + return res.clone().map(|r| vec![r]); } } @@ -1248,13 +1437,14 @@ impl LinkCollector<'_, '_> { // and after removing duplicated kinds, only one remains, the `ambiguity_error` function // won't emit an error. So at this point, we can just take the first candidate as it was // the first retrieved and use it to generate the link. - if let [candidate, _candidate2, ..] = *candidates - && !ambiguity_error(self.cx, &diag, &key.path_str, &candidates) - { - candidates = vec![candidate]; + if let [candidate, _candidate2, ..] = *candidates { + if !ambiguity_error(self.cx, &diag, &key.path_str, &candidates, false) { + candidates = vec![candidate]; + } } - if let &[(res, def_id)] = candidates.as_slice() { + let mut out = Vec::with_capacity(candidates.len()); + for (res, def_id) in candidates { let fragment = match (&key.extra_fragment, def_id) { (Some(_), Some(def_id)) => { report_anchor_conflict(self.cx, diag, def_id); @@ -1264,15 +1454,14 @@ impl LinkCollector<'_, '_> { (None, Some(def_id)) => Some(UrlFragment::Item(def_id)), (None, None) => None, }; - let r = Some((res, fragment)); - self.visited_links.insert(key, r.clone()); - return r; + out.push((res, fragment)); } - - if cache_errors { + if let [r] = out.as_slice() { + self.visited_links.insert(key, Some(r.clone())); + } else if cache_errors { self.visited_links.insert(key, None); } - None + Some(out) } /// After parsing the disambiguator, resolve the main part of the link. @@ -2046,6 +2235,7 @@ fn ambiguity_error( diag_info: &DiagnosticInfo<'_>, path_str: &str, candidates: &[(Res, Option)], + emit_error: bool, ) -> bool { let mut descrs = FxHashSet::default(); let kinds = candidates @@ -2061,6 +2251,8 @@ fn ambiguity_error( // There is no way for users to disambiguate at this point, so better return the first // candidate and not show a warning. return false; + } else if !emit_error { + return true; } let mut msg = format!("`{path_str}` is "); diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index d1a1f0df3e7ed..f358908032285 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -16,7 +16,7 @@ use crate::visit::DocVisitor; pub(crate) const COLLECT_TRAIT_IMPLS: Pass = Pass { name: "collect-trait-impls", - run: collect_trait_impls, + run: Some(collect_trait_impls), description: "retrieves trait impls for items in the crate", }; diff --git a/src/librustdoc/passes/lint.rs b/src/librustdoc/passes/lint.rs index 593027ef7d293..35b62370abb29 100644 --- a/src/librustdoc/passes/lint.rs +++ b/src/librustdoc/passes/lint.rs @@ -14,7 +14,7 @@ use crate::core::DocContext; use crate::visit::DocVisitor; pub(crate) const RUN_LINTS: Pass = - Pass { name: "run-lints", run: run_lints, description: "runs some of rustdoc's lints" }; + Pass { name: "run-lints", run: Some(run_lints), description: "runs some of rustdoc's lints" }; struct Linter<'a, 'tcx> { cx: &'a mut DocContext<'tcx>, diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index f5b7802372149..9ba63d34144ae 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -47,7 +47,7 @@ pub(crate) use self::lint::RUN_LINTS; #[derive(Copy, Clone)] pub(crate) struct Pass { pub(crate) name: &'static str, - pub(crate) run: fn(clean::Crate, &mut DocContext<'_>) -> clean::Crate, + pub(crate) run: Option) -> clean::Crate>, pub(crate) description: &'static str, } diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs index 6be51dd156066..350be37f553da 100644 --- a/src/librustdoc/passes/propagate_doc_cfg.rs +++ b/src/librustdoc/passes/propagate_doc_cfg.rs @@ -13,7 +13,7 @@ use crate::passes::Pass; pub(crate) const PROPAGATE_DOC_CFG: Pass = Pass { name: "propagate-doc-cfg", - run: propagate_doc_cfg, + run: Some(propagate_doc_cfg), description: "propagates `#[doc(cfg(...))]` to child items", }; diff --git a/src/librustdoc/passes/propagate_stability.rs b/src/librustdoc/passes/propagate_stability.rs index f51e993bfa5d0..f55479687f8e7 100644 --- a/src/librustdoc/passes/propagate_stability.rs +++ b/src/librustdoc/passes/propagate_stability.rs @@ -16,7 +16,7 @@ use crate::passes::Pass; pub(crate) const PROPAGATE_STABILITY: Pass = Pass { name: "propagate-stability", - run: propagate_stability, + run: Some(propagate_stability), description: "propagates stability to child items", }; diff --git a/src/librustdoc/passes/strip_aliased_non_local.rs b/src/librustdoc/passes/strip_aliased_non_local.rs index 155ad5438314e..a078eec048ece 100644 --- a/src/librustdoc/passes/strip_aliased_non_local.rs +++ b/src/librustdoc/passes/strip_aliased_non_local.rs @@ -8,7 +8,7 @@ use crate::passes::Pass; pub(crate) const STRIP_ALIASED_NON_LOCAL: Pass = Pass { name: "strip-aliased-non-local", - run: strip_aliased_non_local, + run: Some(strip_aliased_non_local), description: "strips all non-local private aliased items from the output", }; diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs index 430f3d8a574c3..aba04283e59dc 100644 --- a/src/librustdoc/passes/strip_hidden.rs +++ b/src/librustdoc/passes/strip_hidden.rs @@ -16,7 +16,7 @@ use crate::passes::{ImplStripper, Pass}; pub(crate) const STRIP_HIDDEN: Pass = Pass { name: "strip-hidden", - run: strip_hidden, + run: Some(strip_hidden), description: "strips all `#[doc(hidden)]` items from the output", }; diff --git a/src/librustdoc/passes/strip_priv_imports.rs b/src/librustdoc/passes/strip_priv_imports.rs index 7b05756ae215e..2e9f06bd0a30c 100644 --- a/src/librustdoc/passes/strip_priv_imports.rs +++ b/src/librustdoc/passes/strip_priv_imports.rs @@ -8,7 +8,7 @@ use crate::passes::{ImportStripper, Pass}; pub(crate) const STRIP_PRIV_IMPORTS: Pass = Pass { name: "strip-priv-imports", - run: strip_priv_imports, + run: Some(strip_priv_imports), description: "strips all private import statements (`use`, `extern crate`) from a crate", }; diff --git a/src/librustdoc/passes/strip_private.rs b/src/librustdoc/passes/strip_private.rs index 1bafa450be904..78f0ad277408b 100644 --- a/src/librustdoc/passes/strip_private.rs +++ b/src/librustdoc/passes/strip_private.rs @@ -8,7 +8,7 @@ use crate::passes::{ImplStripper, ImportStripper, Pass, Stripper}; pub(crate) const STRIP_PRIVATE: Pass = Pass { name: "strip-private", - run: strip_private, + run: Some(strip_private), description: "strips all private items from a crate which cannot be seen externally, \ implies strip-priv-imports", }; From d540e7285ca14393d2b51f486ecc0f26d2f986c7 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 14 Oct 2024 17:51:37 +0200 Subject: [PATCH 03/17] Add regression tests for #130233 --- .../intra-doc/filter-out-private-2.rs | 15 +++++++++++ .../intra-doc/filter-out-private-2.stderr | 14 ++++++++++ .../intra-doc/filter-out-private.rs | 13 ++++++++++ .../intra-doc/filter-out-private.stderr | 22 ++++++++++++++++ tests/rustdoc/intra-doc/filter-out-private.rs | 26 +++++++++++++++++++ 5 files changed, 90 insertions(+) create mode 100644 tests/rustdoc-ui/intra-doc/filter-out-private-2.rs create mode 100644 tests/rustdoc-ui/intra-doc/filter-out-private-2.stderr create mode 100644 tests/rustdoc-ui/intra-doc/filter-out-private.rs create mode 100644 tests/rustdoc-ui/intra-doc/filter-out-private.stderr create mode 100644 tests/rustdoc/intra-doc/filter-out-private.rs diff --git a/tests/rustdoc-ui/intra-doc/filter-out-private-2.rs b/tests/rustdoc-ui/intra-doc/filter-out-private-2.rs new file mode 100644 index 0000000000000..9209203c99ee5 --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/filter-out-private-2.rs @@ -0,0 +1,15 @@ +// This test ensures that ambiguities (not) resolved at a later stage still emit an error. + +#![deny(rustdoc::broken_intra_doc_links)] +#![crate_name = "foo"] + +#[doc(hidden)] +pub struct Thing {} + +#[allow(non_snake_case)] +#[doc(hidden)] +pub fn Thing() {} + +/// Do stuff with [`Thing`]. +//~^ ERROR all items matching `Thing` are either private or doc(hidden) +pub fn repro(_: Thing) {} diff --git a/tests/rustdoc-ui/intra-doc/filter-out-private-2.stderr b/tests/rustdoc-ui/intra-doc/filter-out-private-2.stderr new file mode 100644 index 0000000000000..394f919de943e --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/filter-out-private-2.stderr @@ -0,0 +1,14 @@ +error: all items matching `Thing` are either private or doc(hidden) + --> $DIR/filter-out-private-2.rs:13:21 + | +LL | /// Do stuff with [`Thing`]. + | ^^^^^ unresolved link + | +note: the lint level is defined here + --> $DIR/filter-out-private-2.rs:3:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/rustdoc-ui/intra-doc/filter-out-private.rs b/tests/rustdoc-ui/intra-doc/filter-out-private.rs new file mode 100644 index 0000000000000..f481b51dad066 --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/filter-out-private.rs @@ -0,0 +1,13 @@ +// This test ensures that ambiguities resolved at a later stage still emit an error. + +#![deny(rustdoc::broken_intra_doc_links)] +#![crate_name = "foo"] + +pub struct Thing {} + +#[allow(non_snake_case)] +pub fn Thing() {} + +/// Do stuff with [`Thing`]. +//~^ ERROR `Thing` is both a function and a struct +pub fn repro(_: Thing) {} diff --git a/tests/rustdoc-ui/intra-doc/filter-out-private.stderr b/tests/rustdoc-ui/intra-doc/filter-out-private.stderr new file mode 100644 index 0000000000000..1d1830b1f1c37 --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/filter-out-private.stderr @@ -0,0 +1,22 @@ +error: `Thing` is both a function and a struct + --> $DIR/filter-out-private.rs:11:21 + | +LL | /// Do stuff with [`Thing`]. + | ^^^^^ ambiguous link + | +note: the lint level is defined here + --> $DIR/filter-out-private.rs:3:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: to link to the function, add parentheses + | +LL | /// Do stuff with [`Thing()`]. + | ++ +help: to link to the struct, prefix with `struct@` + | +LL | /// Do stuff with [`struct@Thing`]. + | +++++++ + +error: aborting due to 1 previous error + diff --git a/tests/rustdoc/intra-doc/filter-out-private.rs b/tests/rustdoc/intra-doc/filter-out-private.rs new file mode 100644 index 0000000000000..70591b120d823 --- /dev/null +++ b/tests/rustdoc/intra-doc/filter-out-private.rs @@ -0,0 +1,26 @@ +// This test ensures that private/hidden items don't create ambiguity. +// This is a regression test for . + +#![deny(rustdoc::broken_intra_doc_links)] +#![crate_name = "foo"] + +pub struct Thing {} + +#[doc(hidden)] +#[allow(non_snake_case)] +pub fn Thing() {} + +pub struct Bar {} + +#[allow(non_snake_case)] +fn Bar() {} + +//@ has 'foo/fn.repro.html' +//@ has - '//*[@class="toggle top-doc"]/*[@class="docblock"]//a/@href' 'struct.Thing.html' +/// Do stuff with [`Thing`]. +pub fn repro(_: Thing) {} + +//@ has 'foo/fn.repro2.html' +//@ has - '//*[@class="toggle top-doc"]/*[@class="docblock"]//a/@href' 'struct.Bar.html' +/// Do stuff with [`Bar`]. +pub fn repro2(_: Bar) {} From 918dc38733985770d1cdcea76169340c620c1f32 Mon Sep 17 00:00:00 2001 From: zlfn Date: Tue, 15 Oct 2024 18:23:39 +0900 Subject: [PATCH 04/17] Combine impl_int and impl_uint Two macros are exactly the same. --- library/core/src/fmt/num.rs | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index aecd725eca561..cc94c392de581 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -31,22 +31,11 @@ macro_rules! impl_int { })* ) } -macro_rules! impl_uint { - ($($t:ident)*) => ( - $(impl DisplayInt for $t { - fn zero() -> Self { 0 } - fn from_u8(u: u8) -> Self { u as Self } - fn to_u8(&self) -> u8 { *self as u8 } - #[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))] - fn to_u32(&self) -> u32 { *self as u32 } - fn to_u64(&self) -> u64 { *self as u64 } - fn to_u128(&self) -> u128 { *self as u128 } - })* - ) -} -impl_int! { i8 i16 i32 i64 i128 isize } -impl_uint! { u8 u16 u32 u64 u128 usize } +impl_int! { + i8 i16 i32 i64 i128 isize + u8 u16 u32 u64 u128 usize +} /// A type that represents a specific radix /// From 0637517da6802bcdc8df9a73a75edb8c41033f11 Mon Sep 17 00:00:00 2001 From: zlfn Date: Tue, 15 Oct 2024 18:32:21 +0900 Subject: [PATCH 05/17] Rename debug! macro to impl_Debug! --- library/core/src/fmt/num.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index cc94c392de581..0f33d730a68e6 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -167,7 +167,8 @@ integer! { i16, u16 } integer! { i32, u32 } integer! { i64, u64 } integer! { i128, u128 } -macro_rules! debug { + +macro_rules! impl_Debug { ($($T:ident)*) => {$( #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for $T { @@ -184,10 +185,6 @@ macro_rules! debug { } )*}; } -debug! { - i8 i16 i32 i64 i128 isize - u8 u16 u32 u64 u128 usize -} // 2 digit decimal look up table static DEC_DIGITS_LUT: &[u8; 200] = b"0001020304050607080910111213141516171819\ @@ -510,6 +507,11 @@ macro_rules! impl_Exp { }; } +impl_Debug! { + i8 i16 i32 i64 i128 isize + u8 u16 u32 u64 u128 usize +} + // Include wasm32 in here since it doesn't reflect the native pointer size, and // often cares strongly about getting a smaller code size. #[cfg(any(target_pointer_width = "64", target_arch = "wasm32"))] From 99af761632420b2778e2b44465a396e28adf6103 Mon Sep 17 00:00:00 2001 From: zlfn Date: Tue, 15 Oct 2024 18:39:30 +0900 Subject: [PATCH 06/17] Refactor `floating` macro and nofloat panic message --- library/core/src/fmt/float.rs | 47 ++++++++++++++++--------------- library/core/src/fmt/nofloat.rs | 21 +++++++------- library/core/src/fmt/num.rs | 50 +++++++++++++++++---------------- 3 files changed, 60 insertions(+), 58 deletions(-) diff --git a/library/core/src/fmt/float.rs b/library/core/src/fmt/float.rs index 20ea0352c2dce..c70dbf54304de 100644 --- a/library/core/src/fmt/float.rs +++ b/library/core/src/fmt/float.rs @@ -196,39 +196,40 @@ where } macro_rules! floating { - ($ty:ident) => { - #[stable(feature = "rust1", since = "1.0.0")] - impl Debug for $ty { - fn fmt(&self, fmt: &mut Formatter<'_>) -> Result { - float_to_general_debug(fmt, self) + ($($ty:ident)*) => { + $( + #[stable(feature = "rust1", since = "1.0.0")] + impl Debug for $ty { + fn fmt(&self, fmt: &mut Formatter<'_>) -> Result { + float_to_general_debug(fmt, self) + } } - } - #[stable(feature = "rust1", since = "1.0.0")] - impl Display for $ty { - fn fmt(&self, fmt: &mut Formatter<'_>) -> Result { - float_to_decimal_display(fmt, self) + #[stable(feature = "rust1", since = "1.0.0")] + impl Display for $ty { + fn fmt(&self, fmt: &mut Formatter<'_>) -> Result { + float_to_decimal_display(fmt, self) + } } - } - #[stable(feature = "rust1", since = "1.0.0")] - impl LowerExp for $ty { - fn fmt(&self, fmt: &mut Formatter<'_>) -> Result { - float_to_exponential_common(fmt, self, false) + #[stable(feature = "rust1", since = "1.0.0")] + impl LowerExp for $ty { + fn fmt(&self, fmt: &mut Formatter<'_>) -> Result { + float_to_exponential_common(fmt, self, false) + } } - } - #[stable(feature = "rust1", since = "1.0.0")] - impl UpperExp for $ty { - fn fmt(&self, fmt: &mut Formatter<'_>) -> Result { - float_to_exponential_common(fmt, self, true) + #[stable(feature = "rust1", since = "1.0.0")] + impl UpperExp for $ty { + fn fmt(&self, fmt: &mut Formatter<'_>) -> Result { + float_to_exponential_common(fmt, self, true) + } } - } + )* }; } -floating! { f32 } -floating! { f64 } +floating! { f32 f64 } #[stable(feature = "rust1", since = "1.0.0")] impl Debug for f16 { diff --git a/library/core/src/fmt/nofloat.rs b/library/core/src/fmt/nofloat.rs index 6b07236f1da12..29aaee75d22bc 100644 --- a/library/core/src/fmt/nofloat.rs +++ b/library/core/src/fmt/nofloat.rs @@ -1,18 +1,17 @@ use crate::fmt::{Debug, Formatter, Result}; macro_rules! floating { - ($ty:ident) => { - #[stable(feature = "rust1", since = "1.0.0")] - impl Debug for $ty { - #[inline] - fn fmt(&self, _fmt: &mut Formatter<'_>) -> Result { - panic!("floating point support is turned off"); + ($($ty:ident)*) => { + $( + #[stable(feature = "rust1", since = "1.0.0")] + impl Debug for $ty { + #[inline] + fn fmt(&self, _fmt: &mut Formatter<'_>) -> Result { + panic!("floating point fmt support is turned off"); + } } - } + )* }; } -floating! { f16 } -floating! { f32 } -floating! { f64 } -floating! { f128 } +floating! { f16 f32 f64 f128 } diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index 0f33d730a68e6..f1540803f978d 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -20,15 +20,15 @@ trait DisplayInt: macro_rules! impl_int { ($($t:ident)*) => ( - $(impl DisplayInt for $t { - fn zero() -> Self { 0 } - fn from_u8(u: u8) -> Self { u as Self } - fn to_u8(&self) -> u8 { *self as u8 } - #[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))] - fn to_u32(&self) -> u32 { *self as u32 } - fn to_u64(&self) -> u64 { *self as u64 } - fn to_u128(&self) -> u128 { *self as u128 } - })* + $(impl DisplayInt for $t { + fn zero() -> Self { 0 } + fn from_u8(u: u8) -> Self { u as Self } + fn to_u8(&self) -> u8 { *self as u8 } + #[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))] + fn to_u32(&self) -> u32 { *self as u32 } + fn to_u64(&self) -> u64 { *self as u64 } + fn to_u128(&self) -> u128 { *self as u128 } + })* ) } @@ -169,21 +169,23 @@ integer! { i64, u64 } integer! { i128, u128 } macro_rules! impl_Debug { - ($($T:ident)*) => {$( - #[stable(feature = "rust1", since = "1.0.0")] - impl fmt::Debug for $T { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if f.debug_lower_hex() { - fmt::LowerHex::fmt(self, f) - } else if f.debug_upper_hex() { - fmt::UpperHex::fmt(self, f) - } else { - fmt::Display::fmt(self, f) + ($($T:ident)*) => { + $( + #[stable(feature = "rust1", since = "1.0.0")] + impl fmt::Debug for $T { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if f.debug_lower_hex() { + fmt::LowerHex::fmt(self, f) + } else if f.debug_upper_hex() { + fmt::UpperHex::fmt(self, f) + } else { + fmt::Display::fmt(self, f) + } } } - } - )*}; + )* + }; } // 2 digit decimal look up table @@ -508,8 +510,8 @@ macro_rules! impl_Exp { } impl_Debug! { - i8 i16 i32 i64 i128 isize - u8 u16 u32 u64 u128 usize + i8 i16 i32 i64 i128 isize + u8 u16 u32 u64 u128 usize } // Include wasm32 in here since it doesn't reflect the native pointer size, and From 2b9e41c1288a5e9f015be4f5da4c90d5a4d9c158 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 15 Oct 2024 01:58:27 +0200 Subject: [PATCH 07/17] Improve documentation for intra-doc links computation --- .../passes/collect_intra_doc_links.rs | 18 +++++++++--------- .../intra-doc/filter-out-private-2.rs | 2 +- .../intra-doc/filter-out-private-2.stderr | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 81e7bcbd7d877..10026e9f05d26 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -288,14 +288,16 @@ pub(crate) struct LinkCollector<'a, 'tcx> { /// Cache the resolved links so we can avoid resolving (and emitting errors for) the same link. /// The link will be `None` if it could not be resolved (i.e. the error was cached). pub(crate) visited_links: FxHashMap)>>, - /// These links are ambiguous. We need for the cache to have its paths filled. Unfortunately, - /// if we run the `LinkCollector` pass after `Cache::populate`, a lot of items that we need - /// to go through will be removed, making a lot of intra-doc links to not be inferred. + /// According to `rustc_resolve`, these links are ambiguous. /// - /// So instead, we store the ambiguous links and we wait for cache paths to be filled before - /// inferring them (if possible). + /// However, we cannot link to an item that has been stripped from the documentation. If all + /// but one of the "possibilities" are stripped, then there is no real ambiguity. To determine + /// if an ambiguity is real, we delay resolving them until after `Cache::populate`, then filter + /// every item that doesn't have a cached path. /// - /// Key is `(item ID, path str)`. + /// We could get correct results by simply delaying everything. This would have fewer happy + /// codepaths, but we want to distinguish different kinds of error conditions, and this is easy + /// to do by resolving links as soon as possible. pub(crate) ambiguous_links: FxIndexMap<(ItemId, String), Vec>, } @@ -1187,9 +1189,7 @@ impl LinkCollector<'_, '_> { report_diagnostic( self.cx.tcx, BROKEN_INTRA_DOC_LINKS, - format!( - "all items matching `{path_str}` are either private or doc(hidden)" - ), + format!("all items matching `{path_str}` are private or doc(hidden)"), &diag_info, |diag, sp, _| { if let Some(sp) = sp { diff --git a/tests/rustdoc-ui/intra-doc/filter-out-private-2.rs b/tests/rustdoc-ui/intra-doc/filter-out-private-2.rs index 9209203c99ee5..9d8edbf6b5dd2 100644 --- a/tests/rustdoc-ui/intra-doc/filter-out-private-2.rs +++ b/tests/rustdoc-ui/intra-doc/filter-out-private-2.rs @@ -11,5 +11,5 @@ pub struct Thing {} pub fn Thing() {} /// Do stuff with [`Thing`]. -//~^ ERROR all items matching `Thing` are either private or doc(hidden) +//~^ ERROR all items matching `Thing` are private or doc(hidden) pub fn repro(_: Thing) {} diff --git a/tests/rustdoc-ui/intra-doc/filter-out-private-2.stderr b/tests/rustdoc-ui/intra-doc/filter-out-private-2.stderr index 394f919de943e..1a49c90a17286 100644 --- a/tests/rustdoc-ui/intra-doc/filter-out-private-2.stderr +++ b/tests/rustdoc-ui/intra-doc/filter-out-private-2.stderr @@ -1,4 +1,4 @@ -error: all items matching `Thing` are either private or doc(hidden) +error: all items matching `Thing` are private or doc(hidden) --> $DIR/filter-out-private-2.rs:13:21 | LL | /// Do stuff with [`Thing`]. From 10f2395c9ee5849e3a769ce21d3e704191ec8085 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 15 Oct 2024 15:42:47 +0200 Subject: [PATCH 08/17] Remove `AmbiguousLinks::disambiguator` --- src/librustdoc/passes/collect_intra_doc_links.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 10026e9f05d26..cbc6e351fac53 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -302,7 +302,6 @@ pub(crate) struct LinkCollector<'a, 'tcx> { } pub(crate) struct AmbiguousLinks { - disambiguator: Option, link_text: Box, diag_info: OwnedDiagnosticInfo, resolved: Vec<(Res, Option)>, @@ -1097,7 +1096,6 @@ impl LinkCollector<'_, '_> { if resolved.len() > 1 { let links = AmbiguousLinks { - disambiguator, link_text: link_text.clone(), diag_info: diag_info.into(), resolved, @@ -1178,7 +1176,7 @@ impl LinkCollector<'_, '_> { res, fragment, path_str, - info.disambiguator, + None, diag_info, &info.link_text, ) { From dca646ab0107fd311427b7f7c4eea448e9f4ee9e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 13 Oct 2024 10:09:42 -0400 Subject: [PATCH 09/17] Rewrite for<..> async correctly --- src/tools/rustfmt/src/types.rs | 50 +++++++++++---------- src/tools/rustfmt/tests/target/asyncness.rs | 2 + 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index 99b3fe60ee2fa..e237662f5aa22 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -613,26 +613,8 @@ impl Rewrite for ast::GenericBound { ast::GenericBound::Trait(ref poly_trait_ref) => { let snippet = context.snippet(self.span()); let has_paren = snippet.starts_with('(') && snippet.ends_with(')'); - let ast::TraitBoundModifiers { - constness, - asyncness, - polarity, - } = poly_trait_ref.modifiers; - let mut constness = constness.as_str().to_string(); - if !constness.is_empty() { - constness.push(' '); - } - let mut asyncness = asyncness.as_str().to_string(); - if !asyncness.is_empty() { - asyncness.push(' '); - } - let polarity = polarity.as_str(); - let shape = shape - .offset_left(constness.len() + polarity.len()) - .max_width_error(shape.width, self.span())?; poly_trait_ref .rewrite_result(context, shape) - .map(|s| format!("{constness}{asyncness}{polarity}{s}")) .map(|s| if has_paren { format!("({})", s) } else { s }) } ast::GenericBound::Use(ref args, span) => { @@ -756,19 +738,41 @@ impl Rewrite for ast::PolyTraitRef { } fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult { - if let Some(lifetime_str) = rewrite_bound_params(context, shape, &self.bound_generic_params) + let (binder, shape) = if let Some(lifetime_str) = + rewrite_bound_params(context, shape, &self.bound_generic_params) { // 6 is "for<> ".len() let extra_offset = lifetime_str.len() + 6; let shape = shape .offset_left(extra_offset) .max_width_error(shape.width, self.span)?; - let path_str = self.trait_ref.rewrite_result(context, shape)?; - - Ok(format!("for<{lifetime_str}> {path_str}")) + (format!("for<{lifetime_str}> "), shape) } else { - self.trait_ref.rewrite_result(context, shape) + (String::new(), shape) + }; + + let ast::TraitBoundModifiers { + constness, + asyncness, + polarity, + } = self.modifiers; + let mut constness = constness.as_str().to_string(); + if !constness.is_empty() { + constness.push(' '); } + let mut asyncness = asyncness.as_str().to_string(); + if !asyncness.is_empty() { + asyncness.push(' '); + } + let polarity = polarity.as_str(); + let shape = shape + .offset_left(constness.len() + polarity.len()) + .max_width_error(shape.width, self.span)?; + + let path_str = self.trait_ref.rewrite_result(context, shape)?; + Ok(format!( + "{binder}{constness}{asyncness}{polarity}{path_str}" + )) } } diff --git a/src/tools/rustfmt/tests/target/asyncness.rs b/src/tools/rustfmt/tests/target/asyncness.rs index d91ac960499b8..dd651ed6a620e 100644 --- a/src/tools/rustfmt/tests/target/asyncness.rs +++ b/src/tools/rustfmt/tests/target/asyncness.rs @@ -1,3 +1,5 @@ // rustfmt-edition: 2018 fn foo() -> impl async Fn() {} + +fn bar() -> impl for<'a> async Fn(&'a ()) {} From 4886e9a134aa7c8c9bb1fed42ebfe22d7f5b2a63 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 15 Oct 2024 14:39:49 -0400 Subject: [PATCH 10/17] Unify secondary_span and swap_secondary_and_primary --- .../src/check/compare_impl_item.rs | 9 +++------ compiler/rustc_hir_analysis/src/check/mod.rs | 1 - .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 1 - compiler/rustc_passes/src/check_attr.rs | 1 - .../src/error_reporting/infer/mod.rs | 18 +++++++----------- .../traits/fulfillment_errors.rs | 3 +-- 6 files changed, 11 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 9ca5f25447b3e..75956165e8737 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -592,14 +592,13 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( &cause, hir.get_if_local(impl_m.def_id) .and_then(|node| node.fn_decl()) - .map(|decl| (decl.output.span(), Cow::from("return type in trait"))), + .map(|decl| (decl.output.span(), Cow::from("return type in trait"), false)), Some(infer::ValuePairs::Terms(ExpectedFound { expected: trait_return_ty.into(), found: impl_return_ty.into(), })), terr, false, - false, ); return Err(diag.emit()); } @@ -1018,14 +1017,13 @@ fn report_trait_method_mismatch<'tcx>( infcx.err_ctxt().note_type_err( &mut diag, &cause, - trait_err_span.map(|sp| (sp, Cow::from("type in trait"))), + trait_err_span.map(|sp| (sp, Cow::from("type in trait"), false)), Some(infer::ValuePairs::PolySigs(ExpectedFound { expected: ty::Binder::dummy(trait_sig), found: ty::Binder::dummy(impl_sig), })), terr, false, - false, ); diag.emit() @@ -1825,14 +1823,13 @@ fn compare_const_predicate_entailment<'tcx>( infcx.err_ctxt().note_type_err( &mut diag, &cause, - trait_c_span.map(|span| (span, Cow::from("type in trait"))), + trait_c_span.map(|span| (span, Cow::from("type in trait"), false)), Some(infer::ValuePairs::Terms(ExpectedFound { expected: trait_ty.into(), found: impl_ty.into(), })), terr, false, - false, ); return Err(diag.emit()); }; diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 004540b264308..959b17b2d4073 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -652,7 +652,6 @@ pub fn check_function_signature<'tcx>( })), err, false, - false, ); return Err(diag.emit()); } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index fa471647d02d0..44c0da0744a2e 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1114,7 +1114,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None, Some(trace.values), e, - false, true, ); } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 7ce29260e3676..4516ea94cad71 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -2302,7 +2302,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { })), terr, false, - false, ); diag.emit(); self.abort.set(true); diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index bd78a6ee3aff7..df5800ab58a66 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -1127,18 +1127,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// the message in `secondary_span` as the primary label, and apply the message that would /// otherwise be used for the primary label on the `secondary_span` `Span`. This applies on /// E0271, like `tests/ui/issues/issue-39970.stderr`. - #[instrument( - level = "debug", - skip(self, diag, secondary_span, swap_secondary_and_primary, prefer_label) - )] + #[instrument(level = "debug", skip(self, diag, secondary_span, prefer_label))] pub fn note_type_err( &self, diag: &mut Diag<'_>, cause: &ObligationCause<'tcx>, - secondary_span: Option<(Span, Cow<'static, str>)>, + secondary_span: Option<(Span, Cow<'static, str>, bool)>, mut values: Option>, terr: TypeError<'tcx>, - swap_secondary_and_primary: bool, prefer_label: bool, ) { let span = cause.span(); @@ -1304,7 +1300,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { diag.span_note(span, msg); } }; - if let Some((sp, msg)) = secondary_span { + if let Some((secondary_span, secondary_msg, swap_secondary_and_primary)) = secondary_span { if swap_secondary_and_primary { let terr = if let Some(infer::ValuePairs::Terms(ExpectedFound { expected, .. @@ -1314,11 +1310,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } else { terr.to_string(self.tcx) }; - label_or_note(sp, terr); - label_or_note(span, msg); + label_or_note(secondary_span, terr); + label_or_note(span, secondary_msg); } else { label_or_note(span, terr.to_string(self.tcx)); - label_or_note(sp, msg); + label_or_note(secondary_span, secondary_msg); } } else if let Some(values) = values && let Some((e, f)) = values.ty() @@ -1788,7 +1784,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { self.type_error_additional_suggestions(&trace, terr), ); let mut diag = self.dcx().create_err(failure_code); - self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr, false, false); + self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr, false); diag } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 824c25db07d2e..8a4c22fdf863b 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -710,7 +710,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { None, TypeError::Sorts(ty::error::ExpectedFound::new(true, expected_ty, ct_ty)), false, - false, ); diag } @@ -1435,6 +1434,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { cx.into_buffer() } ))), + true, )), _ => None, } @@ -1452,7 +1452,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { )) }), err, - true, false, ); self.note_obligation_cause(&mut diag, obligation); From b4e9aad137800936b4fbc3c36da6ff2819b385b5 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 15 Oct 2024 13:20:41 -0400 Subject: [PATCH 11/17] Rename can_coerce to may_coerce --- compiler/rustc_hir_typeck/src/_match.rs | 4 +-- compiler/rustc_hir_typeck/src/cast.rs | 8 ++--- compiler/rustc_hir_typeck/src/coercion.rs | 17 ++++++---- compiler/rustc_hir_typeck/src/expr.rs | 10 +++--- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 10 +++--- .../src/fn_ctxt/suggestions.rs | 34 +++++++++---------- .../rustc_hir_typeck/src/method/suggest.rs | 4 +-- compiler/rustc_hir_typeck/src/pat.rs | 2 +- 8 files changed, 46 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 0d9d1910ae0c1..e68caa3e2e35e 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -235,8 +235,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(ret_coercion) => { let ret_ty = ret_coercion.borrow().expected_ty(); let ret_ty = self.infcx.shallow_resolve(ret_ty); - self.can_coerce(arm_ty, ret_ty) - && prior_arm.is_none_or(|(_, ty, _)| self.can_coerce(ty, ret_ty)) + self.may_coerce(arm_ty, ret_ty) + && prior_arm.is_none_or(|(_, ty, _)| self.may_coerce(ty, ret_ty)) // The match arms need to unify for the case of `impl Trait`. && !matches!(ret_ty.kind(), ty::Alias(ty::Opaque, ..)) } diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 407191661a4b3..8fa6ab8503d08 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -409,7 +409,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { let mut sugg_mutref = false; if let ty::Ref(reg, cast_ty, mutbl) = *self.cast_ty.kind() { if let ty::RawPtr(expr_ty, _) = *self.expr_ty.kind() - && fcx.can_coerce( + && fcx.may_coerce( Ty::new_ref(fcx.tcx, fcx.tcx.lifetimes.re_erased, expr_ty, mutbl), self.cast_ty, ) @@ -418,14 +418,14 @@ impl<'a, 'tcx> CastCheck<'tcx> { } else if let ty::Ref(expr_reg, expr_ty, expr_mutbl) = *self.expr_ty.kind() && expr_mutbl == Mutability::Not && mutbl == Mutability::Mut - && fcx.can_coerce(Ty::new_mut_ref(fcx.tcx, expr_reg, expr_ty), self.cast_ty) + && fcx.may_coerce(Ty::new_mut_ref(fcx.tcx, expr_reg, expr_ty), self.cast_ty) { sugg_mutref = true; } if !sugg_mutref && sugg == None - && fcx.can_coerce( + && fcx.may_coerce( Ty::new_ref(fcx.tcx, reg, self.expr_ty, mutbl), self.cast_ty, ) @@ -433,7 +433,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { sugg = Some((format!("&{}", mutbl.prefix_str()), false)); } } else if let ty::RawPtr(_, mutbl) = *self.cast_ty.kind() - && fcx.can_coerce( + && fcx.may_coerce( Ty::new_ref(fcx.tcx, fcx.tcx.lifetimes.re_erased, self.expr_ty, mutbl), self.cast_ty, ) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index bd0b98702983a..a6df9e45db506 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1083,21 +1083,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) } - /// Same as `coerce()`, but without side-effects. + /// Probe whether `expr_ty` can be coerced to `target_ty`. This has no side-effects, + /// and may return false positives if types are not yet fully constrained by inference. /// - /// Returns false if the coercion creates any obligations that result in - /// errors. - pub(crate) fn can_coerce(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> bool { + /// Returns false if the coercion is not possible, or if the coercion creates any + /// sub-obligations that result in errors. + /// + /// This should only be used for diagnostics. + pub(crate) fn may_coerce(&self, expr_ty: Ty<'tcx>, target_ty: Ty<'tcx>) -> bool { // FIXME(-Znext-solver): We need to structurally resolve both types here. let source = self.resolve_vars_with_obligations(expr_ty); - debug!("coercion::can_with_predicates({:?} -> {:?})", source, target); + debug!("coercion::can_with_predicates({:?} -> {:?})", source, target_ty); let cause = self.cause(DUMMY_SP, ObligationCauseCode::ExprAssignable); // We don't ever need two-phase here since we throw out the result of the coercion. // We also just always set `coerce_never` to true, since this is a heuristic. let coerce = Coerce::new(self, cause, AllowTwoPhase::No, true); self.probe(|_| { - let Ok(ok) = coerce.coerce(source, target) else { + let Ok(ok) = coerce.coerce(source, target_ty) else { return false; }; let ocx = ObligationCtxt::new(self); @@ -1369,7 +1372,7 @@ pub fn can_coerce<'tcx>( ) -> bool { let root_ctxt = crate::typeck_root_ctxt::TypeckRootCtxt::new(tcx, body_id); let fn_ctxt = FnCtxt::new(&root_ctxt, param_env, body_id); - fn_ctxt.can_coerce(ty, output_ty) + fn_ctxt.may_coerce(ty, output_ty) } /// CoerceMany encapsulates the pattern you should use when you have diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index b310398a0f1ba..7bdd3c95ad181 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1330,9 +1330,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let refs_can_coerce = |lhs: Ty<'tcx>, rhs: Ty<'tcx>| { let lhs = Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, lhs.peel_refs()); let rhs = Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, rhs.peel_refs()); - self.can_coerce(rhs, lhs) + self.may_coerce(rhs, lhs) }; - let (applicability, eq) = if self.can_coerce(rhs_ty, lhs_ty) { + let (applicability, eq) = if self.may_coerce(rhs_ty, lhs_ty) { (Applicability::MachineApplicable, true) } else if refs_can_coerce(rhs_ty, lhs_ty) { // The lhs and rhs are likely missing some references in either side. Subsequent @@ -1349,7 +1349,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let actual_lhs_ty = self.check_expr(rhs_expr); ( Applicability::MaybeIncorrect, - self.can_coerce(rhs_ty, actual_lhs_ty) + self.may_coerce(rhs_ty, actual_lhs_ty) || refs_can_coerce(rhs_ty, actual_lhs_ty), ) } else if let ExprKind::Binary( @@ -1363,7 +1363,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let actual_rhs_ty = self.check_expr(lhs_expr); ( Applicability::MaybeIncorrect, - self.can_coerce(actual_rhs_ty, lhs_ty) + self.may_coerce(actual_rhs_ty, lhs_ty) || refs_can_coerce(actual_rhs_ty, lhs_ty), ) } else { @@ -1414,7 +1414,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.param_env, ) .may_apply(); - if lhs_deref_ty_is_sized && self.can_coerce(rhs_ty, lhs_deref_ty) { + if lhs_deref_ty_is_sized && self.may_coerce(rhs_ty, lhs_deref_ty) { err.span_suggestion_verbose( lhs.span.shrink_to_lo(), "consider dereferencing here to assign to the mutably borrowed value", diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index fa471647d02d0..660cbc29d4cd6 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -658,7 +658,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && fn_sig.inputs()[1..] .iter() .zip(input_types.iter()) - .all(|(expected, found)| self.can_coerce(*expected, *found)) + .all(|(expected, found)| self.may_coerce(*expected, *found)) && fn_sig.inputs()[1..].len() == input_types.len() { err.span_suggestion_verbose( @@ -722,7 +722,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let expectation = Expectation::rvalue_hint(self, expected_input_ty); let coerced_ty = expectation.only_has_type(self).unwrap_or(formal_input_ty); - let can_coerce = self.can_coerce(arg_ty, coerced_ty); + let can_coerce = self.may_coerce(arg_ty, coerced_ty); if !can_coerce { return Compatibility::Incompatible(Some(ty::error::TypeError::Sorts( ty::error::ExpectedFound::new(true, coerced_ty, arg_ty), @@ -802,7 +802,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx + tys.len()), ), ) { - if !self.can_coerce(provided_ty, *expected_ty) { + if !self.may_coerce(provided_ty, *expected_ty) { satisfied = false; break; } @@ -1023,7 +1023,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { std::iter::zip(formal_and_expected_inputs.iter(), removed_arg_tys.iter()).all( |((expected_ty, _), (provided_ty, _))| { !provided_ty.references_error() - && self.can_coerce(*provided_ty, *expected_ty) + && self.may_coerce(*provided_ty, *expected_ty) }, ) }; @@ -2124,7 +2124,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let expr_ty = self.typeck_results.borrow().expr_ty(expr); let return_ty = fn_sig.output(); if !matches!(expr.kind, hir::ExprKind::Ret(..)) - && self.can_coerce(expr_ty, return_ty) + && self.may_coerce(expr_ty, return_ty) { found_semi = true; } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 3e9e53261562c..3f703c2fcf692 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -261,7 +261,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let hir::ExprKind::MethodCall(hir::PathSegment { ident: method, .. }, recv_expr, &[], _) = expr.kind && let Some(recv_ty) = self.typeck_results.borrow().expr_ty_opt(recv_expr) - && self.can_coerce(recv_ty, expected) + && self.may_coerce(recv_ty, expected) && let name = method.name.as_str() && (name.starts_with("to_") || name.starts_with("as_") || name == "into") { @@ -349,7 +349,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return true; } - if self.suggest_fn_call(err, expr, found, |output| self.can_coerce(output, expected)) + if self.suggest_fn_call(err, expr, found, |output| self.may_coerce(output, expected)) && let ty::FnDef(def_id, ..) = *found.kind() && let Some(sp) = self.tcx.hir().span_if_local(def_id) { @@ -568,7 +568,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if self.tcx.hir().is_inside_const_context(hir_id) || !expected.is_box() || found.is_box() { return false; } - if self.can_coerce(Ty::new_box(self.tcx, found), expected) { + if self.may_coerce(Ty::new_box(self.tcx, found), expected) { let suggest_boxing = match found.kind() { ty::Tuple(tuple) if tuple.is_empty() => { errors::SuggestBoxing::Unit { start: span.shrink_to_lo(), end: span } @@ -663,7 +663,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; match expected.kind() { ty::Adt(def, _) if Some(def.did()) == pin_did => { - if self.can_coerce(pin_box_found, expected) { + if self.may_coerce(pin_box_found, expected) { debug!("can coerce {:?} to {:?}, suggesting Box::pin", pin_box_found, expected); match found.kind() { ty::Adt(def, _) if def.is_box() => { @@ -689,7 +689,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } true - } else if self.can_coerce(pin_found, expected) { + } else if self.may_coerce(pin_found, expected) { match found.kind() { ty::Adt(def, _) if def.is_box() => { err.help("use `Box::pin`"); @@ -701,7 +701,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false } } - ty::Adt(def, _) if def.is_box() && self.can_coerce(box_found, expected) => { + ty::Adt(def, _) if def.is_box() && self.may_coerce(box_found, expected) => { // Check if the parent expression is a call to Pin::new. If it // is and we were expecting a Box, ergo Pin>, we // can suggest Box::pin. @@ -884,7 +884,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = Binder::bind_with_vars(ty, bound_vars); let ty = self.normalize(hir_ty.span, ty); let ty = self.tcx.instantiate_bound_regions_with_erased(ty); - if self.can_coerce(expected, ty) { + if self.may_coerce(expected, ty) { err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other { span: hir_ty.span, expected, @@ -1141,12 +1141,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Asyncness::No => ty, }; let ty = self.normalize(expr.span, ty); - self.can_coerce(found, ty) + self.may_coerce(found, ty) } hir::FnRetTy::DefaultReturn(_) if in_closure => { self.ret_coercion.as_ref().map_or(false, |ret| { let ret_ty = ret.borrow().expected_ty(); - self.can_coerce(found, ret_ty) + self.may_coerce(found, ret_ty) }) } _ => false, @@ -1510,7 +1510,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { provided_ty }; - if !self.can_coerce(expected_ty, dummy_ty) { + if !self.may_coerce(expected_ty, dummy_ty) { return; } let msg = format!("use `{adt_name}::map_or` to deref inner value of `{adt_name}`"); @@ -1534,7 +1534,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected_ty: Ty<'tcx>, ) { if let ty::Slice(elem_ty) | ty::Array(elem_ty, _) = expected_ty.kind() { - if self.can_coerce(blk_ty, *elem_ty) + if self.may_coerce(blk_ty, *elem_ty) && blk.stmts.is_empty() && blk.rules == hir::BlockCheckMode::DefaultBlock { @@ -1744,7 +1744,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if item_ty.has_param() { return false; } - if self.can_coerce(item_ty, expected_ty) { + if self.may_coerce(item_ty, expected_ty) { err.span_suggestion_verbose( segment.ident.span, format!("try referring to the associated const `{capitalized_name}` instead",), @@ -1804,7 +1804,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // diagnostic in cases where we have `(&&T).clone()` and we expect `T`). && !results.expr_adjustments(callee_expr).iter().any(|adj| matches!(adj.kind, ty::adjustment::Adjust::Deref(..))) // Check that we're in fact trying to clone into the expected type - && self.can_coerce(*pointee_ty, expected_ty) + && self.may_coerce(*pointee_ty, expected_ty) && let trait_ref = ty::TraitRef::new(self.tcx, clone_trait_did, [expected_ty]) // And the expected type doesn't implement `Clone` && !self.predicate_must_hold_considering_regions(&traits::Obligation::new( @@ -2022,7 +2022,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { return false; }; - if is_ctor || !self.can_coerce(args.type_at(0), expected) { + if is_ctor || !self.may_coerce(args.type_at(0), expected) { return false; } @@ -2293,7 +2293,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .then(|| " (its field is private, but it's local to this crate and its privacy can be changed)".to_string()); let sole_field_ty = sole_field.ty(self.tcx, args); - if self.can_coerce(expr_ty, sole_field_ty) { + if self.may_coerce(expr_ty, sole_field_ty) { let variant_path = with_no_trimmed_paths!(self.tcx.def_path_str(variant.def_id)); // FIXME #56861: DRYer prelude filtering @@ -2401,7 +2401,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let int_type = args.type_at(0); - if !self.can_coerce(expr_ty, int_type) { + if !self.may_coerce(expr_ty, int_type) { return false; } @@ -2585,7 +2585,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, checked_ty) } }; - if self.can_coerce(ref_ty, expected) { + if self.may_coerce(ref_ty, expected) { let mut sugg_sp = sp; if let hir::ExprKind::MethodCall(segment, receiver, args, _) = expr.kind { let clone_trait = diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 7f68e19a31392..9dd5954114860 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1934,7 +1934,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && fn_sig.inputs()[1..] .iter() .zip(args.into_iter()) - .all(|(expected, found)| self.can_coerce(*expected, *found)) + .all(|(expected, found)| self.may_coerce(*expected, *found)) && fn_sig.inputs()[1..].len() == args.len() { err.span_suggestion_verbose( @@ -4148,7 +4148,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return false; }; - if !self.can_coerce(output, expected) { + if !self.may_coerce(output, expected) { return false; } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index fb78da0a86c66..5ce9bae81c1c9 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -1767,7 +1767,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else if inexistent_fields.len() == 1 { match pat_field.pat.kind { PatKind::Lit(expr) - if !self.can_coerce( + if !self.may_coerce( self.typeck_results.borrow().expr_ty(expr), self.field_ty(field.span, field_def, args), ) => {} From e3eba2d9204e9af2ac7a089f61996b25cfecf2d8 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 15 Oct 2024 13:26:56 -0400 Subject: [PATCH 12/17] Don't structurally resolve in may_coerce --- compiler/rustc_hir_typeck/src/coercion.rs | 6 +---- .../lazy_subtyping_of_opaques.stderr | 24 ++++++++++++------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index a6df9e45db506..bb2f1f0493a7e 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1091,16 +1091,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// /// This should only be used for diagnostics. pub(crate) fn may_coerce(&self, expr_ty: Ty<'tcx>, target_ty: Ty<'tcx>) -> bool { - // FIXME(-Znext-solver): We need to structurally resolve both types here. - let source = self.resolve_vars_with_obligations(expr_ty); - debug!("coercion::can_with_predicates({:?} -> {:?})", source, target_ty); - let cause = self.cause(DUMMY_SP, ObligationCauseCode::ExprAssignable); // We don't ever need two-phase here since we throw out the result of the coercion. // We also just always set `coerce_never` to true, since this is a heuristic. let coerce = Coerce::new(self, cause, AllowTwoPhase::No, true); self.probe(|_| { - let Ok(ok) = coerce.coerce(source, target_ty) else { + let Ok(ok) = coerce.coerce(expr_ty, target_ty) else { return false; }; let ocx = ObligationCtxt::new(self); diff --git a/tests/ui/type-alias-impl-trait/lazy_subtyping_of_opaques.stderr b/tests/ui/type-alias-impl-trait/lazy_subtyping_of_opaques.stderr index 7bc2fa1b09ea6..921667f577b4e 100644 --- a/tests/ui/type-alias-impl-trait/lazy_subtyping_of_opaques.stderr +++ b/tests/ui/type-alias-impl-trait/lazy_subtyping_of_opaques.stderr @@ -1,3 +1,15 @@ +error[E0308]: mismatched types + --> $DIR/lazy_subtyping_of_opaques.rs:11:5 + | +LL | fn reify_as_tait() -> Thunk { + | ----------- expected `Thunk<_>` because of return type +LL | +LL | Thunk::new(|cont| cont) + | ^^^^^^^^^^^^^^^^^^^^^^^ expected `Thunk<_>`, found `()` + | + = note: expected struct `Thunk<_>` + found unit type `()` + error[E0277]: expected a `FnOnce()` closure, found `()` --> $DIR/lazy_subtyping_of_opaques.rs:11:23 | @@ -12,19 +24,13 @@ error[E0277]: expected a `FnOnce()` closure, found `()` | LL | fn reify_as_tait() -> Thunk { | ^^^^^^^^^^^ expected an `FnOnce()` closure, found `()` +LL | +LL | Thunk::new(|cont| cont) + | ----------------------- return type was inferred to be `{type error}` here | = help: the trait `FnOnce()` is not implemented for `()` = note: wrap the `()` in a closure with no arguments: `|| { /* code */ }` -error[E0308]: mismatched types - --> $DIR/lazy_subtyping_of_opaques.rs:11:5 - | -LL | Thunk::new(|cont| cont) - | ^^^^^^^^^^^^^^^^^^^^^^^ expected `Thunk<_>`, found `()` - | - = note: expected struct `Thunk<_>` - found unit type `()` - error: aborting due to 3 previous errors Some errors have detailed explanations: E0277, E0308. From 9070abab4b6862e42a8ce25eeb4a810301b76dd7 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 15 Oct 2024 13:47:43 -0400 Subject: [PATCH 13/17] Structurally resolve in may_coerce --- compiler/rustc_hir_typeck/src/coercion.rs | 23 +++++++++++++++++-- .../diagnostics/coerce-in-may-coerce.rs | 19 +++++++++++++++ .../diagnostics/coerce-in-may-coerce.stderr | 21 +++++++++++++++++ 3 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 tests/ui/traits/next-solver/diagnostics/coerce-in-may-coerce.rs create mode 100644 tests/ui/traits/next-solver/diagnostics/coerce-in-may-coerce.stderr diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index bb2f1f0493a7e..fb9262a59b9c9 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1094,12 +1094,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let cause = self.cause(DUMMY_SP, ObligationCauseCode::ExprAssignable); // We don't ever need two-phase here since we throw out the result of the coercion. // We also just always set `coerce_never` to true, since this is a heuristic. - let coerce = Coerce::new(self, cause, AllowTwoPhase::No, true); + let coerce = Coerce::new(self, cause.clone(), AllowTwoPhase::No, true); self.probe(|_| { + // Make sure to structurally resolve the types, since we use + // the `TyKind`s heavily in coercion. + let ocx = ObligationCtxt::new(self); + let structurally_resolve = |ty| { + let ty = self.shallow_resolve(ty); + if self.next_trait_solver() + && let ty::Alias(..) = ty.kind() + { + ocx.structurally_normalize(&cause, self.param_env, ty) + } else { + Ok(ty) + } + }; + let Ok(expr_ty) = structurally_resolve(expr_ty) else { + return false; + }; + let Ok(target_ty) = structurally_resolve(target_ty) else { + return false; + }; + let Ok(ok) = coerce.coerce(expr_ty, target_ty) else { return false; }; - let ocx = ObligationCtxt::new(self); ocx.register_obligations(ok.obligations); ocx.select_where_possible().is_empty() }) diff --git a/tests/ui/traits/next-solver/diagnostics/coerce-in-may-coerce.rs b/tests/ui/traits/next-solver/diagnostics/coerce-in-may-coerce.rs new file mode 100644 index 0000000000000..bd3dccad15280 --- /dev/null +++ b/tests/ui/traits/next-solver/diagnostics/coerce-in-may-coerce.rs @@ -0,0 +1,19 @@ +//@ compile-flags: -Znext-solver + +trait Mirror { + type Assoc; +} +impl Mirror for T { + type Assoc = T; +} + +fn arg() -> &'static [i32; 1] { todo!() } + +fn arg_error(x: ::Assoc, y: ()) { todo!() } + +fn main() { + // Should suggest to reverse the args... + // but if we don't normalize the expected, then we don't. + arg_error((), || ()); + //~^ ERROR arguments to this function are incorrect +} diff --git a/tests/ui/traits/next-solver/diagnostics/coerce-in-may-coerce.stderr b/tests/ui/traits/next-solver/diagnostics/coerce-in-may-coerce.stderr new file mode 100644 index 0000000000000..1938b3375a51a --- /dev/null +++ b/tests/ui/traits/next-solver/diagnostics/coerce-in-may-coerce.stderr @@ -0,0 +1,21 @@ +error[E0308]: arguments to this function are incorrect + --> $DIR/coerce-in-may-coerce.rs:17:5 + | +LL | arg_error((), || ()); + | ^^^^^^^^^ -- ----- expected `()`, found `{closure@$DIR/coerce-in-may-coerce.rs:17:19: 17:21}` + | | + | expected `::Assoc`, found `()` + | +note: function defined here + --> $DIR/coerce-in-may-coerce.rs:12:4 + | +LL | fn arg_error(x: ::Assoc, y: ()) { todo!() } + | ^^^^^^^^^ -------------------------- ----- +help: swap these arguments + | +LL | arg_error(|| (), ()); + | ~~~~~~~~~~~ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. From c7730989de17b0cbdc1d48481062745d31d5c5a0 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 28 Sep 2024 13:21:39 -0400 Subject: [PATCH 14/17] Don't check unsize goal in MIR validation when opaques remain --- compiler/rustc_mir_transform/src/validate.rs | 11 +++++++++++ tests/crashes/130921.rs | 10 ---------- tests/ui/impl-trait/unsize-cast-validation-rpit.rs | 12 ++++++++++++ 3 files changed, 23 insertions(+), 10 deletions(-) delete mode 100644 tests/crashes/130921.rs create mode 100644 tests/ui/impl-trait/unsize-cast-validation-rpit.rs diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index e353be6a105f0..25e68f44456b8 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -595,6 +595,17 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { &self, pred: impl Upcast, ty::Predicate<'tcx>>, ) -> bool { + let pred: ty::Predicate<'tcx> = pred.upcast(self.tcx); + + // We sometimes have to use `defining_opaque_types` for predicates + // to succeed here and figuring out how exactly that should work + // is annoying. It is harmless enough to just not validate anything + // in that case. We still check this after analysis as all opaque + // types have been revealed at this point. + if pred.has_opaque_types() { + return true; + } + let infcx = self.tcx.infer_ctxt().build(); let ocx = ObligationCtxt::new(&infcx); ocx.register_obligation(Obligation::new( diff --git a/tests/crashes/130921.rs b/tests/crashes/130921.rs deleted file mode 100644 index b7cb1303937e6..0000000000000 --- a/tests/crashes/130921.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ known-bug: #130921 -//@ compile-flags: -Zvalidate-mir -Copt-level=0 --crate-type lib - -pub fn hello() -> [impl Sized; 2] { - if false { - let x = hello(); - let _: &[i32] = &x; - } - todo!() -} diff --git a/tests/ui/impl-trait/unsize-cast-validation-rpit.rs b/tests/ui/impl-trait/unsize-cast-validation-rpit.rs new file mode 100644 index 0000000000000..cace30aca8a6d --- /dev/null +++ b/tests/ui/impl-trait/unsize-cast-validation-rpit.rs @@ -0,0 +1,12 @@ +//@ check-pass +//@ compile-flags: -Zvalidate-mir + +fn hello() -> &'static [impl Sized; 0] { + if false { + let x = hello(); + let _: &[i32] = x; + } + &[] +} + +fn main() {} From 476ea45c68223e4b2f9674d20f1aff8dd52fe1fb Mon Sep 17 00:00:00 2001 From: Hood Chatham Date: Wed, 16 Oct 2024 12:22:14 +0200 Subject: [PATCH 15/17] Emscripten: Xfail backtrace ui tests It is possible to link libunwind and use the normal backtrace code, but it fails to symbolize stack traces. I investigated and could get the list of instruction pointers and symbol names, but I'm not sure how to use the dwarf info to map from instruction pointer to source location. In any case, fixing this is probably not a high priority. See https://github.com/rust-lang/rust/issues/131738 --- tests/ui/backtrace/dylib-dep.rs | 1 + tests/ui/backtrace/line-tables-only.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/ui/backtrace/dylib-dep.rs b/tests/ui/backtrace/dylib-dep.rs index fcd1f92e28ebc..a41931ad54891 100644 --- a/tests/ui/backtrace/dylib-dep.rs +++ b/tests/ui/backtrace/dylib-dep.rs @@ -9,6 +9,7 @@ //@ ignore-musl musl doesn't support dynamic libraries (at least when the original test was written). //@ needs-unwind //@ compile-flags: -g -Copt-level=0 -Cstrip=none -Cforce-frame-pointers=yes +//@ ignore-emscripten Requires custom symbolization code //@ aux-crate: dylib_dep_helper=dylib-dep-helper.rs //@ aux-crate: auxiliary=dylib-dep-helper-aux.rs //@ run-pass diff --git a/tests/ui/backtrace/line-tables-only.rs b/tests/ui/backtrace/line-tables-only.rs index 044f59e483ab4..6624c71e184b0 100644 --- a/tests/ui/backtrace/line-tables-only.rs +++ b/tests/ui/backtrace/line-tables-only.rs @@ -10,6 +10,7 @@ //@ compile-flags: -Cstrip=none -Cdebuginfo=line-tables-only //@ ignore-android FIXME #17520 //@ ignore-fuchsia Backtraces not symbolized +//@ ignore-emscripten Requires custom symbolization code //@ needs-unwind //@ aux-build: line-tables-only-helper.rs From 89ea9e44f073a67a2b92de2ede5985acb1f810ec Mon Sep 17 00:00:00 2001 From: Michal Piotrowski Date: Wed, 16 Oct 2024 12:36:44 +0200 Subject: [PATCH 16/17] Fix trivially_copy_pass_by_ref in stable_mir --- compiler/stable_mir/src/mir/body.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index 742469a1c9325..f96487cc53c9f 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -1028,7 +1028,7 @@ impl ProjectionElem { ProjectionElem::Field(_idx, fty) => Ok(*fty), ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => Self::index_ty(ty), ProjectionElem::Subslice { from, to, from_end } => { - Self::subslice_ty(ty, from, to, from_end) + Self::subslice_ty(ty, *from, *to, *from_end) } ProjectionElem::Downcast(_) => Ok(ty), ProjectionElem::OpaqueCast(ty) | ProjectionElem::Subtype(ty) => Ok(*ty), @@ -1039,13 +1039,13 @@ impl ProjectionElem { ty.kind().builtin_index().ok_or_else(|| error!("Cannot index non-array type: {ty:?}")) } - fn subslice_ty(ty: Ty, from: &u64, to: &u64, from_end: &bool) -> Result { + fn subslice_ty(ty: Ty, from: u64, to: u64, from_end: bool) -> Result { let ty_kind = ty.kind(); match ty_kind { TyKind::RigidTy(RigidTy::Slice(..)) => Ok(ty), TyKind::RigidTy(RigidTy::Array(inner, _)) if !from_end => Ty::try_new_array( inner, - to.checked_sub(*from).ok_or_else(|| error!("Subslice overflow: {from}..{to}"))?, + to.checked_sub(from).ok_or_else(|| error!("Subslice overflow: {from}..{to}"))?, ), TyKind::RigidTy(RigidTy::Array(inner, size)) => { let size = size.eval_target_usize()?; From a10a44956e4efddf4fdf0f7a8b10796b9ae965ea Mon Sep 17 00:00:00 2001 From: Michal Piotrowski Date: Wed, 16 Oct 2024 13:31:23 +0200 Subject: [PATCH 17/17] Fix needless_lifetimes in stable_mir --- compiler/stable_mir/src/mir/visit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/stable_mir/src/mir/visit.rs b/compiler/stable_mir/src/mir/visit.rs index e2d1ff7fdd3a4..85205528979cf 100644 --- a/compiler/stable_mir/src/mir/visit.rs +++ b/compiler/stable_mir/src/mir/visit.rs @@ -487,7 +487,7 @@ pub struct PlaceRef<'a> { pub projection: &'a [ProjectionElem], } -impl<'a> PlaceRef<'a> { +impl PlaceRef<'_> { /// Get the type of this place. pub fn ty(&self, locals: &[LocalDecl]) -> Result { self.projection.iter().fold(Ok(locals[self.local].ty), |place_ty, elem| elem.ty(place_ty?))