From cf34545720986d99712e3b542e8f395360c75095 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sun, 27 Oct 2024 11:55:20 -0600 Subject: [PATCH 01/13] CI: build FreeBSD artifacts on FreeBSD 13.4 13.2 is EoL, and 13.3 will be EoL too in about 2 months. Plus, both suffer from a bug in LLVM's libunwind. It causes a segfault inside of std::backtrace::Backtrace::capture(). Fixes #132185 --- src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile | 6 +++--- src/ci/docker/scripts/freebsd-toolchain.sh | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile index f42e6f770ebe8..fd0f5da8c495a 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile @@ -29,9 +29,9 @@ COPY scripts/cmake.sh /scripts/ RUN /scripts/cmake.sh ENV \ - AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd12-ar \ - CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd12-clang \ - CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd12-clang++ + AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd13-ar \ + CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd13-clang \ + CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd13-clang++ ENV HOSTS=x86_64-unknown-freebsd diff --git a/src/ci/docker/scripts/freebsd-toolchain.sh b/src/ci/docker/scripts/freebsd-toolchain.sh index 0d02636db9196..b927658b4fdc2 100755 --- a/src/ci/docker/scripts/freebsd-toolchain.sh +++ b/src/ci/docker/scripts/freebsd-toolchain.sh @@ -5,8 +5,8 @@ set -eux arch=$1 binutils_version=2.40 -freebsd_version=12.3 -triple=$arch-unknown-freebsd12 +freebsd_version=13.4 +triple=$arch-unknown-freebsd13 sysroot=/usr/local/$triple hide_output() { @@ -59,7 +59,7 @@ done # Originally downloaded from: # URL=https://download.freebsd.org/ftp/releases/${freebsd_arch}/${freebsd_version}-RELEASE/base.txz -URL=https://ci-mirrors.rust-lang.org/rustc/2022-05-06-freebsd-${freebsd_version}-${freebsd_arch}-base.txz +URL=https://ci-mirrors.rust-lang.org/rustc/2024-09-13-freebsd-${freebsd_version}-${freebsd_arch}-base.txz curl "$URL" | tar xJf - -C "$sysroot" --wildcards "${files_to_extract[@]}" # Clang can do cross-builds out of the box, if we give it the right From 0454d7903b4e5508e5169efdb28e4fa94d2dc64a Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sun, 12 Jan 2025 14:27:56 -0700 Subject: [PATCH 02/13] Fixup: fix clang command lines in another file --- src/ci/docker/host-x86_64/dist-various-2/Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile index ece5f174d06de..8aabfaafbabbc 100644 --- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile @@ -56,9 +56,9 @@ ENV \ CFLAGS_x86_64_fortanix_unknown_sgx="-D__ELF__ -isystem/usr/include/x86_64-linux-gnu -mlvi-hardening -mllvm -x86-experimental-lvi-inline-asm-hardening" \ CXX_x86_64_fortanix_unknown_sgx=clang++-11 \ CXXFLAGS_x86_64_fortanix_unknown_sgx="-D__ELF__ -isystem/usr/include/x86_64-linux-gnu -mlvi-hardening -mllvm -x86-experimental-lvi-inline-asm-hardening" \ - AR_i686_unknown_freebsd=i686-unknown-freebsd12-ar \ - CC_i686_unknown_freebsd=i686-unknown-freebsd12-clang \ - CXX_i686_unknown_freebsd=i686-unknown-freebsd12-clang++ \ + AR_i686_unknown_freebsd=i686-unknown-freebsd13-ar \ + CC_i686_unknown_freebsd=i686-unknown-freebsd13-clang \ + CXX_i686_unknown_freebsd=i686-unknown-freebsd13-clang++ \ CC_aarch64_unknown_uefi=clang-11 \ CXX_aarch64_unknown_uefi=clang++-11 \ CC_i686_unknown_uefi=clang-11 \ From b2b12ae0cb6c7e6dd71092aafa14e06b57a290ec Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 19 Jan 2025 16:15:00 -0800 Subject: [PATCH 03/13] Add an example of using `carrying_mul_add` to write wider multiplication Just the basic quadratic version that you wouldn't actually want for a true bigint, but it's nice and short so is useful as an example :) --- library/core/src/num/uint_macros.rs | 33 +++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 404e4bcffd379..c8433b3bb168a 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -2663,8 +2663,8 @@ macro_rules! uint_impl { /// /// Basic usage: /// - /// Please note that this example is shared between integer types. - /// Which explains why `u32` is used here. + /// Please note that this example is shared between integer types, + /// which explains why `u32` is used here. /// /// ``` /// #![feature(bigint_helper_methods)] @@ -2677,6 +2677,35 @@ macro_rules! uint_impl { "(", stringify!($SelfT), "::MAX, ", stringify!($SelfT), "::MAX));" )] /// ``` + /// + /// This is the core per-digit operation for "grade school" O(n²) multiplication. + /// + /// Please note that this example is shared between integer types, + /// using `u8` for simplicity of the demonstration. + /// + /// ``` + /// #![feature(bigint_helper_methods)] + /// + /// fn quadratic_mul(a: [u8; N], b: [u8; N]) -> [u8; N] { + /// let mut out = [0; N]; + /// for j in 0..N { + /// let mut carry = 0; + /// for i in 0..(N - j) { + /// (out[j + i], carry) = u8::carrying_mul_add(a[i], b[j], out[j + i], carry); + /// } + /// } + /// out + /// } + /// + /// // -1 * -1 == 1 + /// assert_eq!(quadratic_mul([0xFF; 3], [0xFF; 3]), [1, 0, 0]); + /// + /// assert_eq!(u32::wrapping_mul(0x9e3779b9, 0x7f4a7c15), 0xCFFC982D); + /// assert_eq!( + /// quadratic_mul(u32::to_le_bytes(0x9e3779b9), u32::to_le_bytes(0x7f4a7c15)), + /// u32::to_le_bytes(0xCFFC982D) + /// ); + /// ``` #[unstable(feature = "bigint_helper_methods", issue = "85532")] #[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")] #[must_use = "this returns the result of the operation, \ From 8dec09f3c5bf8e1f12c6ba6eb6040d710353ca63 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 15 Jan 2025 21:57:10 +0100 Subject: [PATCH 04/13] support wasm inline assembly in naked functions --- .../rustc_codegen_ssa/src/mir/naked_asm.rs | 140 ++++++++++++- tests/assembly/wasm32-naked-fn.rs | 198 ++++++++++++++++++ 2 files changed, 334 insertions(+), 4 deletions(-) create mode 100644 tests/assembly/wasm32-naked-fn.rs diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs index 8df270abc8173..35e0ea545258f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs +++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs @@ -1,10 +1,12 @@ +use rustc_abi::{BackendRepr, Float, Integer, Primitive, RegKind}; use rustc_attr_parsing::InstructionSetAttr; use rustc_middle::mir::mono::{Linkage, MonoItem, MonoItemData, Visibility}; use rustc_middle::mir::{Body, InlineAsmOperand}; -use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf}; -use rustc_middle::ty::{Instance, TyCtxt}; +use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv, LayoutOf}; +use rustc_middle::ty::{Instance, Ty, TyCtxt}; use rustc_middle::{bug, ty}; use rustc_span::sym; +use rustc_target::callconv::{ArgAbi, FnAbi, PassMode}; use crate::common; use crate::traits::{AsmCodegenMethods, BuilderMethods, GlobalAsmOperandRef, MiscCodegenMethods}; @@ -32,7 +34,8 @@ pub(crate) fn codegen_naked_asm<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let item_data = cx.codegen_unit().items().get(&MonoItem::Fn(instance)).unwrap(); let name = cx.mangled_name(instance); - let (begin, end) = prefix_and_suffix(cx.tcx(), instance, &name, item_data); + let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty()); + let (begin, end) = prefix_and_suffix(cx.tcx(), instance, &name, item_data, fn_abi); let mut template_vec = Vec::new(); template_vec.push(rustc_ast::ast::InlineAsmTemplatePiece::String(begin.into())); @@ -103,6 +106,7 @@ enum AsmBinaryFormat { Elf, Macho, Coff, + Wasm, } impl AsmBinaryFormat { @@ -111,6 +115,8 @@ impl AsmBinaryFormat { Self::Coff } else if target.is_like_osx { Self::Macho + } else if target.is_like_wasm { + Self::Wasm } else { Self::Elf } @@ -122,6 +128,7 @@ fn prefix_and_suffix<'tcx>( instance: Instance<'tcx>, asm_name: &str, item_data: &MonoItemData, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, ) -> (String, String) { use std::fmt::Write; @@ -169,7 +176,7 @@ fn prefix_and_suffix<'tcx>( } Linkage::LinkOnceAny | Linkage::LinkOnceODR | Linkage::WeakAny | Linkage::WeakODR => { match asm_binary_format { - AsmBinaryFormat::Elf | AsmBinaryFormat::Coff => { + AsmBinaryFormat::Elf | AsmBinaryFormat::Coff | AsmBinaryFormat::Wasm => { writeln!(w, ".weak {asm_name}")?; } AsmBinaryFormat::Macho => { @@ -264,7 +271,132 @@ fn prefix_and_suffix<'tcx>( writeln!(end, "{}", arch_suffix).unwrap(); } } + AsmBinaryFormat::Wasm => { + let section = link_section.unwrap_or(format!(".text.{asm_name}")); + + writeln!(begin, ".section {section},\"\",@").unwrap(); + // wasm functions cannot be aligned, so skip + write_linkage(&mut begin).unwrap(); + if let Visibility::Hidden = item_data.visibility { + writeln!(begin, ".hidden {asm_name}").unwrap(); + } + writeln!(begin, ".type {asm_name}, @function").unwrap(); + if !arch_prefix.is_empty() { + writeln!(begin, "{}", arch_prefix).unwrap(); + } + writeln!(begin, "{asm_name}:").unwrap(); + writeln!(begin, ".functype {asm_name} {}", wasm_functype(tcx, fn_abi)).unwrap(); + + writeln!(end).unwrap(); + // .size is ignored for function symbols, so we can skip it + writeln!(end, "end_function").unwrap(); + } } (begin, end) } + +/// The webassembly type signature for the given function. +/// +/// Used by the `.functype` directive on wasm targets. +fn wasm_functype<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> String { + let mut signature = String::with_capacity(64); + + let ptr_type = match tcx.data_layout.pointer_size.bits() { + 32 => "i32", + 64 => "i64", + other => bug!("wasm pointer size cannot be {other} bits"), + }; + + let hidden_return = + matches!(fn_abi.ret.mode, PassMode::Indirect { .. } | PassMode::Pair { .. }); + + signature.push('('); + + if hidden_return { + signature.push_str(ptr_type); + if !fn_abi.args.is_empty() { + signature.push_str(", "); + } + } + + let mut it = fn_abi.args.iter().peekable(); + while let Some(arg_abi) = it.next() { + wasm_type(&mut signature, arg_abi, ptr_type); + if it.peek().is_some() { + signature.push_str(", "); + } + } + + signature.push_str(") -> ("); + + if !hidden_return { + wasm_type(&mut signature, &fn_abi.ret, ptr_type); + } + + signature.push(')'); + + signature +} + +fn wasm_type<'tcx>(signature: &mut String, arg_abi: &ArgAbi<'_, Ty<'tcx>>, ptr_type: &'static str) { + match arg_abi.mode { + PassMode::Ignore => { /* do nothing */ } + PassMode::Direct(_) => { + let direct_type = match arg_abi.layout.backend_repr { + BackendRepr::Scalar(scalar) => wasm_primitive(scalar.primitive(), ptr_type), + BackendRepr::Vector { .. } => "v128", + other => unreachable!("unexpected BackendRepr: {:?}", other), + }; + + signature.push_str(direct_type); + } + PassMode::Pair(_, _) => match arg_abi.layout.backend_repr { + BackendRepr::ScalarPair(a, b) => { + signature.push_str(wasm_primitive(a.primitive(), ptr_type)); + signature.push_str(", "); + signature.push_str(wasm_primitive(b.primitive(), ptr_type)); + } + other => unreachable!("{other:?}"), + }, + PassMode::Cast { pad_i32, ref cast } => { + // For wasm, Cast is used for single-field primitive wrappers like `struct Wrapper(i64);` + assert!(!pad_i32, "not currently used by wasm calling convention"); + assert!(cast.prefix[0].is_none(), "no prefix"); + assert_eq!(cast.rest.total, arg_abi.layout.size, "single item"); + + let wrapped_wasm_type = match cast.rest.unit.kind { + RegKind::Integer => match cast.rest.unit.size.bytes() { + ..=4 => "i32", + ..=8 => "i64", + _ => ptr_type, + }, + RegKind::Float => match cast.rest.unit.size.bytes() { + ..=4 => "f32", + ..=8 => "f64", + _ => ptr_type, + }, + RegKind::Vector => "v128", + }; + + signature.push_str(wrapped_wasm_type); + } + PassMode::Indirect { .. } => signature.push_str(ptr_type), + } +} + +fn wasm_primitive(primitive: Primitive, ptr_type: &'static str) -> &'static str { + match primitive { + Primitive::Int(integer, _) => match integer { + Integer::I8 | Integer::I16 | Integer::I32 => "i32", + Integer::I64 => "i64", + Integer::I128 => "i64, i64", + }, + Primitive::Float(float) => match float { + Float::F16 | Float::F32 => "f32", + Float::F64 => "f64", + Float::F128 => "i64, i64", + }, + Primitive::Pointer(_) => ptr_type, + } +} diff --git a/tests/assembly/wasm32-naked-fn.rs b/tests/assembly/wasm32-naked-fn.rs new file mode 100644 index 0000000000000..8e98b0847298f --- /dev/null +++ b/tests/assembly/wasm32-naked-fn.rs @@ -0,0 +1,198 @@ +//@ revisions: wasm32-unknown wasm64-unknown wasm32-wasip1 +//@ add-core-stubs +//@ assembly-output: emit-asm +//@ [wasm32-unknown] compile-flags: --target wasm32-unknown-unknown +//@ [wasm64-unknown] compile-flags: --target wasm64-unknown-unknown +//@ [wasm32-wasip1] compile-flags: --target wasm32-wasip1 +//@ [wasm32-unknown] needs-llvm-components: webassembly +//@ [wasm64-unknown] needs-llvm-components: webassembly +//@ [wasm32-wasip1] needs-llvm-components: webassembly + +#![crate_type = "lib"] +#![feature(no_core, naked_functions, asm_experimental_arch, f128, linkage, fn_align)] +#![no_core] + +extern crate minicore; +use minicore::*; + +// CHECK: .section .text.nop,"",@ +// CHECK: .globl nop +// CHECK-LABEL: nop: +// CHECK: .functype nop () -> () +// CHECK-NOT: .size +// CHECK: end_function +#[no_mangle] +#[naked] +unsafe extern "C" fn nop() { + naked_asm!("nop") +} + +// CHECK: .section .text.weak_aligned_nop,"",@ +// CHECK: .weak weak_aligned_nop +// CHECK-LABEL: nop: +// CHECK: .functype weak_aligned_nop () -> () +// CHECK-NOT: .size +// CHECK: end_function +#[no_mangle] +#[naked] +#[linkage = "weak"] +// wasm functions cannot be aligned, so this has no effect +#[repr(align(32))] +unsafe extern "C" fn weak_aligned_nop() { + naked_asm!("nop") +} + +// CHECK-LABEL: fn_i8_i8: +// CHECK-NEXT: .functype fn_i8_i8 (i32) -> (i32) +// +// CHECK-NEXT: local.get 0 +// CHECK-NEXT: local.get 0 +// CHECK-NEXT: i32.mul +// +// CHECK-NEXT: end_function +#[no_mangle] +#[naked] +unsafe extern "C" fn fn_i8_i8(num: i8) -> i8 { + naked_asm!("local.get 0", "local.get 0", "i32.mul") +} + +// CHECK-LABEL: fn_i8_i8_i8: +// CHECK: .functype fn_i8_i8_i8 (i32, i32) -> (i32) +#[no_mangle] +#[naked] +unsafe extern "C" fn fn_i8_i8_i8(a: i8, b: i8) -> i8 { + naked_asm!("local.get 1", "local.get 0", "i32.mul") +} + +// CHECK-LABEL: fn_unit_i8: +// CHECK: .functype fn_unit_i8 () -> (i32) +#[no_mangle] +#[naked] +unsafe extern "C" fn fn_unit_i8() -> i8 { + naked_asm!("i32.const 42") +} + +// CHECK-LABEL: fn_i8_unit: +// CHECK: .functype fn_i8_unit (i32) -> () +#[no_mangle] +#[naked] +unsafe extern "C" fn fn_i8_unit(_: i8) { + naked_asm!("nop") +} + +// CHECK-LABEL: fn_i32_i32: +// CHECK: .functype fn_i32_i32 (i32) -> (i32) +#[no_mangle] +#[naked] +unsafe extern "C" fn fn_i32_i32(num: i32) -> i32 { + naked_asm!("local.get 0", "local.get 0", "i32.mul") +} + +// CHECK-LABEL: fn_i64_i64: +// CHECK: .functype fn_i64_i64 (i64) -> (i64) +#[no_mangle] +#[naked] +unsafe extern "C" fn fn_i64_i64(num: i64) -> i64 { + naked_asm!("local.get 0", "local.get 0", "i64.mul") +} + +// CHECK-LABEL: fn_i128_i128: +// wasm32-unknown,wasm32-wasip1: .functype fn_i128_i128 (i32, i64, i64) -> () +// wasm64-unknown: .functype fn_i128_i128 (i64, i64, i64) -> () +#[allow(improper_ctypes_definitions)] +#[no_mangle] +#[naked] +unsafe extern "C" fn fn_i128_i128(num: i128) -> i128 { + naked_asm!( + "local.get 0", + "local.get 2", + "i64.store 8", + "local.get 0", + "local.get 1", + "i64.store 0", + ) +} + +// CHECK-LABEL: fn_f128_f128: +// wasm32-unknown,wasm32-wasip1: .functype fn_f128_f128 (i32, i64, i64) -> () +// wasm64-unknown: .functype fn_f128_f128 (i64, i64, i64) -> () +#[no_mangle] +#[naked] +unsafe extern "C" fn fn_f128_f128(num: f128) -> f128 { + naked_asm!( + "local.get 0", + "local.get 2", + "i64.store 8", + "local.get 0", + "local.get 1", + "i64.store 0", + ) +} + +#[repr(C)] +struct Compound { + a: u16, + b: i64, +} + +// CHECK-LABEL: fn_compound_compound: +// wasm32-wasip1: .functype fn_compound_compound (i32, i32) -> () +// wasm32-unknown: .functype fn_compound_compound (i32, i32, i64) -> () +// wasm64-unknown: .functype fn_compound_compound (i64, i64) -> () +#[no_mangle] +#[naked] +unsafe extern "C" fn fn_compound_compound(_: Compound) -> Compound { + // this is the wasm32-unknown-unknown assembly + naked_asm!( + "local.get 0", + "local.get 2", + "i64.store 8", + "local.get 0", + "local.get 1", + "i32.store16 0", + ) +} + +#[repr(C)] +struct WrapperI32(i32); + +// CHECK-LABEL: fn_wrapperi32_wrapperi32: +// CHECK: .functype fn_wrapperi32_wrapperi32 (i32) -> (i32) +#[no_mangle] +#[naked] +unsafe extern "C" fn fn_wrapperi32_wrapperi32(_: WrapperI32) -> WrapperI32 { + naked_asm!("local.get 0") +} + +#[repr(C)] +struct WrapperI64(i64); + +// CHECK-LABEL: fn_wrapperi64_wrapperi64: +// CHECK: .functype fn_wrapperi64_wrapperi64 (i64) -> (i64) +#[no_mangle] +#[naked] +unsafe extern "C" fn fn_wrapperi64_wrapperi64(_: WrapperI64) -> WrapperI64 { + naked_asm!("local.get 0") +} + +#[repr(C)] +struct WrapperF32(f32); + +// CHECK-LABEL: fn_wrapperf32_wrapperf32: +// CHECK: .functype fn_wrapperf32_wrapperf32 (f32) -> (f32) +#[no_mangle] +#[naked] +unsafe extern "C" fn fn_wrapperf32_wrapperf32(_: WrapperF32) -> WrapperF32 { + naked_asm!("local.get 0") +} + +#[repr(C)] +struct WrapperF64(f64); + +// CHECK-LABEL: fn_wrapperf64_wrapperf64: +// CHECK: .functype fn_wrapperf64_wrapperf64 (f64) -> (f64) +#[no_mangle] +#[naked] +unsafe extern "C" fn fn_wrapperf64_wrapperf64(_: WrapperF64) -> WrapperF64 { + naked_asm!("local.get 0") +} From bcf478b7a6915a8ce14009934f2893ddcce8052c Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Fri, 17 Jan 2025 22:34:26 +0100 Subject: [PATCH 05/13] work around the `wasm32-unknown-unknown` ABI being broken --- .../rustc_codegen_ssa/src/mir/naked_asm.rs | 47 +++++++++++++++---- tests/assembly/wasm32-naked-fn.rs | 17 +++---- 2 files changed, 48 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs index 35e0ea545258f..dc406809874d5 100644 --- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs +++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs @@ -1,12 +1,14 @@ use rustc_abi::{BackendRepr, Float, Integer, Primitive, RegKind}; use rustc_attr_parsing::InstructionSetAttr; +use rustc_hir::def_id::DefId; use rustc_middle::mir::mono::{Linkage, MonoItem, MonoItemData, Visibility}; use rustc_middle::mir::{Body, InlineAsmOperand}; use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv, LayoutOf}; use rustc_middle::ty::{Instance, Ty, TyCtxt}; -use rustc_middle::{bug, ty}; +use rustc_middle::{bug, span_bug, ty}; use rustc_span::sym; use rustc_target::callconv::{ArgAbi, FnAbi, PassMode}; +use rustc_target::spec::WasmCAbi; use crate::common; use crate::traits::{AsmCodegenMethods, BuilderMethods, GlobalAsmOperandRef, MiscCodegenMethods}; @@ -285,7 +287,12 @@ fn prefix_and_suffix<'tcx>( writeln!(begin, "{}", arch_prefix).unwrap(); } writeln!(begin, "{asm_name}:").unwrap(); - writeln!(begin, ".functype {asm_name} {}", wasm_functype(tcx, fn_abi)).unwrap(); + writeln!( + begin, + ".functype {asm_name} {}", + wasm_functype(tcx, fn_abi, instance.def_id()) + ) + .unwrap(); writeln!(end).unwrap(); // .size is ignored for function symbols, so we can skip it @@ -299,7 +306,7 @@ fn prefix_and_suffix<'tcx>( /// The webassembly type signature for the given function. /// /// Used by the `.functype` directive on wasm targets. -fn wasm_functype<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> String { +fn wasm_functype<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, def_id: DefId) -> String { let mut signature = String::with_capacity(64); let ptr_type = match tcx.data_layout.pointer_size.bits() { @@ -308,8 +315,18 @@ fn wasm_functype<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Str other => bug!("wasm pointer size cannot be {other} bits"), }; - let hidden_return = - matches!(fn_abi.ret.mode, PassMode::Indirect { .. } | PassMode::Pair { .. }); + // FIXME: remove this once the wasm32-unknown-unknown ABI is fixed + // please also add `wasm32-unknown-unknown` back in `tests/assembly/wasm32-naked-fn.rs` + // basically the commit introducing this comment should be reverted + if let PassMode::Pair { .. } = fn_abi.ret.mode { + let _ = WasmCAbi::Legacy; + span_bug!( + tcx.def_span(def_id), + "cannot return a pair (the wasm32-unknown-unknown ABI is broken, see https://github.com/rust-lang/rust/issues/115666" + ); + } + + let hidden_return = matches!(fn_abi.ret.mode, PassMode::Indirect { .. }); signature.push('('); @@ -322,7 +339,7 @@ fn wasm_functype<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Str let mut it = fn_abi.args.iter().peekable(); while let Some(arg_abi) = it.next() { - wasm_type(&mut signature, arg_abi, ptr_type); + wasm_type(tcx, &mut signature, arg_abi, ptr_type, def_id); if it.peek().is_some() { signature.push_str(", "); } @@ -331,7 +348,7 @@ fn wasm_functype<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Str signature.push_str(") -> ("); if !hidden_return { - wasm_type(&mut signature, &fn_abi.ret, ptr_type); + wasm_type(tcx, &mut signature, &fn_abi.ret, ptr_type, def_id); } signature.push(')'); @@ -339,13 +356,27 @@ fn wasm_functype<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Str signature } -fn wasm_type<'tcx>(signature: &mut String, arg_abi: &ArgAbi<'_, Ty<'tcx>>, ptr_type: &'static str) { +fn wasm_type<'tcx>( + tcx: TyCtxt<'tcx>, + signature: &mut String, + arg_abi: &ArgAbi<'_, Ty<'tcx>>, + ptr_type: &'static str, + def_id: DefId, +) { match arg_abi.mode { PassMode::Ignore => { /* do nothing */ } PassMode::Direct(_) => { let direct_type = match arg_abi.layout.backend_repr { BackendRepr::Scalar(scalar) => wasm_primitive(scalar.primitive(), ptr_type), BackendRepr::Vector { .. } => "v128", + BackendRepr::Memory { .. } => { + // FIXME: remove this branch once the wasm32-unknown-unknown ABI is fixed + let _ = WasmCAbi::Legacy; + span_bug!( + tcx.def_span(def_id), + "cannot use memory args (the wasm32-unknown-unknown ABI is broken, see https://github.com/rust-lang/rust/issues/115666" + ); + } other => unreachable!("unexpected BackendRepr: {:?}", other), }; diff --git a/tests/assembly/wasm32-naked-fn.rs b/tests/assembly/wasm32-naked-fn.rs index 8e98b0847298f..4911a6bd08f68 100644 --- a/tests/assembly/wasm32-naked-fn.rs +++ b/tests/assembly/wasm32-naked-fn.rs @@ -1,10 +1,10 @@ -//@ revisions: wasm32-unknown wasm64-unknown wasm32-wasip1 +// FIXME: add wasm32-unknown when the wasm32-unknown-unknown ABI is fixed +// see https://github.com/rust-lang/rust/issues/115666 +//@ revisions: wasm64-unknown wasm32-wasip1 //@ add-core-stubs //@ assembly-output: emit-asm -//@ [wasm32-unknown] compile-flags: --target wasm32-unknown-unknown //@ [wasm64-unknown] compile-flags: --target wasm64-unknown-unknown //@ [wasm32-wasip1] compile-flags: --target wasm32-wasip1 -//@ [wasm32-unknown] needs-llvm-components: webassembly //@ [wasm64-unknown] needs-llvm-components: webassembly //@ [wasm32-wasip1] needs-llvm-components: webassembly @@ -97,7 +97,7 @@ unsafe extern "C" fn fn_i64_i64(num: i64) -> i64 { } // CHECK-LABEL: fn_i128_i128: -// wasm32-unknown,wasm32-wasip1: .functype fn_i128_i128 (i32, i64, i64) -> () +// wasm32-wasip1: .functype fn_i128_i128 (i32, i64, i64) -> () // wasm64-unknown: .functype fn_i128_i128 (i64, i64, i64) -> () #[allow(improper_ctypes_definitions)] #[no_mangle] @@ -114,7 +114,7 @@ unsafe extern "C" fn fn_i128_i128(num: i128) -> i128 { } // CHECK-LABEL: fn_f128_f128: -// wasm32-unknown,wasm32-wasip1: .functype fn_f128_f128 (i32, i64, i64) -> () +// wasm32-wasip1: .functype fn_f128_f128 (i32, i64, i64) -> () // wasm64-unknown: .functype fn_f128_f128 (i64, i64, i64) -> () #[no_mangle] #[naked] @@ -137,18 +137,19 @@ struct Compound { // CHECK-LABEL: fn_compound_compound: // wasm32-wasip1: .functype fn_compound_compound (i32, i32) -> () -// wasm32-unknown: .functype fn_compound_compound (i32, i32, i64) -> () // wasm64-unknown: .functype fn_compound_compound (i64, i64) -> () #[no_mangle] #[naked] unsafe extern "C" fn fn_compound_compound(_: Compound) -> Compound { - // this is the wasm32-unknown-unknown assembly + // this is the wasm32-wasip1 assembly naked_asm!( "local.get 0", - "local.get 2", + "local.get 1", + "i64.load 8", "i64.store 8", "local.get 0", "local.get 1", + "i32.load16_u 0", "i32.store16 0", ) } From a175e8d90312a113869d366ba7dde0742df7f5e2 Mon Sep 17 00:00:00 2001 From: MarcoIeni <11428655+MarcoIeni@users.noreply.github.com> Date: Mon, 20 Jan 2025 17:38:17 +0100 Subject: [PATCH 06/13] CI: free disk on linux arm runner --- src/ci/github-actions/jobs.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 799ea3e9ad2df..ecd8642d76674 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -44,6 +44,8 @@ runners: <<: *base-job - &job-aarch64-linux + # Free some disk space to avoid running out of space during the build. + free_disk: true os: ubuntu-22.04-arm envs: From 9d6a1c980e7de879d6eb64c281aac3cdfdefce3f Mon Sep 17 00:00:00 2001 From: jyn Date: Sat, 18 Jan 2025 16:55:31 -0500 Subject: [PATCH 07/13] Shorten linker output even more when `--verbose` is not present - Don't show environment variables. Seeing PATH is almost never useful, and it can be extremely long. - For .rlibs in the sysroot, replace crate hashes with a `"-*"` string. This will expand to the full crate name when pasted into the shell. - Move `.rlib` to outside the glob. - Abbreviate the sysroot path to `` wherever it appears in the arguments. This also adds an example of the linker output as a run-make test. Currently it only runs on x86_64-unknown-linux-gnu, because each platform has its own linker arguments. So that it's stable across machines, pass BUILD_ROOT as an argument through compiletest through to run-make tests. --- Cargo.lock | 1 + compiler/rustc_codegen_ssa/Cargo.toml | 1 + .../rustc_codegen_ssa/src/back/command.rs | 17 ++++- compiler/rustc_codegen_ssa/src/back/link.rs | 1 + compiler/rustc_codegen_ssa/src/errors.rs | 62 ++++++++++++++----- src/tools/compiletest/src/runtest/run_make.rs | 2 + src/tools/run-make-support/src/lib.rs | 2 +- .../run-make-support/src/path_helpers.rs | 6 ++ src/tools/tidy/src/deps.rs | 1 + tests/run-make/linker-warning/rmake.rs | 41 ++++++++---- tests/run-make/linker-warning/short-error.txt | 9 +++ 11 files changed, 115 insertions(+), 28 deletions(-) create mode 100644 tests/run-make/linker-warning/short-error.txt diff --git a/Cargo.lock b/Cargo.lock index a08d43a014c06..2917b9ef5d91a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3536,6 +3536,7 @@ dependencies = [ "ar_archive_writer", "arrayvec", "bitflags", + "bstr", "cc", "either", "itertools", diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 3254b5d38e7a4..904297b987268 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" ar_archive_writer = "0.4.2" arrayvec = { version = "0.7", default-features = false } bitflags = "2.4.1" +bstr = "1.11.3" # Pinned so `cargo update` bumps don't cause breakage. Please also update the # `cc` in `rustc_llvm` if you update the `cc` here. cc = "=1.2.7" diff --git a/compiler/rustc_codegen_ssa/src/back/command.rs b/compiler/rustc_codegen_ssa/src/back/command.rs index b3c5b86ccf430..63023fdba20fc 100644 --- a/compiler/rustc_codegen_ssa/src/back/command.rs +++ b/compiler/rustc_codegen_ssa/src/back/command.rs @@ -13,6 +13,7 @@ pub(crate) struct Command { args: Vec, env: Vec<(OsString, OsString)>, env_remove: Vec, + env_clear: bool, } #[derive(Clone)] @@ -36,7 +37,13 @@ impl Command { } fn _new(program: Program) -> Command { - Command { program, args: Vec::new(), env: Vec::new(), env_remove: Vec::new() } + Command { + program, + args: Vec::new(), + env: Vec::new(), + env_remove: Vec::new(), + env_clear: false, + } } pub(crate) fn arg>(&mut self, arg: P) -> &mut Command { @@ -79,6 +86,11 @@ impl Command { self } + pub(crate) fn env_clear(&mut self) -> &mut Command { + self.env_clear = true; + self + } + fn _env_remove(&mut self, key: &OsStr) { self.env_remove.push(key.to_owned()); } @@ -106,6 +118,9 @@ impl Command { for k in &self.env_remove { ret.env_remove(k); } + if self.env_clear { + ret.env_clear(); + } ret } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index df35b5e8426f1..ba59bd1266af7 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -991,6 +991,7 @@ fn link_natively( command: cmd, escaped_output, verbose: sess.opts.verbose, + sysroot_dir: sess.sysroot.clone(), }; sess.dcx().emit_err(err); // If MSVC's `link.exe` was expected but the return code diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index c7213bbc801f9..5e684632fb247 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -351,6 +351,7 @@ pub(crate) struct LinkingFailed<'a> { pub command: Command, pub escaped_output: String, pub verbose: bool, + pub sysroot_dir: PathBuf, } impl Diagnostic<'_, G> for LinkingFailed<'_> { @@ -364,6 +365,8 @@ impl Diagnostic<'_, G> for LinkingFailed<'_> { if self.verbose { diag.note(format!("{:?}", self.command)); } else { + self.command.env_clear(); + enum ArgGroup { Regular(OsString), Objects(usize), @@ -398,26 +401,55 @@ impl Diagnostic<'_, G> for LinkingFailed<'_> { args.push(ArgGroup::Regular(arg)); } } - self.command.args(args.into_iter().map(|arg_group| match arg_group { - ArgGroup::Regular(arg) => arg, - ArgGroup::Objects(n) => OsString::from(format!("<{n} object files omitted>")), - ArgGroup::Rlibs(dir, rlibs) => { - let mut arg = dir.into_os_string(); - arg.push("/{"); - let mut first = true; - for rlib in rlibs { - if !first { - arg.push(","); + let crate_hash = regex::bytes::Regex::new(r"-[0-9a-f]+\.rlib$").unwrap(); + self.command.args(args.into_iter().map(|arg_group| { + match arg_group { + // SAFETY: we are only matching on ASCII, not any surrogate pairs, so any replacements we do will still be valid. + ArgGroup::Regular(arg) => unsafe { + use bstr::ByteSlice; + OsString::from_encoded_bytes_unchecked( + arg.as_encoded_bytes().replace( + self.sysroot_dir.as_os_str().as_encoded_bytes(), + b"", + ), + ) + }, + ArgGroup::Objects(n) => OsString::from(format!("<{n} object files omitted>")), + ArgGroup::Rlibs(mut dir, rlibs) => { + let is_sysroot_dir = match dir.strip_prefix(&self.sysroot_dir) { + Ok(short) => { + dir = Path::new("").join(short); + true + } + Err(_) => false, + }; + let mut arg = dir.into_os_string(); + arg.push("/{"); + let mut first = true; + for mut rlib in rlibs { + if !first { + arg.push(","); + } + first = false; + if is_sysroot_dir { + // SAFETY: Regex works one byte at a type, and our regex will not match surrogate pairs (because it only matches ascii). + rlib = unsafe { + OsString::from_encoded_bytes_unchecked( + crate_hash + .replace(rlib.as_encoded_bytes(), b"-*") + .into_owned(), + ) + }; + } + arg.push(rlib); } - first = false; - arg.push(rlib); + arg.push("}.rlib"); + arg } - arg.push("}"); - arg } })); - diag.note(format!("{:?}", self.command)); + diag.note(format!("{:?}", self.command).trim_start_matches("env -i").to_owned()); diag.note("some arguments are omitted. use `--verbose` to show all linker arguments"); } diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs index 8a49d63053521..7ef16e4a9667b 100644 --- a/src/tools/compiletest/src/runtest/run_make.rs +++ b/src/tools/compiletest/src/runtest/run_make.rs @@ -414,6 +414,8 @@ impl TestCx<'_> { // Provide path to checkout root. This is the top-level directory containing // rust-lang/rust checkout. .env("SOURCE_ROOT", &source_root) + // Path to the build directory. This is usually the same as `source_root.join("build").join("host")`. + .env("BUILD_ROOT", &build_root) // Provide path to stage-corresponding rustc. .env("RUSTC", &self.config.rustc_path) // Provide the directory to libraries that are needed to run the *compiler*. This is not diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index ffd4ca22a0086..7316244b3841d 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -90,7 +90,7 @@ pub use artifact_names::{ /// Path-related helpers. pub use path_helpers::{ cwd, filename_contains, filename_not_in_denylist, has_extension, has_prefix, has_suffix, - not_contains, path, shallow_find_files, source_root, + not_contains, path, shallow_find_files, build_root, source_root, }; /// Helpers for scoped test execution where certain properties are attempted to be maintained. diff --git a/src/tools/run-make-support/src/path_helpers.rs b/src/tools/run-make-support/src/path_helpers.rs index 87901793a921e..1c59f2feea4c7 100644 --- a/src/tools/run-make-support/src/path_helpers.rs +++ b/src/tools/run-make-support/src/path_helpers.rs @@ -34,6 +34,12 @@ pub fn source_root() -> PathBuf { env_var("SOURCE_ROOT").into() } +/// Path to the build directory root. +#[must_use] +pub fn build_root() -> PathBuf { + env_var("BUILD_ROOT").into() +} + /// Browse the directory `path` non-recursively and return all files which respect the parameters /// outlined by `closure`. #[track_caller] diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index d4cbc37f6d2b3..e9e2deb240f5f 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -253,6 +253,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "bitflags", "blake3", "block-buffer", + "bstr", "byteorder", // via ruzstd in object in thorin-dwp "cc", "cfg-if", diff --git a/tests/run-make/linker-warning/rmake.rs b/tests/run-make/linker-warning/rmake.rs index 4d21c5ea5690a..88e467e6cce3f 100644 --- a/tests/run-make/linker-warning/rmake.rs +++ b/tests/run-make/linker-warning/rmake.rs @@ -1,8 +1,16 @@ -use run_make_support::{Rustc, rustc}; +use run_make_support::{Rustc, diff, regex, rustc}; fn run_rustc() -> Rustc { let mut rustc = rustc(); - rustc.arg("main.rs").output("main").linker("./fake-linker"); + rustc + .arg("main.rs") + // NOTE: `link-self-contained` can vary depending on config.toml. + // Make sure we use a consistent value. + .arg("-Clink-self-contained=-linker") + .arg("-Clinker-flavor=gnu-cc") + .arg("-Zunstable-options") + .output("main") + .linker("./fake-linker"); rustc } @@ -11,18 +19,29 @@ fn main() { rustc().arg("fake-linker.rs").output("fake-linker").run(); // Make sure we don't show the linker args unless `--verbose` is passed - run_rustc() - .link_arg("run_make_error") - .verbose() - .run_fail() - .assert_stderr_contains_regex("fake-linker.*run_make_error") + let out = run_rustc().link_arg("run_make_error").verbose().run_fail(); + out.assert_stderr_contains_regex("fake-linker.*run_make_error") .assert_stderr_not_contains("object files omitted") + .assert_stderr_contains("PATH=\"") .assert_stderr_contains_regex(r"lib(/|\\\\)libstd"); - run_rustc() - .link_arg("run_make_error") - .run_fail() - .assert_stderr_contains("fake-linker") + + let out = run_rustc().link_arg("run_make_error").run_fail(); + out.assert_stderr_contains("fake-linker") .assert_stderr_contains("object files omitted") .assert_stderr_contains_regex(r"\{") + .assert_stderr_not_contains("PATH=\"") .assert_stderr_not_contains_regex(r"lib(/|\\\\)libstd"); + + // FIXME: we should have a version of this for mac and windows + if run_make_support::target() == "x86_64-unknown-linux-gnu" { + diff() + .expected_file("short-error.txt") + .actual_text("(linker error)", out.stderr()) + .normalize(r#"/rustc[^/]*/"#, "/rustc/") + .normalize( + regex::escape(run_make_support::build_root().to_str().unwrap()), + "/build-root", + ) + .run(); + } } diff --git a/tests/run-make/linker-warning/short-error.txt b/tests/run-make/linker-warning/short-error.txt new file mode 100644 index 0000000000000..dd3b742bbfd56 --- /dev/null +++ b/tests/run-make/linker-warning/short-error.txt @@ -0,0 +1,9 @@ +error: linking with `./fake-linker` failed: exit status: 1 + | + = note: "./fake-linker" "-m64" "/tmp/rustc/symbols.o" "<2 object files omitted>" "-Wl,--as-needed" "-Wl,-Bstatic" "/lib/rustlib/x86_64-unknown-linux-gnu/lib/{libstd-*,libpanic_unwind-*,libobject-*,libmemchr-*,libaddr2line-*,libgimli-*,librustc_demangle-*,libstd_detect-*,libhashbrown-*,librustc_std_workspace_alloc-*,libminiz_oxide-*,libadler2-*,libunwind-*,libcfg_if-*,liblibc-*,liballoc-*,librustc_std_workspace_core-*,libcore-*,libcompiler_builtins-*}.rlib" "-Wl,-Bdynamic" "-lgcc_s" "-lutil" "-lrt" "-lpthread" "-lm" "-ldl" "-lc" "-Wl,--eh-frame-hdr" "-Wl,-z,noexecstack" "-L" "/build-root/test/run-make/linker-warning/rmake_out" "-L" "/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-o" "main" "-Wl,--gc-sections" "-pie" "-Wl,-z,relro,-z,now" "-nodefaultlibs" "run_make_error" + = note: some arguments are omitted. use `--verbose` to show all linker arguments + = note: error: baz + + +error: aborting due to 1 previous error + From 9d88b82b99cdd43c79e5fb5d031e522347863db2 Mon Sep 17 00:00:00 2001 From: jyn Date: Mon, 20 Jan 2025 16:08:08 -0500 Subject: [PATCH 08/13] Ignore `mermaid.min.js` It is very long and tends to match a lot of search queries. It's not useful to show with ripgrep. Note that this does not actually untrack the file; changes can still be committed (although I suspect it may not have been intentional to commit originally?). This just changes how it interacts with tools that use `.gitignore` as a default filter. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index f84a3704ca900..ddc8dad95e809 100644 --- a/.gitignore +++ b/.gitignore @@ -83,6 +83,7 @@ __pycache__/ node_modules package-lock.json package.json +/src/doc/rustc-dev-guide/mermaid.min.js ## Rustdoc GUI tests tests/rustdoc-gui/src/**.lock From 51af4d6d228490bb97cc53f9eea50647e0443513 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 21 Jan 2025 10:23:14 +0100 Subject: [PATCH 09/13] Add Kobzol on vacation --- triagebot.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/triagebot.toml b/triagebot.toml index 5ee52bbf435c9..4a09fe116a572 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1025,6 +1025,7 @@ users_on_vacation = [ "nnethercote", "spastorino", "workingjubilee", + "kobzol" ] [[assign.warn_non_default_branch.exceptions]] From 00381ead1af39db9e5ce24a8da4dda59b714dbf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 2 Jan 2025 18:02:57 +0100 Subject: [PATCH 10/13] Make it possible to build GCC on CI This is the first step to enable download of precompiled GCC --- src/bootstrap/src/core/build_steps/gcc.rs | 54 +++++++++++++++++-- .../host-x86_64/dist-x86_64-linux/Dockerfile | 1 + src/ci/docker/scripts/build-zstd.sh | 6 +++ 3 files changed, 57 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/gcc.rs b/src/bootstrap/src/core/build_steps/gcc.rs index 563b715fa6400..98b8635132b0d 100644 --- a/src/bootstrap/src/core/build_steps/gcc.rs +++ b/src/bootstrap/src/core/build_steps/gcc.rs @@ -12,6 +12,8 @@ use std::fs; use std::path::PathBuf; use std::sync::OnceLock; +use build_helper::ci::CiEnv; + use crate::Kind; use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::core::config::TargetSelection; @@ -112,16 +114,60 @@ impl Step for Gcc { return true; } - command(root.join("contrib/download_prerequisites")).current_dir(&root).run(builder); - command(root.join("configure")) + // GCC creates files (e.g. symlinks to the downloaded dependencies) + // in the source directory, which does not work with our CI setup, where we mount + // source directories as read-only on Linux. + // Therefore, as a part of the build in CI, we first copy the whole source directory + // to the build directory, and perform the build from there. + let src_dir = if CiEnv::is_ci() { + let src_dir = builder.gcc_out(target).join("src"); + if src_dir.exists() { + builder.remove_dir(&src_dir); + } + builder.create_dir(&src_dir); + builder.cp_link_r(&root, &src_dir); + src_dir + } else { + root + }; + + command(src_dir.join("contrib/download_prerequisites")).current_dir(&src_dir).run(builder); + let mut configure_cmd = command(src_dir.join("configure")); + configure_cmd .current_dir(&out_dir) + // On CI, we compile GCC with Clang. + // The -Wno-everything flag is needed to make GCC compile with Clang 19. + // `-g -O2` are the default flags that are otherwise used by Make. + // FIXME(kobzol): change the flags once we have [gcc] configuration in config.toml. + .env("CXXFLAGS", "-Wno-everything -g -O2") + .env("CFLAGS", "-Wno-everything -g -O2") .arg("--enable-host-shared") .arg("--enable-languages=jit") .arg("--enable-checking=release") .arg("--disable-bootstrap") .arg("--disable-multilib") - .arg(format!("--prefix={}", install_dir.display())) - .run(builder); + .arg(format!("--prefix={}", install_dir.display())); + let cc = builder.build.cc(target).display().to_string(); + let cc = builder + .build + .config + .ccache + .as_ref() + .map_or_else(|| cc.clone(), |ccache| format!("{ccache} {cc}")); + configure_cmd.env("CC", cc); + + if let Ok(ref cxx) = builder.build.cxx(target) { + let cxx = cxx.display().to_string(); + let cxx = builder + .build + .config + .ccache + .as_ref() + .map_or_else(|| cxx.clone(), |ccache| format!("{ccache} {cxx}")); + configure_cmd.env("CXX", cxx); + } + configure_cmd.run(builder); + command("make").current_dir(&out_dir).arg(format!("-j{}", builder.jobs())).run(builder); command("make").current_dir(&out_dir).arg("install").run(builder); diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile index dde6fe7f6d0f3..3a39623058255 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile @@ -34,6 +34,7 @@ RUN yum upgrade -y && \ python3 \ unzip \ wget \ + flex \ xz \ zlib-devel.i686 \ zlib-devel.x86_64 \ diff --git a/src/ci/docker/scripts/build-zstd.sh b/src/ci/docker/scripts/build-zstd.sh index a3d37ccc31120..cffa7151e3864 100755 --- a/src/ci/docker/scripts/build-zstd.sh +++ b/src/ci/docker/scripts/build-zstd.sh @@ -25,5 +25,11 @@ cd zstd-$ZSTD CFLAGS=-fPIC hide_output make -j$(nproc) VERBOSE=1 hide_output make install +# It doesn't seem to be possible to move destination directory +# of the `make install` above. We thus copy the built artifacts +# manually to our custom rustroot, so that it can be found through +# LD_LIBRARY_PATH. +cp /usr/local/lib/libzstd* /rustroot/lib64 + cd .. rm -rf zstd-$ZSTD From bac4db378b5108d973f17c2010adbfede83d8f2a Mon Sep 17 00:00:00 2001 From: Boxy Date: Tue, 21 Jan 2025 11:10:02 +0000 Subject: [PATCH 11/13] Use `structurally_normalize` instead of manual `normalizes-to` goals --- .../rustc_next_trait_solver/src/solve/mod.rs | 42 +++++------ .../traits/fulfillment_errors.rs | 21 +++--- .../src/traits/engine.rs | 11 +++ .../src/traits/structural_normalize.rs | 71 +++++++------------ ...not-fn.stderr => is-not-fn.current.stderr} | 8 +-- .../async-closures/is-not-fn.next.stderr | 19 +++++ .../async-await/async-closures/is-not-fn.rs | 5 +- ...stituting-in-region-112823.current.stderr} | 6 +- ...nsubstituting-in-region-112823.next.stderr | 29 ++++++++ ...-type-whensubstituting-in-region-112823.rs | 8 ++- ...3941.stderr => issue-33941.current.stderr} | 6 +- tests/ui/issues/issue-33941.next.stderr | 25 +++++++ tests/ui/issues/issue-33941.rs | 6 +- ...rg-type-mismatch-issue-45727.current.fixed | 12 ++++ ...-type-mismatch-issue-45727.current.stderr} | 4 +- ...losure-arg-type-mismatch-issue-45727.fixed | 5 -- ...-arg-type-mismatch-issue-45727.next.stderr | 24 +++++++ .../closure-arg-type-mismatch-issue-45727.rs | 13 +++- ...elate_error_uses_structurally_normalize.rs | 28 ++++++++ 19 files changed, 236 insertions(+), 107 deletions(-) rename tests/ui/async-await/async-closures/{is-not-fn.stderr => is-not-fn.current.stderr} (77%) create mode 100644 tests/ui/async-await/async-closures/is-not-fn.next.stderr rename tests/ui/impl-trait/{ice-unexpected-param-type-whensubstituting-in-region-112823.stderr => ice-unexpected-param-type-whensubstituting-in-region-112823.current.stderr} (96%) create mode 100644 tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.next.stderr rename tests/ui/issues/{issue-33941.stderr => issue-33941.current.stderr} (93%) create mode 100644 tests/ui/issues/issue-33941.next.stderr create mode 100644 tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.fixed rename tests/ui/mismatched_types/{closure-arg-type-mismatch-issue-45727.stderr => closure-arg-type-mismatch-issue-45727.current.stderr} (92%) delete mode 100644 tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.fixed create mode 100644 tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr create mode 100644 tests/ui/traits/next-solver/diagnostics/alias_relate_error_uses_structurally_normalize.rs diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 37678bfd8805f..8d1194ee53980 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -277,23 +277,7 @@ where param_env: I::ParamEnv, ty: I::Ty, ) -> Result { - if let ty::Alias(..) = ty.kind() { - let normalized_ty = self.next_ty_infer(); - let alias_relate_goal = Goal::new( - self.cx(), - param_env, - ty::PredicateKind::AliasRelate( - ty.into(), - normalized_ty.into(), - ty::AliasRelationDirection::Equate, - ), - ); - self.add_goal(GoalSource::Misc, alias_relate_goal); - self.try_evaluate_added_goals()?; - Ok(self.resolve_vars_if_possible(normalized_ty)) - } else { - Ok(ty) - } + self.structurally_normalize_term(param_env, ty.into()).map(|term| term.expect_ty()) } /// Normalize a const for when it is structurally matched on, or more likely @@ -308,22 +292,34 @@ where param_env: I::ParamEnv, ct: I::Const, ) -> Result { - if let ty::ConstKind::Unevaluated(..) = ct.kind() { - let normalized_ct = self.next_const_infer(); + self.structurally_normalize_term(param_env, ct.into()).map(|term| term.expect_const()) + } + + /// Normalize a term for when it is structurally matched on. + /// + /// This function is necessary in nearly all cases before matching on a ty/const. + /// Not doing so is likely to be incomplete and therefore unsound during coherence. + fn structurally_normalize_term( + &mut self, + param_env: I::ParamEnv, + term: I::Term, + ) -> Result { + if let Some(_) = term.to_alias_term() { + let normalized_term = self.next_term_infer_of_kind(term); let alias_relate_goal = Goal::new( self.cx(), param_env, ty::PredicateKind::AliasRelate( - ct.into(), - normalized_ct.into(), + term, + normalized_term, ty::AliasRelationDirection::Equate, ), ); self.add_goal(GoalSource::Misc, alias_relate_goal); self.try_evaluate_added_goals()?; - Ok(self.resolve_vars_if_possible(normalized_ct)) + Ok(self.resolve_vars_if_possible(normalized_term)) } else { - Ok(ct) + Ok(term) } } 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 c40ba33084569..bcd3b0109b709 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 @@ -1338,20 +1338,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let derive_better_type_error = |alias_term: ty::AliasTerm<'tcx>, expected_term: ty::Term<'tcx>| { let ocx = ObligationCtxt::new(self); - let normalized_term = match expected_term.unpack() { - ty::TermKind::Ty(_) => self.next_ty_var(DUMMY_SP).into(), - ty::TermKind::Const(_) => self.next_const_var(DUMMY_SP).into(), - }; - ocx.register_obligation(Obligation::new( - self.tcx, - ObligationCause::dummy(), + + let Ok(normalized_term) = ocx.structurally_normalize_term( + &ObligationCause::dummy(), obligation.param_env, - ty::PredicateKind::NormalizesTo(ty::NormalizesTo { - alias: alias_term, - term: normalized_term, - }), - )); - let _ = ocx.select_where_possible(); + alias_term.to_term(self.tcx), + ) else { + return None; + }; + if let Err(terr) = ocx.eq( &ObligationCause::dummy(), obligation.param_env, diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 5e270b62b0081..48b26ee19d4dc 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -340,4 +340,15 @@ where .at(cause, param_env) .structurally_normalize_const(value, &mut **self.engine.borrow_mut()) } + + pub fn structurally_normalize_term( + &self, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + value: ty::Term<'tcx>, + ) -> Result, Vec> { + self.infcx + .at(cause, param_env) + .structurally_normalize_term(value, &mut **self.engine.borrow_mut()) + } } diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs index f8e8f2176c182..458791df66fd6 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs @@ -12,39 +12,7 @@ impl<'tcx> At<'_, 'tcx> { ty: Ty<'tcx>, fulfill_cx: &mut dyn TraitEngine<'tcx, E>, ) -> Result, Vec> { - assert!(!ty.is_ty_var(), "should have resolved vars before calling"); - - if self.infcx.next_trait_solver() { - let ty::Alias(..) = *ty.kind() else { - return Ok(ty); - }; - - let new_infer_ty = self.infcx.next_ty_var(self.cause.span); - - // We simply emit an `alias-eq` goal here, since that will take care of - // normalizing the LHS of the projection until it is a rigid projection - // (or a not-yet-defined opaque in scope). - let obligation = Obligation::new( - self.infcx.tcx, - self.cause.clone(), - self.param_env, - ty::PredicateKind::AliasRelate( - ty.into(), - new_infer_ty.into(), - ty::AliasRelationDirection::Equate, - ), - ); - - fulfill_cx.register_predicate_obligation(self.infcx, obligation); - let errors = fulfill_cx.select_where_possible(self.infcx); - if !errors.is_empty() { - return Err(errors); - } - - Ok(self.infcx.resolve_vars_if_possible(new_infer_ty)) - } else { - Ok(self.normalize(ty).into_value_registering_obligations(self.infcx, fulfill_cx)) - } + self.structurally_normalize_term(ty.into(), fulfill_cx).map(|term| term.expect_type()) } fn structurally_normalize_const( @@ -52,14 +20,29 @@ impl<'tcx> At<'_, 'tcx> { ct: ty::Const<'tcx>, fulfill_cx: &mut dyn TraitEngine<'tcx, E>, ) -> Result, Vec> { - assert!(!ct.is_ct_infer(), "should have resolved vars before calling"); + if self.infcx.tcx.features().generic_const_exprs() { + return Ok(super::evaluate_const(&self.infcx, ct, self.param_env)); + } + + self.structurally_normalize_term(ct.into(), fulfill_cx).map(|term| term.expect_const()) + } + + fn structurally_normalize_term( + &self, + term: ty::Term<'tcx>, + fulfill_cx: &mut dyn TraitEngine<'tcx, E>, + ) -> Result, Vec> { + assert!(!term.is_infer(), "should have resolved vars before calling"); if self.infcx.next_trait_solver() { - let ty::ConstKind::Unevaluated(..) = ct.kind() else { - return Ok(ct); - }; + if let None = term.to_alias_term() { + return Ok(term); + } - let new_infer_ct = self.infcx.next_const_var(self.cause.span); + let new_infer = match term.unpack() { + ty::TermKind::Ty(_) => self.infcx.next_ty_var(self.cause.span).into(), + ty::TermKind::Const(_) => self.infcx.next_const_var(self.cause.span).into(), + }; // We simply emit an `alias-eq` goal here, since that will take care of // normalizing the LHS of the projection until it is a rigid projection @@ -68,11 +51,7 @@ impl<'tcx> At<'_, 'tcx> { self.infcx.tcx, self.cause.clone(), self.param_env, - ty::PredicateKind::AliasRelate( - ct.into(), - new_infer_ct.into(), - ty::AliasRelationDirection::Equate, - ), + ty::PredicateKind::AliasRelate(term, new_infer, ty::AliasRelationDirection::Equate), ); fulfill_cx.register_predicate_obligation(self.infcx, obligation); @@ -81,11 +60,9 @@ impl<'tcx> At<'_, 'tcx> { return Err(errors); } - Ok(self.infcx.resolve_vars_if_possible(new_infer_ct)) - } else if self.infcx.tcx.features().generic_const_exprs() { - Ok(super::evaluate_const(&self.infcx, ct, self.param_env)) + Ok(self.infcx.resolve_vars_if_possible(new_infer)) } else { - Ok(self.normalize(ct).into_value_registering_obligations(self.infcx, fulfill_cx)) + Ok(self.normalize(term).into_value_registering_obligations(self.infcx, fulfill_cx)) } } } diff --git a/tests/ui/async-await/async-closures/is-not-fn.stderr b/tests/ui/async-await/async-closures/is-not-fn.current.stderr similarity index 77% rename from tests/ui/async-await/async-closures/is-not-fn.stderr rename to tests/ui/async-await/async-closures/is-not-fn.current.stderr index bc1d5e6e9d112..e7be1d5b10efe 100644 --- a/tests/ui/async-await/async-closures/is-not-fn.stderr +++ b/tests/ui/async-await/async-closures/is-not-fn.current.stderr @@ -1,5 +1,5 @@ -error[E0271]: expected `{async closure@is-not-fn.rs:5:14}` to be a closure that returns `()`, but it returns `{async closure body@$DIR/is-not-fn.rs:5:23: 5:25}` - --> $DIR/is-not-fn.rs:5:14 +error[E0271]: expected `{async closure@is-not-fn.rs:8:14}` to be a closure that returns `()`, but it returns `{async closure body@$DIR/is-not-fn.rs:8:23: 8:25}` + --> $DIR/is-not-fn.rs:8:14 | LL | needs_fn(async || {}); | -------- ^^^^^^^^^^^ expected `()`, found `async` closure body @@ -7,9 +7,9 @@ LL | needs_fn(async || {}); | required by a bound introduced by this call | = note: expected unit type `()` - found `async` closure body `{async closure body@$DIR/is-not-fn.rs:5:23: 5:25}` + found `async` closure body `{async closure body@$DIR/is-not-fn.rs:8:23: 8:25}` note: required by a bound in `needs_fn` - --> $DIR/is-not-fn.rs:4:25 + --> $DIR/is-not-fn.rs:7:25 | LL | fn needs_fn(x: impl FnOnce()) {} | ^^^^^^^^ required by this bound in `needs_fn` diff --git a/tests/ui/async-await/async-closures/is-not-fn.next.stderr b/tests/ui/async-await/async-closures/is-not-fn.next.stderr new file mode 100644 index 0000000000000..e7be1d5b10efe --- /dev/null +++ b/tests/ui/async-await/async-closures/is-not-fn.next.stderr @@ -0,0 +1,19 @@ +error[E0271]: expected `{async closure@is-not-fn.rs:8:14}` to be a closure that returns `()`, but it returns `{async closure body@$DIR/is-not-fn.rs:8:23: 8:25}` + --> $DIR/is-not-fn.rs:8:14 + | +LL | needs_fn(async || {}); + | -------- ^^^^^^^^^^^ expected `()`, found `async` closure body + | | + | required by a bound introduced by this call + | + = note: expected unit type `()` + found `async` closure body `{async closure body@$DIR/is-not-fn.rs:8:23: 8:25}` +note: required by a bound in `needs_fn` + --> $DIR/is-not-fn.rs:7:25 + | +LL | fn needs_fn(x: impl FnOnce()) {} + | ^^^^^^^^ required by this bound in `needs_fn` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/async-await/async-closures/is-not-fn.rs b/tests/ui/async-await/async-closures/is-not-fn.rs index 4acaa5d9809a1..eacd07b7cdd86 100644 --- a/tests/ui/async-await/async-closures/is-not-fn.rs +++ b/tests/ui/async-await/async-closures/is-not-fn.rs @@ -1,7 +1,10 @@ //@ edition:2021 +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver fn main() { fn needs_fn(x: impl FnOnce()) {} needs_fn(async || {}); - //~^ ERROR expected `{async closure@is-not-fn.rs:5:14}` to be a closure that returns `()` + //~^ ERROR expected `{async closure@is-not-fn.rs:8:14}` to be a closure that returns `()` } diff --git a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.stderr b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.current.stderr similarity index 96% rename from tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.stderr rename to tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.current.stderr index 28a0f7461e2d5..146a3d21068cd 100644 --- a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.stderr +++ b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.current.stderr @@ -1,11 +1,11 @@ error[E0407]: method `line_stream` is not a member of trait `X` - --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:25:5 + --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:28:5 | LL | fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a member of trait `X` error[E0049]: type `LineStream` has 0 type parameters but its trait declaration has 1 type parameter - --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:22:21 + --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:25:21 | LL | type LineStream<'a, Repr> | -- ---- @@ -18,7 +18,7 @@ LL | type LineStream<'c, 'd> = impl Stream; | found 0 type parameters error[E0277]: `()` is not a future - --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:25:43 + --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:28:43 | LL | fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not a future diff --git a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.next.stderr b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.next.stderr new file mode 100644 index 0000000000000..3c24eb9adbee7 --- /dev/null +++ b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.next.stderr @@ -0,0 +1,29 @@ +error[E0407]: method `line_stream` is not a member of trait `X` + --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:28:5 + | +LL | fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a member of trait `X` + +error[E0049]: type `LineStream` has 0 type parameters but its trait declaration has 1 type parameter + --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:25:21 + | +LL | type LineStream<'a, Repr> + | -- ---- + | | + | expected 1 type parameter +... +LL | type LineStream<'c, 'd> = impl Stream; + | ^^ ^^ + | | + | found 0 type parameters + +error[E0271]: type mismatch resolving `::LineStreamFut<'a, Repr> == ()` + --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:28:43 + | +LL | fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0049, E0271, E0407. +For more information about an error, try `rustc --explain E0049`. diff --git a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs index d6fa56663a3f0..c97bd1799436f 100644 --- a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs +++ b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs @@ -1,3 +1,6 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver // test for ICE #112823 // Unexpected parameter Type(Repr) when substituting in region @@ -23,8 +26,9 @@ impl X for Y { //~^ ERROR type `LineStream` has 0 type parameters but its trait declaration has 1 type parameter type LineStreamFut<'a, Repr> = impl Future>; fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {} - //~^ ERROR `()` is not a future - //~^^ method `line_stream` is not a member of trait `X` + //[current]~^ ERROR `()` is not a future + //[next]~^^ ERROR type mismatch resolving `::LineStreamFut<'a, Repr> == ()` + //~^^^ method `line_stream` is not a member of trait `X` } pub fn main() {} diff --git a/tests/ui/issues/issue-33941.stderr b/tests/ui/issues/issue-33941.current.stderr similarity index 93% rename from tests/ui/issues/issue-33941.stderr rename to tests/ui/issues/issue-33941.current.stderr index 9535ea57430d0..d653bbd327427 100644 --- a/tests/ui/issues/issue-33941.stderr +++ b/tests/ui/issues/issue-33941.current.stderr @@ -1,5 +1,5 @@ error[E0271]: expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)` - --> $DIR/issue-33941.rs:6:36 + --> $DIR/issue-33941.rs:9:36 | LL | for _ in HashMap::new().iter().cloned() {} | ^^^^^^ expected `&_`, found `(&_, &_)` @@ -7,7 +7,7 @@ LL | for _ in HashMap::new().iter().cloned() {} = note: expected reference `&_` found tuple `(&_, &_)` note: the method call chain might not have had the expected associated types - --> $DIR/issue-33941.rs:6:29 + --> $DIR/issue-33941.rs:9:29 | LL | for _ in HashMap::new().iter().cloned() {} | -------------- ^^^^^^ `Iterator::Item` is `(&_, &_)` here @@ -17,7 +17,7 @@ note: required by a bound in `cloned` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL error[E0271]: expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)` - --> $DIR/issue-33941.rs:6:14 + --> $DIR/issue-33941.rs:9:14 | LL | for _ in HashMap::new().iter().cloned() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&_`, found `(&_, &_)` diff --git a/tests/ui/issues/issue-33941.next.stderr b/tests/ui/issues/issue-33941.next.stderr new file mode 100644 index 0000000000000..a5a6e51545a58 --- /dev/null +++ b/tests/ui/issues/issue-33941.next.stderr @@ -0,0 +1,25 @@ +error[E0271]: expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)` + --> $DIR/issue-33941.rs:9:36 + | +LL | for _ in HashMap::new().iter().cloned() {} + | ^^^^^^ expected `&_`, found `(&_, &_)` + | + = note: expected reference `&_` + found tuple `(&_, &_)` +note: required by a bound in `cloned` + --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL + +error[E0271]: expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)` + --> $DIR/issue-33941.rs:9:14 + | +LL | for _ in HashMap::new().iter().cloned() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&_`, found `(&_, &_)` + | + = note: expected reference `&_` + found tuple `(&_, &_)` + = note: required for `Cloned>` to implement `Iterator` + = note: required for `Cloned>` to implement `IntoIterator` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/issues/issue-33941.rs b/tests/ui/issues/issue-33941.rs index 7b5be30834b9d..b0736204a0811 100644 --- a/tests/ui/issues/issue-33941.rs +++ b/tests/ui/issues/issue-33941.rs @@ -1,8 +1,12 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver //@ compile-flags: -Zdeduplicate-diagnostics=yes use std::collections::HashMap; fn main() { - for _ in HashMap::new().iter().cloned() {} //~ ERROR expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)` + for _ in HashMap::new().iter().cloned() {} //~^ ERROR expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)` + //~| ERROR expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)` } diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.fixed b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.fixed new file mode 100644 index 0000000000000..7383ab177dc31 --- /dev/null +++ b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.fixed @@ -0,0 +1,12 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@[current] run-rustfix +fn main() { + let _ = (-10..=10).find(|x: &i32| x.signum() == 0); + //[current]~^ ERROR type mismatch in closure arguments + //[next]~^^ ERROR expected a `FnMut(& as Iterator>::Item)` closure, found + let _ = (-10..=10).find(|x: &i32| x.signum() == 0); + //[current]~^ ERROR type mismatch in closure arguments + //[next]~^^ ERROR expected `RangeInclusive<{integer}>` to be an iterator that yields `&&i32`, but it yields `{integer}` +} diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.stderr b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.stderr similarity index 92% rename from tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.stderr rename to tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.stderr index e52e095e9f729..c35d70a635cbd 100644 --- a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.stderr +++ b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.stderr @@ -1,5 +1,5 @@ error[E0631]: type mismatch in closure arguments - --> $DIR/closure-arg-type-mismatch-issue-45727.rs:3:24 + --> $DIR/closure-arg-type-mismatch-issue-45727.rs:6:24 | LL | let _ = (-10..=10).find(|x: i32| x.signum() == 0); | ^^^^ -------- found signature defined here @@ -16,7 +16,7 @@ LL | let _ = (-10..=10).find(|x: &i32| x.signum() == 0); | + error[E0631]: type mismatch in closure arguments - --> $DIR/closure-arg-type-mismatch-issue-45727.rs:4:24 + --> $DIR/closure-arg-type-mismatch-issue-45727.rs:9:24 | LL | let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0); | ^^^^ ----------- found signature defined here diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.fixed b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.fixed deleted file mode 100644 index e6e3e1551e959..0000000000000 --- a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.fixed +++ /dev/null @@ -1,5 +0,0 @@ -//@ run-rustfix -fn main() { - let _ = (-10..=10).find(|x: &i32| x.signum() == 0); //~ ERROR type mismatch in closure arguments - let _ = (-10..=10).find(|x: &i32| x.signum() == 0); //~ ERROR type mismatch in closure arguments -} diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr new file mode 100644 index 0000000000000..6104a08933737 --- /dev/null +++ b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr @@ -0,0 +1,24 @@ +error[E0277]: expected a `FnMut(& as Iterator>::Item)` closure, found `{closure@$DIR/closure-arg-type-mismatch-issue-45727.rs:6:29: 6:37}` + --> $DIR/closure-arg-type-mismatch-issue-45727.rs:6:29 + | +LL | let _ = (-10..=10).find(|x: i32| x.signum() == 0); + | ---- ^^^^^^^^^^^^^^^^^^^^^^^^ expected an `FnMut(& as Iterator>::Item)` closure, found `{closure@$DIR/closure-arg-type-mismatch-issue-45727.rs:6:29: 6:37}` + | | + | required by a bound introduced by this call + | + = help: the trait `for<'a> FnMut(&'a as Iterator>::Item)` is not implemented for closure `{closure@$DIR/closure-arg-type-mismatch-issue-45727.rs:6:29: 6:37}` + = note: expected a closure with arguments `(i32,)` + found a closure with arguments `(& as Iterator>::Item,)` +note: required by a bound in `find` + --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL + +error[E0271]: expected `RangeInclusive<{integer}>` to be an iterator that yields `&&i32`, but it yields `{integer}` + --> $DIR/closure-arg-type-mismatch-issue-45727.rs:9:33 + | +LL | let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0); + | ^^^^^^ expected `&&i32`, found integer + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0271, E0277. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs index 64e815606d427..668a1a7a29c6f 100644 --- a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs +++ b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs @@ -1,5 +1,12 @@ -//@ run-rustfix +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@[current] run-rustfix fn main() { - let _ = (-10..=10).find(|x: i32| x.signum() == 0); //~ ERROR type mismatch in closure arguments - let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0); //~ ERROR type mismatch in closure arguments + let _ = (-10..=10).find(|x: i32| x.signum() == 0); + //[current]~^ ERROR type mismatch in closure arguments + //[next]~^^ ERROR expected a `FnMut(& as Iterator>::Item)` closure, found + let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0); + //[current]~^ ERROR type mismatch in closure arguments + //[next]~^^ ERROR expected `RangeInclusive<{integer}>` to be an iterator that yields `&&i32`, but it yields `{integer}` } diff --git a/tests/ui/traits/next-solver/diagnostics/alias_relate_error_uses_structurally_normalize.rs b/tests/ui/traits/next-solver/diagnostics/alias_relate_error_uses_structurally_normalize.rs new file mode 100644 index 0000000000000..5cea9bb74d793 --- /dev/null +++ b/tests/ui/traits/next-solver/diagnostics/alias_relate_error_uses_structurally_normalize.rs @@ -0,0 +1,28 @@ +//@ compile-flags: -Znext-solver + +// When encountering a fulfillment error from an `alias-relate` goal failing, we +// would previously manually construct a `normalizes-to` goal involving the alias +// and an infer var. This would then ICE as normalization would return a nested +// goal (the `T: Sized` from the `Trait` impl for `Foo` below) from the root goal +// which is not supported. + +struct Foo(T); + +trait Trait { + type Assoc; +} + +// `T: Sized` being explicit is not required, but the bound being present *is*. +impl Trait for Foo { + type Assoc = u64; +} + +fn bar>(_: T) {} + +fn main() { + let foo = Foo(Default::default()); + bar(foo); + //~^ ERROR: type mismatch resolving ` as Trait>::Assoc == u32` + // Here diagnostics would manually construct a ` as Trait>::Assoc normalizes-to ?x` goal + // which would return a nested goal of `?y: Sized` from the impl. +} From dbf4040b66eff160bd48c9c04aa8ceb026c19d42 Mon Sep 17 00:00:00 2001 From: Boxy Date: Tue, 21 Jan 2025 11:22:30 +0000 Subject: [PATCH 12/13] Rename `structurally_normalize` to `structurally_normalize_ty` --- compiler/rustc_borrowck/src/type_check/canonical.rs | 4 ++-- compiler/rustc_hir_analysis/src/autoderef.rs | 8 ++++---- compiler/rustc_hir_analysis/src/coherence/orphan.rs | 2 +- compiler/rustc_hir_typeck/src/coercion.rs | 2 +- compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs | 2 +- compiler/rustc_trait_selection/src/traits/coherence.rs | 2 +- compiler/rustc_trait_selection/src/traits/engine.rs | 4 ++-- .../src/traits/structural_normalize.rs | 2 +- 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index 3903c45fda529..bffd9f383343d 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -185,7 +185,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { CustomTypeOp::new( |ocx| { let structurally_normalize = |ty| { - ocx.structurally_normalize( + ocx.structurally_normalize_ty( &ObligationCause::misc( location.to_locations().span(body), body.source.def_id().expect_local(), @@ -230,7 +230,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ConstraintCategory::Boring, CustomTypeOp::new( |ocx| { - ocx.structurally_normalize( + ocx.structurally_normalize_ty( &ObligationCause::misc( location.to_locations().span(body), body.source.def_id().expect_local(), diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs index d8e9227a87c86..b3eade8c8ae47 100644 --- a/compiler/rustc_hir_analysis/src/autoderef.rs +++ b/compiler/rustc_hir_analysis/src/autoderef.rs @@ -86,7 +86,7 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> { if self.infcx.next_trait_solver() && let ty::Alias(..) = ty.kind() { - let (normalized_ty, obligations) = self.structurally_normalize(ty)?; + let (normalized_ty, obligations) = self.structurally_normalize_ty(ty)?; self.state.obligations.extend(obligations); (AutoderefKind::Builtin, normalized_ty) } else { @@ -166,7 +166,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { } let (normalized_ty, obligations) = - self.structurally_normalize(Ty::new_projection(tcx, trait_target_def_id, [ty]))?; + self.structurally_normalize_ty(Ty::new_projection(tcx, trait_target_def_id, [ty]))?; debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations); self.state.obligations.extend(obligations); @@ -174,12 +174,12 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { } #[instrument(level = "debug", skip(self), ret)] - pub fn structurally_normalize( + pub fn structurally_normalize_ty( &self, ty: Ty<'tcx>, ) -> Option<(Ty<'tcx>, PredicateObligations<'tcx>)> { let ocx = ObligationCtxt::new(self.infcx); - let Ok(normalized_ty) = ocx.structurally_normalize( + let Ok(normalized_ty) = ocx.structurally_normalize_ty( &traits::ObligationCause::misc(self.span, self.body_id), self.param_env, ty, diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 7d651155781a1..d17ee86ba667c 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -320,7 +320,7 @@ fn orphan_check<'tcx>( } let ty = if infcx.next_trait_solver() { - ocx.structurally_normalize( + ocx.structurally_normalize_ty( &cause, ty::ParamEnv::empty(), infcx.resolve_vars_if_possible(ty), diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 6945dbc321697..3c25f4a8b7cc2 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1124,7 +1124,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if self.next_trait_solver() && let ty::Alias(..) = ty.kind() { - ocx.structurally_normalize(&cause, self.param_env, ty) + ocx.structurally_normalize_ty(&cause, self.param_env, ty) } else { Ok(ty) } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index be6d9570e35b4..e26c09e3601cb 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1433,7 +1433,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // in a reentrant borrow, causing an ICE. let result = self .at(&self.misc(sp), self.param_env) - .structurally_normalize(ty, &mut **self.fulfillment_cx.borrow_mut()); + .structurally_normalize_ty(ty, &mut **self.fulfillment_cx.borrow_mut()); match result { Ok(normalized_ty) => normalized_ty, Err(errors) => { diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index e27143f139641..50d47d20e1a4e 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -709,7 +709,7 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> { if matches!(ty.kind(), ty::Alias(..)) { let ocx = ObligationCtxt::new(infcx); ty = ocx - .structurally_normalize(&ObligationCause::dummy(), param_env, ty) + .structurally_normalize_ty(&ObligationCause::dummy(), param_env, ty) .map_err(|_| ())?; if !ocx.select_where_possible().is_empty() { return Err(()); diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 48b26ee19d4dc..4a3983fca31ce 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -319,7 +319,7 @@ where self.infcx.at(cause, param_env).deeply_normalize(value, &mut **self.engine.borrow_mut()) } - pub fn structurally_normalize( + pub fn structurally_normalize_ty( &self, cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -327,7 +327,7 @@ where ) -> Result, Vec> { self.infcx .at(cause, param_env) - .structurally_normalize(value, &mut **self.engine.borrow_mut()) + .structurally_normalize_ty(value, &mut **self.engine.borrow_mut()) } pub fn structurally_normalize_const( diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs index 458791df66fd6..e6d5d336b8d55 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs @@ -7,7 +7,7 @@ use crate::traits::{NormalizeExt, Obligation}; #[extension(pub trait StructurallyNormalizeExt<'tcx>)] impl<'tcx> At<'_, 'tcx> { - fn structurally_normalize( + fn structurally_normalize_ty( &self, ty: Ty<'tcx>, fulfill_cx: &mut dyn TraitEngine<'tcx, E>, From 587b9c64d02c5ccf35eeef74d635dc3596bdf74a Mon Sep 17 00:00:00 2001 From: Caio Date: Tue, 21 Jan 2025 08:45:33 -0300 Subject: [PATCH 13/13] [cfg_match] Document the use of expressions --- library/core/src/macros/mod.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 5c04e5a40df09..6b93b44226d76 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -313,6 +313,17 @@ pub macro cfg_match { /// } /// } /// ``` +/// +/// If desired, it is possible to return expressions through the use of surrounding braces: +/// +/// ``` +/// #![feature(cfg_match)] +/// +/// let _some_string = cfg_match! {{ +/// unix => { "With great power comes great electricity bills" }, +/// _ => { "Behind every successful diet is an unwatched pizza" }, +/// }}; +/// ``` #[cfg(not(bootstrap))] #[unstable(feature = "cfg_match", issue = "115585")] #[rustc_diagnostic_item = "cfg_match"]