diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs index f14b1920722f4..96bece2a368cd 100644 --- a/compiler/rustc_builtin_macros/src/global_allocator.rs +++ b/compiler/rustc_builtin_macros/src/global_allocator.rs @@ -85,7 +85,7 @@ impl AllocFnFactory<'_, '_> { body, define_opaque: None, })); - let item = self.cx.item(self.span, self.attrs(), kind); + let item = self.cx.item(self.span, self.attrs(method), kind); self.cx.stmt_item(self.ty_span, item) } @@ -100,8 +100,18 @@ impl AllocFnFactory<'_, '_> { self.cx.expr_call(self.ty_span, method, args) } - fn attrs(&self) -> AttrVec { - thin_vec![self.cx.attr_word(sym::rustc_std_internal_symbol, self.span)] + fn attrs(&self, method: &AllocatorMethod) -> AttrVec { + let alloc_attr = match method.name { + sym::alloc => sym::rustc_allocator, + sym::dealloc => sym::rustc_deallocator, + sym::realloc => sym::rustc_reallocator, + sym::alloc_zeroed => sym::rustc_allocator_zeroed, + _ => unreachable!("Unknown allocator method!"), + }; + thin_vec![ + self.cx.attr_word(sym::rustc_std_internal_symbol, self.span), + self.cx.attr_word(alloc_attr, self.span) + ] } fn arg_ty(&self, input: &AllocatorMethodInput, args: &mut ThinVec) -> Box { diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 573c51a95398b..dcf6b9454978c 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -407,13 +407,16 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( to_add.extend(sanitize_attrs(cx, codegen_fn_attrs.no_sanitize)); // For non-naked functions, set branch protection attributes on aarch64. - if let Some(BranchProtection { bti, pac_ret }) = + if let Some(BranchProtection { bti, pac_ret, gcs }) = cx.sess().opts.unstable_opts.branch_protection { assert!(cx.sess().target.arch == "aarch64"); if bti { to_add.push(llvm::CreateAttrString(cx.llcx, "branch-target-enforcement")); } + if gcs { + to_add.push(llvm::CreateAttrString(cx.llcx, "guarded-control-stack")); + } if let Some(PacRet { leaf, pc, key }) = pac_ret { if pc { to_add.push(llvm::CreateAttrString(cx.llcx, "branch-protection-pauth-lr")); diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 4a8ea11a3a834..057f525c76f03 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -370,7 +370,8 @@ pub(crate) unsafe fn create_module<'ll>( ); } - if let Some(BranchProtection { bti, pac_ret }) = sess.opts.unstable_opts.branch_protection { + if let Some(BranchProtection { bti, pac_ret, gcs }) = sess.opts.unstable_opts.branch_protection + { if sess.target.arch == "aarch64" { llvm::add_module_flag_u32( llmod, @@ -403,6 +404,12 @@ pub(crate) unsafe fn create_module<'ll>( "sign-return-address-with-bkey", u32::from(pac_opts.key == PAuthKey::B), ); + llvm::add_module_flag_u32( + llmod, + llvm::ModuleFlagMergeBehavior::Min, + "guarded-control-stack", + gcs.into(), + ); } else { bug!( "branch-protection used on non-AArch64 target; \ diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 418dd658121db..785978b4d7111 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -636,6 +636,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { dest, rustc_apfloat::Round::NearestTiesToEven, )?, + sym::fmaf16 => self.fma_intrinsic::(args, dest)?, + sym::fmaf32 => self.fma_intrinsic::(args, dest)?, + sym::fmaf64 => self.fma_intrinsic::(args, dest)?, + sym::fmaf128 => self.fma_intrinsic::(args, dest)?, + sym::fmuladdf16 => self.float_muladd_intrinsic::(args, dest)?, + sym::fmuladdf32 => self.float_muladd_intrinsic::(args, dest)?, + sym::fmuladdf64 => self.float_muladd_intrinsic::(args, dest)?, + sym::fmuladdf128 => self.float_muladd_intrinsic::(args, dest)?, // Unsupported intrinsic: skip the return_to_block below. _ => return interp_ok(false), @@ -1035,4 +1043,42 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.write_scalar(res, dest)?; interp_ok(()) } + + fn fma_intrinsic( + &mut self, + args: &[OpTy<'tcx, M::Provenance>], + dest: &PlaceTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, ()> + where + F: rustc_apfloat::Float + rustc_apfloat::FloatConvert + Into>, + { + let a: F = self.read_scalar(&args[0])?.to_float()?; + let b: F = self.read_scalar(&args[1])?.to_float()?; + let c: F = self.read_scalar(&args[2])?.to_float()?; + + let res = a.mul_add(b, c).value; + let res = self.adjust_nan(res, &[a, b, c]); + self.write_scalar(res, dest)?; + interp_ok(()) + } + + fn float_muladd_intrinsic( + &mut self, + args: &[OpTy<'tcx, M::Provenance>], + dest: &PlaceTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, ()> + where + F: rustc_apfloat::Float + rustc_apfloat::FloatConvert + Into>, + { + let a: F = self.read_scalar(&args[0])?.to_float()?; + let b: F = self.read_scalar(&args[1])?.to_float()?; + let c: F = self.read_scalar(&args[2])?.to_float()?; + + let fuse = M::float_fuse_mul_add(self); + + let res = if fuse { a.mul_add(b, c).value } else { ((a * b).value + c).value }; + let res = self.adjust_nan(res, &[a, b, c]); + self.write_scalar(res, dest)?; + interp_ok(()) + } } diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index e22629993fba7..1725635e0b479 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -289,6 +289,9 @@ pub trait Machine<'tcx>: Sized { a } + /// Determines whether the `fmuladd` intrinsics fuse the multiply-add or use separate operations. + fn float_fuse_mul_add(_ecx: &mut InterpCx<'tcx, Self>) -> bool; + /// Called before a basic block terminator is executed. #[inline] fn before_terminator(_ecx: &mut InterpCx<'tcx, Self>) -> InterpResult<'tcx> { @@ -672,6 +675,11 @@ pub macro compile_time_machine(<$tcx: lifetime>) { match fn_val {} } + #[inline(always)] + fn float_fuse_mul_add(_ecx: &mut InterpCx<$tcx, Self>) -> bool { + true + } + #[inline(always)] fn ub_checks(_ecx: &InterpCx<$tcx, Self>) -> InterpResult<$tcx, bool> { // We can't look at `tcx.sess` here as that can differ across crates, which can lead to diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 6faa67f6a904a..bc3448be5823e 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -90,6 +90,10 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::contract_check_ensures | sym::contract_check_requires | sym::contract_checks + | sym::copysignf16 + | sym::copysignf32 + | sym::copysignf64 + | sym::copysignf128 | sym::cosf16 | sym::cosf32 | sym::cosf64 @@ -106,6 +110,10 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::expf32 | sym::expf64 | sym::expf128 + | sym::fabsf16 + | sym::fabsf32 + | sym::fabsf64 + | sym::fabsf128 | sym::fadd_algebraic | sym::fdiv_algebraic | sym::floorf16 diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 7730bddc0f12d..800f5efee41bf 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -772,7 +772,8 @@ fn test_unstable_options_tracking_hash() { branch_protection, Some(BranchProtection { bti: true, - pac_ret: Some(PacRet { leaf: true, pc: true, key: PAuthKey::B }) + pac_ret: Some(PacRet { leaf: true, pc: true, key: PAuthKey::B }), + gcs: true, }) ); tracked!(codegen_backend, Some("abc".to_string())); diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index c29ab569f4795..f6790f7ed1e96 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -599,14 +599,16 @@ impl Cursor<'_> { if potential_closing.is_none() { // a less fortunate recovery if all else fails which finds any dashes preceded by whitespace // on a standalone line. Might be wrong. + let mut base_index = 0; while let Some(closing) = rest.find("---") { let preceding_chars_start = rest[..closing].rfind("\n").map_or(0, |i| i + 1); if rest[preceding_chars_start..closing].chars().all(is_horizontal_whitespace) { // candidate found - potential_closing = Some(closing); + potential_closing = Some(closing + base_index); break; } else { rest = &rest[closing + 3..]; + base_index += closing + 3; } } } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 4f039381e500d..a4422abc6883a 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1368,7 +1368,6 @@ impl<'tcx> Ty<'tcx> { /// 2229 drop reorder migration analysis. #[inline] pub fn has_significant_drop(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> bool { - assert!(!self.has_non_region_infer()); // Avoid querying in simple cases. match needs_drop_components(tcx, self) { Err(AlwaysRequiresDrop) => true, @@ -1381,6 +1380,16 @@ impl<'tcx> Ty<'tcx> { _ => self, }; + // FIXME + // We should be canonicalizing, or else moving this to a method of inference + // context, or *something* like that, + // but for now just avoid passing inference variables + // to queries that can't cope with them. + // Instead, conservatively return "true" (may change drop order). + if query_ty.has_infer() { + return true; + } + // This doesn't depend on regions, so try to minimize distinct // query keys used. let erased = tcx.normalize_erasing_regions(typing_env, query_ty); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 81ada79dd4384..ebb6a93b1dd18 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1621,6 +1621,7 @@ pub struct PacRet { pub struct BranchProtection { pub bti: bool, pub pac_ret: Option, + pub gcs: bool, } pub(crate) const fn default_lib_output() -> CrateType { diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 3b9d81177861d..b2cc169f12cb7 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -866,7 +866,7 @@ mod desc { pub(crate) const parse_polonius: &str = "either no value or `legacy` (the default), or `next`"; pub(crate) const parse_stack_protector: &str = "one of (`none` (default), `basic`, `strong`, or `all`)"; - pub(crate) const parse_branch_protection: &str = "a `,` separated combination of `bti`, `pac-ret`, followed by a combination of `pc`, `b-key`, or `leaf`"; + pub(crate) const parse_branch_protection: &str = "a `,` separated combination of `bti`, `gcs`, `pac-ret`, (optionally with `pc`, `b-key`, `leaf` if `pac-ret` is set)"; pub(crate) const parse_proc_macro_execution_strategy: &str = "one of supported execution strategies (`same-thread`, or `cross-thread`)"; pub(crate) const parse_remap_path_scope: &str = @@ -1905,6 +1905,7 @@ pub mod parse { Some(pac) => pac.pc = true, _ => return false, }, + "gcs" => slot.gcs = true, _ => return false, }; } diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index d0b53e3a237f6..09d9b160700ca 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -179,9 +179,7 @@ impl fmt::Debug for CStr { impl Default for &CStr { #[inline] fn default() -> Self { - const SLICE: &[c_char] = &[0]; - // SAFETY: `SLICE` is indeed pointing to a valid nul-terminated string. - unsafe { CStr::from_ptr(SLICE.as_ptr()) } + c"" } } diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index a174ced5a2a63..cef700be9ea1f 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -1312,28 +1312,28 @@ pub fn log2f128(x: f128) -> f128; /// [`f16::mul_add`](../../std/primitive.f16.html#method.mul_add) #[rustc_intrinsic] #[rustc_nounwind] -pub fn fmaf16(a: f16, b: f16, c: f16) -> f16; +pub const fn fmaf16(a: f16, b: f16, c: f16) -> f16; /// Returns `a * b + c` for `f32` values. /// /// The stabilized version of this intrinsic is /// [`f32::mul_add`](../../std/primitive.f32.html#method.mul_add) #[rustc_intrinsic] #[rustc_nounwind] -pub fn fmaf32(a: f32, b: f32, c: f32) -> f32; +pub const fn fmaf32(a: f32, b: f32, c: f32) -> f32; /// Returns `a * b + c` for `f64` values. /// /// The stabilized version of this intrinsic is /// [`f64::mul_add`](../../std/primitive.f64.html#method.mul_add) #[rustc_intrinsic] #[rustc_nounwind] -pub fn fmaf64(a: f64, b: f64, c: f64) -> f64; +pub const fn fmaf64(a: f64, b: f64, c: f64) -> f64; /// Returns `a * b + c` for `f128` values. /// /// The stabilized version of this intrinsic is /// [`f128::mul_add`](../../std/primitive.f128.html#method.mul_add) #[rustc_intrinsic] #[rustc_nounwind] -pub fn fmaf128(a: f128, b: f128, c: f128) -> f128; +pub const fn fmaf128(a: f128, b: f128, c: f128) -> f128; /// Returns `a * b + c` for `f16` values, non-deterministically executing /// either a fused multiply-add or two operations with rounding of the @@ -1347,7 +1347,7 @@ pub fn fmaf128(a: f128, b: f128, c: f128) -> f128; /// example. #[rustc_intrinsic] #[rustc_nounwind] -pub fn fmuladdf16(a: f16, b: f16, c: f16) -> f16; +pub const fn fmuladdf16(a: f16, b: f16, c: f16) -> f16; /// Returns `a * b + c` for `f32` values, non-deterministically executing /// either a fused multiply-add or two operations with rounding of the /// intermediate result. @@ -1360,7 +1360,7 @@ pub fn fmuladdf16(a: f16, b: f16, c: f16) -> f16; /// example. #[rustc_intrinsic] #[rustc_nounwind] -pub fn fmuladdf32(a: f32, b: f32, c: f32) -> f32; +pub const fn fmuladdf32(a: f32, b: f32, c: f32) -> f32; /// Returns `a * b + c` for `f64` values, non-deterministically executing /// either a fused multiply-add or two operations with rounding of the /// intermediate result. @@ -1373,7 +1373,7 @@ pub fn fmuladdf32(a: f32, b: f32, c: f32) -> f32; /// example. #[rustc_intrinsic] #[rustc_nounwind] -pub fn fmuladdf64(a: f64, b: f64, c: f64) -> f64; +pub const fn fmuladdf64(a: f64, b: f64, c: f64) -> f64; /// Returns `a * b + c` for `f128` values, non-deterministically executing /// either a fused multiply-add or two operations with rounding of the /// intermediate result. @@ -1386,7 +1386,7 @@ pub fn fmuladdf64(a: f64, b: f64, c: f64) -> f64; /// example. #[rustc_intrinsic] #[rustc_nounwind] -pub fn fmuladdf128(a: f128, b: f128, c: f128) -> f128; +pub const fn fmuladdf128(a: f128, b: f128, c: f128) -> f128; /// Returns the largest integer less than or equal to an `f16`. /// @@ -3170,7 +3170,7 @@ pub const fn maximumf128(x: f128, y: f128) -> f128 { /// [`f16::abs`](../../std/primitive.f16.html#method.abs) #[rustc_nounwind] #[rustc_intrinsic] -pub const unsafe fn fabsf16(x: f16) -> f16; +pub const fn fabsf16(x: f16) -> f16; /// Returns the absolute value of an `f32`. /// @@ -3179,7 +3179,7 @@ pub const unsafe fn fabsf16(x: f16) -> f16; #[rustc_nounwind] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -pub const unsafe fn fabsf32(x: f32) -> f32; +pub const fn fabsf32(x: f32) -> f32; /// Returns the absolute value of an `f64`. /// @@ -3188,7 +3188,7 @@ pub const unsafe fn fabsf32(x: f32) -> f32; #[rustc_nounwind] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -pub const unsafe fn fabsf64(x: f64) -> f64; +pub const fn fabsf64(x: f64) -> f64; /// Returns the absolute value of an `f128`. /// @@ -3196,7 +3196,7 @@ pub const unsafe fn fabsf64(x: f64) -> f64; /// [`f128::abs`](../../std/primitive.f128.html#method.abs) #[rustc_nounwind] #[rustc_intrinsic] -pub const unsafe fn fabsf128(x: f128) -> f128; +pub const fn fabsf128(x: f128) -> f128; /// Copies the sign from `y` to `x` for `f16` values. /// @@ -3204,7 +3204,7 @@ pub const unsafe fn fabsf128(x: f128) -> f128; /// [`f16::copysign`](../../std/primitive.f16.html#method.copysign) #[rustc_nounwind] #[rustc_intrinsic] -pub const unsafe fn copysignf16(x: f16, y: f16) -> f16; +pub const fn copysignf16(x: f16, y: f16) -> f16; /// Copies the sign from `y` to `x` for `f32` values. /// @@ -3213,7 +3213,7 @@ pub const unsafe fn copysignf16(x: f16, y: f16) -> f16; #[rustc_nounwind] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -pub const unsafe fn copysignf32(x: f32, y: f32) -> f32; +pub const fn copysignf32(x: f32, y: f32) -> f32; /// Copies the sign from `y` to `x` for `f64` values. /// /// The stabilized version of this intrinsic is @@ -3221,7 +3221,7 @@ pub const unsafe fn copysignf32(x: f32, y: f32) -> f32; #[rustc_nounwind] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -pub const unsafe fn copysignf64(x: f64, y: f64) -> f64; +pub const fn copysignf64(x: f64, y: f64) -> f64; /// Copies the sign from `y` to `x` for `f128` values. /// @@ -3229,7 +3229,7 @@ pub const unsafe fn copysignf64(x: f64, y: f64) -> f64; /// [`f128::copysign`](../../std/primitive.f128.html#method.copysign) #[rustc_nounwind] #[rustc_intrinsic] -pub const unsafe fn copysignf128(x: f128, y: f128) -> f128; +pub const fn copysignf128(x: f128, y: f128) -> f128; /// Generates the LLVM body for the automatic differentiation of `f` using Enzyme, /// with `df` as the derivative function and `args` as its arguments. diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 6088fb6fa1786..70d787a12cd0f 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -1366,8 +1366,7 @@ impl f128 { #[rustc_const_unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn copysign(self, sign: f128) -> f128 { - // SAFETY: this is actually a safe intrinsic - unsafe { intrinsics::copysignf128(self, sign) } + intrinsics::copysignf128(self, sign) } /// Float addition that allows optimizations based on algebraic rules. @@ -1659,7 +1658,8 @@ impl f128 { #[doc(alias = "fmaf128", alias = "fusedMultiplyAdd")] #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn mul_add(self, a: f128, b: f128) -> f128 { + #[rustc_const_unstable(feature = "const_mul_add", issue = "146724")] + pub const fn mul_add(self, a: f128, b: f128) -> f128 { intrinsics::fmaf128(self, a, b) } diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 3f66c5973d4ac..f834c34ad139b 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -1343,8 +1343,7 @@ impl f16 { #[rustc_const_unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn copysign(self, sign: f16) -> f16 { - // SAFETY: this is actually a safe intrinsic - unsafe { intrinsics::copysignf16(self, sign) } + intrinsics::copysignf16(self, sign) } /// Float addition that allows optimizations based on algebraic rules. @@ -1634,7 +1633,8 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[doc(alias = "fmaf16", alias = "fusedMultiplyAdd")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn mul_add(self, a: f16, b: f16) -> f16 { + #[rustc_const_unstable(feature = "const_mul_add", issue = "146724")] + pub const fn mul_add(self, a: f16, b: f16) -> f16 { intrinsics::fmaf16(self, a, b) } diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index ebce89e5b3da5..e11eb331ddd11 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -1449,8 +1449,7 @@ impl f32 { #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn abs(self) -> f32 { - // SAFETY: this is actually a safe intrinsic - unsafe { intrinsics::fabsf32(self) } + intrinsics::fabsf32(self) } /// Returns a number that represents the sign of `self`. @@ -1508,8 +1507,7 @@ impl f32 { #[stable(feature = "copysign", since = "1.35.0")] #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] pub const fn copysign(self, sign: f32) -> f32 { - // SAFETY: this is actually a safe intrinsic - unsafe { intrinsics::copysignf32(self, sign) } + intrinsics::copysignf32(self, sign) } /// Float addition that allows optimizations based on algebraic rules. @@ -1799,7 +1797,8 @@ pub mod math { #[doc(alias = "fmaf", alias = "fusedMultiplyAdd")] #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "core_float_math", issue = "137578")] - pub fn mul_add(x: f32, y: f32, z: f32) -> f32 { + #[rustc_const_unstable(feature = "const_mul_add", issue = "146724")] + pub const fn mul_add(x: f32, y: f32, z: f32) -> f32 { intrinsics::fmaf32(x, y, z) } diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 91e3949fc3900..8a48fc9097ba7 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -1447,8 +1447,7 @@ impl f64 { #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn abs(self) -> f64 { - // SAFETY: this is actually a safe intrinsic - unsafe { intrinsics::fabsf64(self) } + intrinsics::fabsf64(self) } /// Returns a number that represents the sign of `self`. @@ -1506,8 +1505,7 @@ impl f64 { #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn copysign(self, sign: f64) -> f64 { - // SAFETY: this is actually a safe intrinsic - unsafe { intrinsics::copysignf64(self, sign) } + intrinsics::copysignf64(self, sign) } /// Float addition that allows optimizations based on algebraic rules. @@ -1797,7 +1795,8 @@ pub mod math { #[doc(alias = "fma", alias = "fusedMultiplyAdd")] #[unstable(feature = "core_float_math", issue = "137578")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn mul_add(x: f64, a: f64, b: f64) -> f64 { + #[rustc_const_unstable(feature = "const_mul_add", issue = "146724")] + pub const fn mul_add(x: f64, a: f64, b: f64) -> f64 { intrinsics::fmaf64(x, a, b) } diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs index d31eba863f5fe..62278bf96c3c1 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs @@ -20,24 +20,6 @@ const TOL_PRECISE: f128 = 1e-28; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f128_math)] -fn test_mul_add() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert_biteq!(12.3f128.mul_add(4.5, 6.7), 62.0500000000000000000000000000000037); - assert_biteq!((-12.3f128).mul_add(-4.5, -6.7), 48.6500000000000000000000000000000049); - assert_biteq!(0.0f128.mul_add(8.9, 1.2), 1.2); - assert_biteq!(3.4f128.mul_add(-0.0, 5.6), 5.6); - assert!(nan.mul_add(7.8, 9.0).is_nan()); - assert_biteq!(inf.mul_add(7.8, 9.0), inf); - assert_biteq!(neg_inf.mul_add(7.8, 9.0), neg_inf); - assert_biteq!(8.9f128.mul_add(inf, 3.2), inf); - assert_biteq!((-3.2f128).mul_add(2.4, neg_inf), neg_inf); -} - #[test] #[cfg(any(miri, target_has_reliable_f128_math))] fn test_max_recip() { diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index 302fd0861d75d..7ffafd467a519 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs @@ -22,24 +22,6 @@ const TOL_P4: f16 = 10.0; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f16_math)] -fn test_mul_add() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert_biteq!(12.3f16.mul_add(4.5, 6.7), 62.031); - assert_biteq!((-12.3f16).mul_add(-4.5, -6.7), 48.625); - assert_biteq!(0.0f16.mul_add(8.9, 1.2), 1.2); - assert_biteq!(3.4f16.mul_add(-0.0, 5.6), 5.6); - assert!(nan.mul_add(7.8, 9.0).is_nan()); - assert_biteq!(inf.mul_add(7.8, 9.0), inf); - assert_biteq!(neg_inf.mul_add(7.8, 9.0), neg_inf); - assert_biteq!(8.9f16.mul_add(inf, 3.2), inf); - assert_biteq!((-3.2f16).mul_add(2.4, neg_inf), neg_inf); -} - #[test] #[cfg(any(miri, target_has_reliable_f16_math))] fn test_max_recip() { diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs deleted file mode 100644 index a1fe8b076501d..0000000000000 --- a/library/coretests/tests/floats/f32.rs +++ /dev/null @@ -1,21 +0,0 @@ -use core::f32; - -use super::assert_biteq; - -// FIXME(#140515): mingw has an incorrect fma https://sourceforge.net/p/mingw-w64/bugs/848/ -#[cfg_attr(all(target_os = "windows", target_env = "gnu", not(target_abi = "llvm")), ignore)] -#[test] -fn test_mul_add() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_biteq!(f32::math::mul_add(12.3f32, 4.5, 6.7), 62.05); - assert_biteq!(f32::math::mul_add(-12.3f32, -4.5, -6.7), 48.65); - assert_biteq!(f32::math::mul_add(0.0f32, 8.9, 1.2), 1.2); - assert_biteq!(f32::math::mul_add(3.4f32, -0.0, 5.6), 5.6); - assert!(f32::math::mul_add(nan, 7.8, 9.0).is_nan()); - assert_biteq!(f32::math::mul_add(inf, 7.8, 9.0), inf); - assert_biteq!(f32::math::mul_add(neg_inf, 7.8, 9.0), neg_inf); - assert_biteq!(f32::math::mul_add(8.9f32, inf, 3.2), inf); - assert_biteq!(f32::math::mul_add(-3.2f32, 2.4, neg_inf), neg_inf); -} diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs deleted file mode 100644 index 4c5a3d68d1fd6..0000000000000 --- a/library/coretests/tests/floats/f64.rs +++ /dev/null @@ -1,21 +0,0 @@ -use core::f64; - -use super::assert_biteq; - -// FIXME(#140515): mingw has an incorrect fma https://sourceforge.net/p/mingw-w64/bugs/848/ -#[cfg_attr(all(target_os = "windows", target_env = "gnu", not(target_abi = "llvm")), ignore)] -#[test] -fn test_mul_add() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_biteq!(12.3f64.mul_add(4.5, 6.7), 62.050000000000004); - assert_biteq!((-12.3f64).mul_add(-4.5, -6.7), 48.650000000000006); - assert_biteq!(0.0f64.mul_add(8.9, 1.2), 1.2); - assert_biteq!(3.4f64.mul_add(-0.0, 5.6), 5.6); - assert!(nan.mul_add(7.8, 9.0).is_nan()); - assert_biteq!(inf.mul_add(7.8, 9.0), inf); - assert_biteq!(neg_inf.mul_add(7.8, 9.0), neg_inf); - assert_biteq!(8.9f64.mul_add(inf, 3.2), inf); - assert_biteq!((-3.2f64).mul_add(2.4, neg_inf), neg_inf); -} diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index 31515561c637b..65a7812a75449 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -34,6 +34,10 @@ trait TestableFloat: Sized { const RAW_12_DOT_5: Self; const RAW_1337: Self; const RAW_MINUS_14_DOT_25: Self; + /// The result of 12.3.mul_add(4.5, 6.7) + const MUL_ADD_RESULT: Self; + /// The result of (-12.3).mul_add(-4.5, -6.7) + const NEG_MUL_ADD_RESULT: Self; } impl TestableFloat for f16 { @@ -58,6 +62,8 @@ impl TestableFloat for f16 { const RAW_12_DOT_5: Self = Self::from_bits(0x4a40); const RAW_1337: Self = Self::from_bits(0x6539); const RAW_MINUS_14_DOT_25: Self = Self::from_bits(0xcb20); + const MUL_ADD_RESULT: Self = 62.031; + const NEG_MUL_ADD_RESULT: Self = 48.625; } impl TestableFloat for f32 { @@ -84,6 +90,8 @@ impl TestableFloat for f32 { const RAW_12_DOT_5: Self = Self::from_bits(0x41480000); const RAW_1337: Self = Self::from_bits(0x44a72000); const RAW_MINUS_14_DOT_25: Self = Self::from_bits(0xc1640000); + const MUL_ADD_RESULT: Self = 62.05; + const NEG_MUL_ADD_RESULT: Self = 48.65; } impl TestableFloat for f64 { @@ -106,6 +114,8 @@ impl TestableFloat for f64 { const RAW_12_DOT_5: Self = Self::from_bits(0x4029000000000000); const RAW_1337: Self = Self::from_bits(0x4094e40000000000); const RAW_MINUS_14_DOT_25: Self = Self::from_bits(0xc02c800000000000); + const MUL_ADD_RESULT: Self = 62.050000000000004; + const NEG_MUL_ADD_RESULT: Self = 48.650000000000006; } impl TestableFloat for f128 { @@ -128,6 +138,8 @@ impl TestableFloat for f128 { const RAW_12_DOT_5: Self = Self::from_bits(0x40029000000000000000000000000000); const RAW_1337: Self = Self::from_bits(0x40094e40000000000000000000000000); const RAW_MINUS_14_DOT_25: Self = Self::from_bits(0xc002c800000000000000000000000000); + const MUL_ADD_RESULT: Self = 62.0500000000000000000000000000000037; + const NEG_MUL_ADD_RESULT: Self = 48.6500000000000000000000000000000049; } /// Determine the tolerance for values of the argument type. @@ -359,8 +371,6 @@ macro_rules! float_test { mod f128; mod f16; -mod f32; -mod f64; float_test! { name: num, @@ -1180,15 +1190,12 @@ float_test! { } } -// FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support -// the intrinsics. - float_test! { name: sqrt_domain, attrs: { const: #[cfg(false)], - f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], - f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test { assert!(Float::NAN.sqrt().is_nan()); @@ -1247,8 +1254,8 @@ float_test! { name: total_cmp, attrs: { const: #[cfg(false)], - f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], - f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test { use core::cmp::Ordering; @@ -1356,8 +1363,8 @@ float_test! { name: total_cmp_s_nan, attrs: { const: #[cfg(false)], - f16: #[cfg(false)], - f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], + f16: #[cfg(miri)], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test { use core::cmp::Ordering; @@ -1433,6 +1440,7 @@ float_test! { name: powi, attrs: { const: #[cfg(false)], + // FIXME(f16_f128): `powi` does not work in Miri for these types f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, @@ -1453,8 +1461,8 @@ float_test! { float_test! { name: to_degrees, attrs: { - f16: #[cfg(target_has_reliable_f16)], - f128: #[cfg(target_has_reliable_f128)], + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], }, test { let pi: Float = Float::PI; @@ -1474,8 +1482,8 @@ float_test! { float_test! { name: to_radians, attrs: { - f16: #[cfg(target_has_reliable_f16)], - f128: #[cfg(target_has_reliable_f128)], + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], }, test { let pi: Float = Float::PI; @@ -1495,8 +1503,8 @@ float_test! { float_test! { name: to_algebraic, attrs: { - f16: #[cfg(target_has_reliable_f16)], - f128: #[cfg(target_has_reliable_f128)], + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], }, test { let a: Float = 123.0; @@ -1519,8 +1527,8 @@ float_test! { float_test! { name: to_bits_conv, attrs: { - f16: #[cfg(target_has_reliable_f16)], - f128: #[cfg(target_has_reliable_f128)], + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], }, test { assert_biteq!(flt(1.0), Float::RAW_1); @@ -1542,3 +1550,25 @@ float_test! { assert_biteq!(Float::from_bits(masked_nan2), Float::from_bits(masked_nan2)); } } + +float_test! { + name: mul_add, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let nan: Float = Float::NAN; + let inf: Float = Float::INFINITY; + let neg_inf: Float = Float::NEG_INFINITY; + assert_biteq!(flt(12.3).mul_add(4.5, 6.7), Float::MUL_ADD_RESULT); + assert_biteq!((flt(-12.3)).mul_add(-4.5, -6.7), Float::NEG_MUL_ADD_RESULT); + assert_biteq!(flt(0.0).mul_add(8.9, 1.2), 1.2); + assert_biteq!(flt(3.4).mul_add(-0.0, 5.6), 5.6); + assert!(nan.mul_add(7.8, 9.0).is_nan()); + assert_biteq!(inf.mul_add(7.8, 9.0), inf); + assert_biteq!(neg_inf.mul_add(7.8, 9.0), neg_inf); + assert_biteq!(flt(8.9).mul_add(inf, 3.2), inf); + assert_biteq!((flt(-3.2)).mul_add(2.4, neg_inf), neg_inf); + } +} diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 5c519f3a499d2..a80d7f8b44d7d 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -20,6 +20,7 @@ #![feature(const_convert)] #![feature(const_destruct)] #![feature(const_eval_select)] +#![feature(const_mul_add)] #![feature(const_ops)] #![feature(const_option_ops)] #![feature(const_ref_cell)] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 45abd6bca8a5b..233e41aa34535 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -332,6 +332,7 @@ #![feature(char_internals)] #![feature(clone_to_uninit)] #![feature(const_convert)] +#![feature(const_mul_add)] #![feature(core_intrinsics)] #![feature(core_io_borrowed_buf)] #![feature(drop_guard)] diff --git a/library/std/src/num/f32.rs b/library/std/src/num/f32.rs index ac1d889cc3731..e7810e77e76f0 100644 --- a/library/std/src/num/f32.rs +++ b/library/std/src/num/f32.rs @@ -217,7 +217,8 @@ impl f32 { #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn mul_add(self, a: f32, b: f32) -> f32 { + #[rustc_const_unstable(feature = "const_mul_add", issue = "146724")] + pub const fn mul_add(self, a: f32, b: f32) -> f32 { core::f32::math::mul_add(self, a, b) } diff --git a/library/std/src/num/f64.rs b/library/std/src/num/f64.rs index 55c8593a0c0b1..cbebbfb1be166 100644 --- a/library/std/src/num/f64.rs +++ b/library/std/src/num/f64.rs @@ -217,7 +217,8 @@ impl f64 { #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn mul_add(self, a: f64, b: f64) -> f64 { + #[rustc_const_unstable(feature = "const_mul_add", issue = "146724")] + pub const fn mul_add(self, a: f64, b: f64) -> f64 { core::f64::math::mul_add(self, a, b) } diff --git a/library/std/src/sync/nonpoison/mutex.rs b/library/std/src/sync/nonpoison/mutex.rs index 07430ce3a1393..eeecf5d710767 100644 --- a/library/std/src/sync/nonpoison/mutex.rs +++ b/library/std/src/sync/nonpoison/mutex.rs @@ -373,7 +373,7 @@ impl Mutex { /// or written through after the mutex is dropped. #[unstable(feature = "mutex_data_ptr", issue = "140368")] // #[unstable(feature = "nonpoison_mutex", issue = "134645")] - pub fn data_ptr(&self) -> *mut T { + pub const fn data_ptr(&self) -> *mut T { self.data.get() } } diff --git a/library/std/src/sync/nonpoison/rwlock.rs b/library/std/src/sync/nonpoison/rwlock.rs index eb0aef99cc1e7..b2f26edc083e9 100644 --- a/library/std/src/sync/nonpoison/rwlock.rs +++ b/library/std/src/sync/nonpoison/rwlock.rs @@ -495,7 +495,7 @@ impl RwLock { /// or written through after the lock is dropped. #[unstable(feature = "rwlock_data_ptr", issue = "140368")] // #[unstable(feature = "nonpoison_rwlock", issue = "134645")] - pub fn data_ptr(&self) -> *mut T { + pub const fn data_ptr(&self) -> *mut T { self.data.get() } } diff --git a/library/std/src/sync/poison/mutex.rs b/library/std/src/sync/poison/mutex.rs index 7e9d920d92f85..6fdb4f6799ee5 100644 --- a/library/std/src/sync/poison/mutex.rs +++ b/library/std/src/sync/poison/mutex.rs @@ -668,7 +668,7 @@ impl Mutex { /// are properly synchronized to avoid data races, and that it is not read /// or written through after the mutex is dropped. #[unstable(feature = "mutex_data_ptr", issue = "140368")] - pub fn data_ptr(&self) -> *mut T { + pub const fn data_ptr(&self) -> *mut T { self.data.get() } } diff --git a/library/std/src/sync/poison/rwlock.rs b/library/std/src/sync/poison/rwlock.rs index 0a463f3f9c7e3..e3a72c73bf4ed 100644 --- a/library/std/src/sync/poison/rwlock.rs +++ b/library/std/src/sync/poison/rwlock.rs @@ -667,7 +667,7 @@ impl RwLock { /// are properly synchronized to avoid data races, and that it is not read /// or written through after the lock is dropped. #[unstable(feature = "rwlock_data_ptr", issue = "140368")] - pub fn data_ptr(&self) -> *mut T { + pub const fn data_ptr(&self) -> *mut T { self.data.get() } } diff --git a/library/std/src/sync/reentrant_lock.rs b/library/std/src/sync/reentrant_lock.rs index 4140718560c65..f560b616dd922 100644 --- a/library/std/src/sync/reentrant_lock.rs +++ b/library/std/src/sync/reentrant_lock.rs @@ -355,7 +355,7 @@ impl ReentrantLock { /// properly synchronized to avoid data races, and that it is not read /// through after the lock is dropped. #[unstable(feature = "reentrant_lock_data_ptr", issue = "140368")] - pub fn data_ptr(&self) -> *const T { + pub const fn data_ptr(&self) -> *const T { &raw const self.data } diff --git a/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile b/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile index 71de8f917fa2c..04b46226acfa4 100644 --- a/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile +++ b/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ubuntu:25.10 ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y --no-install-recommends \ diff --git a/src/ci/docker/host-aarch64/aarch64-gnu-llvm-20/Dockerfile b/src/ci/docker/host-aarch64/aarch64-gnu-llvm-20/Dockerfile index adbb1f03378a6..095624d6fb714 100644 --- a/src/ci/docker/host-aarch64/aarch64-gnu-llvm-20/Dockerfile +++ b/src/ci/docker/host-aarch64/aarch64-gnu-llvm-20/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:25.04 +FROM ubuntu:25.10 ARG DEBIAN_FRONTEND=noninteractive diff --git a/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile b/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile index e6133fce83e28..4b61fd94a6cfa 100644 --- a/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile +++ b/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ubuntu:25.10 ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y --no-install-recommends \ diff --git a/src/doc/book b/src/doc/book index 3e9dc46aa563c..33f1af40cc44d 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 3e9dc46aa563ca0c53ec826c41b05f10c5915925 +Subproject commit 33f1af40cc44dde7e3e892f7a508e6f427d2cbc6 diff --git a/src/doc/reference b/src/doc/reference index b3ce60628c6f5..cc7247d8dfaef 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit b3ce60628c6f55ab8ff3dba9f3d20203df1c0dee +Subproject commit cc7247d8dfaef4c39000bb12c55c32ba5b5ba976 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index dd26bc8e726dc..2c9b490d70e53 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit dd26bc8e726dc2e73534c8972d4dccd1bed7495f +Subproject commit 2c9b490d70e535cf166bf17feba59e594579843f diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index df2bac877b66f..0dc9ce843e9c9 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -2f3f27bf79ec147fec9d2e7980605307a74067f4 +9f32ccf35fb877270bc44a86a126440f04d676d0 diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md index a1612738537d7..249140956c09a 100644 --- a/src/doc/rustc-dev-guide/src/SUMMARY.md +++ b/src/doc/rustc-dev-guide/src/SUMMARY.md @@ -108,6 +108,7 @@ - [Installation](./autodiff/installation.md) - [How to debug](./autodiff/debugging.md) - [Autodiff flags](./autodiff/flags.md) + - [Type Trees](./autodiff/type-trees.md) # Source Code Representation diff --git a/src/doc/rustc-dev-guide/src/about-this-guide.md b/src/doc/rustc-dev-guide/src/about-this-guide.md index f1a406a1c29be..4f5733ae0821a 100644 --- a/src/doc/rustc-dev-guide/src/about-this-guide.md +++ b/src/doc/rustc-dev-guide/src/about-this-guide.md @@ -48,9 +48,9 @@ In addition, many of the ideas discussed throughout this guide are idealized des that are not fully realized yet. All this makes keeping this guide completely up to date on everything very hard! -The Guide itself is of course open-source as well, -and the sources can be found at the [GitHub repository]. -If you find any mistakes in the guide, please file an issue about it. +The guide itself is of course open source as well, +and the sources are hosted on [a GitHub repository]. +If you find any mistakes in the guide, please file an issue. Even better, open a PR with a correction! If you do contribute to the guide, @@ -105,7 +105,7 @@ You might also find the following sites useful: [cheatsheet]: https://bors.rust-lang.org/ [Miri]: https://github.com/rust-lang/miri [@bors]: https://github.com/bors -[GitHub repository]: https://github.com/rust-lang/rustc-dev-guide/ +[a GitHub repository]: https://github.com/rust-lang/rustc-dev-guide/ [rustc API docs]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle [Forge]: https://forge.rust-lang.org/ [compiler-team]: https://github.com/rust-lang/compiler-team/ diff --git a/src/doc/rustc-dev-guide/src/appendix/glossary.md b/src/doc/rustc-dev-guide/src/appendix/glossary.md index 1837b59e850ae..21162f8ee7d08 100644 --- a/src/doc/rustc-dev-guide/src/appendix/glossary.md +++ b/src/doc/rustc-dev-guide/src/appendix/glossary.md @@ -68,6 +68,7 @@ Term | Meaning rib | A data structure in the name resolver that keeps track of a single scope for names. ([see more](../name-resolution.md)) RPIT | A return-position `impl Trait`. ([see the reference](https://doc.rust-lang.org/reference/types/impl-trait.html#abstract-return-types)). RPITIT | A return-position `impl Trait` in trait. Unlike RPIT, this is desugared to a generic associated type (GAT). Introduced in [RFC 3425](https://rust-lang.github.io/rfcs/3425-return-position-impl-trait-in-traits.html). ([see more](../return-position-impl-trait-in-trait.md)) +rustbuild | A deprecated term for the part of bootstrap that is written in Rust scrutinee | A scrutinee is the expression that is matched on in `match` expressions and similar pattern matching constructs. For example, in `match x { A => 1, B => 2 }`, the expression `x` is the scrutinee. `sess` | The compiler _session_, which stores global data used throughout compilation side tables | Because the [AST](#ast) and HIR are immutable once created, we often carry extra information about them in the form of hashtables, indexed by the id of a particular node. diff --git a/src/doc/rustc-dev-guide/src/autodiff/type-trees.md b/src/doc/rustc-dev-guide/src/autodiff/type-trees.md new file mode 100644 index 0000000000000..68cb78650b009 --- /dev/null +++ b/src/doc/rustc-dev-guide/src/autodiff/type-trees.md @@ -0,0 +1,193 @@ +# TypeTrees for Autodiff + +## What are TypeTrees? +Memory layout descriptors for Enzyme. Tell Enzyme exactly how types are structured in memory so it can compute derivatives efficiently. + +## Structure +```rust +TypeTree(Vec) + +Type { + offset: isize, // byte offset (-1 = everywhere) + size: usize, // size in bytes + kind: Kind, // Float, Integer, Pointer, etc. + child: TypeTree // nested structure +} +``` + +## Example: `fn compute(x: &f32, data: &[f32]) -> f32` + +**Input 0: `x: &f32`** +```rust +TypeTree(vec![Type { + offset: -1, size: 8, kind: Pointer, + child: TypeTree(vec![Type { + offset: 0, size: 4, kind: Float, // Single value: use offset 0 + child: TypeTree::new() + }]) +}]) +``` + +**Input 1: `data: &[f32]`** +```rust +TypeTree(vec![Type { + offset: -1, size: 8, kind: Pointer, + child: TypeTree(vec![Type { + offset: -1, size: 4, kind: Float, // -1 = all elements + child: TypeTree::new() + }]) +}]) +``` + +**Output: `f32`** +```rust +TypeTree(vec![Type { + offset: 0, size: 4, kind: Float, // Single scalar: use offset 0 + child: TypeTree::new() +}]) +``` + +## Why Needed? +- Enzyme can't deduce complex type layouts from LLVM IR +- Prevents slow memory pattern analysis +- Enables correct derivative computation for nested structures +- Tells Enzyme which bytes are differentiable vs metadata + +## What Enzyme Does With This Information: + +Without TypeTrees: +```llvm +; Enzyme sees generic LLVM IR: +define float @distance(ptr %p1, ptr %p2) { +; Has to guess what these pointers point to +; Slow analysis of all memory operations +; May miss optimization opportunities +} +``` + +With TypeTrees: +```llvm +define "enzyme_type"="{[-1]:Float@float}" float @distance( + ptr "enzyme_type"="{[-1]:Pointer, [-1,0]:Float@float}" %p1, + ptr "enzyme_type"="{[-1]:Pointer, [-1,0]:Float@float}" %p2 +) { +; Enzyme knows exact type layout +; Can generate efficient derivative code directly +} +``` + +# TypeTrees - Offset and -1 Explained + +## Type Structure + +```rust +Type { + offset: isize, // WHERE this type starts + size: usize, // HOW BIG this type is + kind: Kind, // WHAT KIND of data (Float, Int, Pointer) + child: TypeTree // WHAT'S INSIDE (for pointers/containers) +} +``` + +## Offset Values + +### Regular Offset (0, 4, 8, etc.) +**Specific byte position within a structure** + +```rust +struct Point { + x: f32, // offset 0, size 4 + y: f32, // offset 4, size 4 + id: i32, // offset 8, size 4 +} +``` + +TypeTree for `&Point` (internal representation): +```rust +TypeTree(vec![ + Type { offset: 0, size: 4, kind: Float }, // x at byte 0 + Type { offset: 4, size: 4, kind: Float }, // y at byte 4 + Type { offset: 8, size: 4, kind: Integer } // id at byte 8 +]) +``` + +Generates LLVM +```llvm +"enzyme_type"="{[-1]:Pointer, [-1,0]:Float@float, [-1,4]:Float@float, [-1,8]:Integer, [-1,9]:Integer, [-1,10]:Integer, [-1,11]:Integer}" +``` + +### Offset -1 (Special: "Everywhere") +**Means "this pattern repeats for ALL elements"** + +#### Example 1: Direct Array `[f32; 100]` (no pointer indirection) +```rust +TypeTree(vec![Type { + offset: -1, // ALL positions + size: 4, // each f32 is 4 bytes + kind: Float, // every element is float +}]) +``` + +Generates LLVM: `"enzyme_type"="{[-1]:Float@float}"` + +#### Example 1b: Array Reference `&[f32; 100]` (with pointer indirection) +```rust +TypeTree(vec![Type { + offset: -1, size: 8, kind: Pointer, + child: TypeTree(vec![Type { + offset: -1, // ALL array elements + size: 4, // each f32 is 4 bytes + kind: Float, // every element is float + }]) +}]) +``` + +Generates LLVM: `"enzyme_type"="{[-1]:Pointer, [-1,-1]:Float@float}"` + +Instead of listing 100 separate Types with offsets `0,4,8,12...396` + +#### Example 2: Slice `&[i32]` +```rust +// Pointer to slice data +TypeTree(vec![Type { + offset: -1, size: 8, kind: Pointer, + child: TypeTree(vec![Type { + offset: -1, // ALL slice elements + size: 4, // each i32 is 4 bytes + kind: Integer + }]) +}]) +``` + +Generates LLVM: `"enzyme_type"="{[-1]:Pointer, [-1,-1]:Integer}"` + +#### Example 3: Mixed Structure +```rust +struct Container { + header: i64, // offset 0 + data: [f32; 1000], // offset 8, but elements use -1 +} +``` + +```rust +TypeTree(vec![ + Type { offset: 0, size: 8, kind: Integer }, // header + Type { offset: 8, size: 4000, kind: Pointer, + child: TypeTree(vec![Type { + offset: -1, size: 4, kind: Float // ALL array elements + }]) + } +]) +``` + +## Key Distinction: Single Values vs Arrays + +**Single Values** use offset `0` for precision: +- `&f32` has exactly one f32 value at offset 0 +- More precise than using -1 ("everywhere") +- Generates: `{[-1]:Pointer, [-1,0]:Float@float}` + +**Arrays** use offset `-1` for efficiency: +- `&[f32; 100]` has the same pattern repeated 100 times +- Using -1 avoids listing 100 separate offsets +- Generates: `{[-1]:Pointer, [-1,-1]:Float@float}` \ No newline at end of file diff --git a/src/doc/rustc-dev-guide/src/building/bootstrapping/writing-tools-in-bootstrap.md b/src/doc/rustc-dev-guide/src/building/bootstrapping/writing-tools-in-bootstrap.md index c3660e24b1526..8ac2e6bfe287c 100644 --- a/src/doc/rustc-dev-guide/src/building/bootstrapping/writing-tools-in-bootstrap.md +++ b/src/doc/rustc-dev-guide/src/building/bootstrapping/writing-tools-in-bootstrap.md @@ -3,18 +3,32 @@ There are three types of tools you can write in bootstrap: - **`Mode::ToolBootstrap`** + Use this for tools that don’t need anything from the in-tree compiler and can run with the stage0 `rustc`. - The output is placed in the "bootstrap-tools" directory. This mode is for general-purpose tools built - entirely with the stage0 compiler, including target libraries and only works for stage 0. + The output is placed in the "bootstrap-tools" directory. + This mode is for general-purpose tools built entirely with the stage0 compiler, + including target libraries, and it only works for stage 0. - **`Mode::ToolStd`** - Use this for tools that rely on the locally built std. The output goes into the "stageN-tools" directory. + + Use this for tools that rely on the locally built std. + The output goes into the "stageN-tools" directory. This mode is rarely used, mainly for `compiletest` which requires `libtest`. - **`Mode::ToolRustcPrivate`** - Use this for tools that use the `rustc_private` mechanism, and thus depend on the locally built `rustc` and its rlib artifacts. This is more complex than the other modes because the tool must be built with the same compiler used for `rustc` and placed in the "stageN-tools" directory. When you choose `Mode::ToolRustcPrivate`, `ToolBuild` implementation takes care of this automatically. If you need to use the builder’s compiler for something specific, you can get it from `ToolBuildResult`, which is - returned by the tool's [`Step`]. -Regardless of the tool type you must return `ToolBuildResult` from the tool’s [`Step`] implementation and use `ToolBuild` inside it. + Use this for tools that use the `rustc_private` mechanism, + and thus depend on the locally built `rustc` and its rlib artifacts. + This is more complex than the other modes, + because the tool must be built with the same compiler used for `rustc`, + and placed in the "stageN-tools" directory. + When you choose `Mode::ToolRustcPrivate`, + `ToolBuild` implementation takes care of this automatically. + If you need to use the builder’s compiler for something specific, + you can get it from `ToolBuildResult`, which is returned by the tool's [`Step`]. + +Regardless of the tool type, +you must return `ToolBuildResult` from the tool’s [`Step`] implementation, +and use `ToolBuild` inside it. [`Step`]: https://doc.rust-lang.org/nightly/nightly-rustc/bootstrap/core/builder/trait.Step.html diff --git a/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md b/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md index b07d3533f59bc..36610f28854b5 100644 --- a/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md +++ b/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md @@ -149,7 +149,7 @@ On Windows, the Powershell commands may give you an error that looks like this: ``` PS C:\Users\vboxuser\rust> ./x ./x : File C:\Users\vboxuser\rust\x.ps1 cannot be loaded because running scripts is disabled on this system. For more -information, see about_Execution_Policies at https:/go.microsoft.com/fwlink/?LinkID=135170. +information, see about_Execution_Policies at https://go.microsoft.com/fwlink/?LinkID=135170. At line:1 char:1 + ./x + ~~~ diff --git a/src/doc/rustc-dev-guide/src/compiler-team.md b/src/doc/rustc-dev-guide/src/compiler-team.md index 6be52833f3964..896d9e6f6d94c 100644 --- a/src/doc/rustc-dev-guide/src/compiler-team.md +++ b/src/doc/rustc-dev-guide/src/compiler-team.md @@ -1,10 +1,14 @@ # About the compiler team +> NOTE: +> There exists much detail about the team [on Forge], making most of the following obsolete. + rustc is maintained by the [Rust compiler team][team]. The people who belong to this team collectively work to track regressions and implement new features. Members of the Rust compiler team are people who have made significant contributions to rustc and its design. +[on Forge]: https://forge.rust-lang.org/compiler [team]: https://www.rust-lang.org/governance/teams/compiler ## Discussion diff --git a/src/doc/rustc-dev-guide/src/fuzzing.md b/src/doc/rustc-dev-guide/src/fuzzing.md index 3000537861778..cc98b49a97c68 100644 --- a/src/doc/rustc-dev-guide/src/fuzzing.md +++ b/src/doc/rustc-dev-guide/src/fuzzing.md @@ -90,14 +90,15 @@ Here are a few things you can do to help the Rust project after filing an ICE. triggering the ICE, such as syntax errors or borrow-checking errors - Minimize the test case (see below). If successful, you can label the issue with `S-has-mcve`. Otherwise, you can apply `E-needs-mcve`. -- Add the minimal test case to the rust-lang/rust repo as a [crashes test]. +- Add the minimal test case to the rust-lang/rust repo as a [crash test]. While you're at it, consider including other "untracked" crashes in your PR. - Please don't forget to mark your issue with `S-bug-has-test` afterwards. + Please don't forget to mark all relevant issues with `S-bug-has-test` once + your PR is merged. See also [applying and removing labels][labeling]. [bisect]: https://rust-lang.github.io/cargo-bisect-rustc/ -[crashes test]: tests/compiletest.html#crashes-tests +[crash test]: tests/compiletest.html#crash-tests [labeling]: https://forge.rust-lang.org/release/issue-triaging.html#applying-and-removing-labels ## Minimization diff --git a/src/doc/rustc-dev-guide/src/profiling/with_perf.md b/src/doc/rustc-dev-guide/src/profiling/with_perf.md index 0d4f23bcd9ad3..e452dde5226d4 100644 --- a/src/doc/rustc-dev-guide/src/profiling/with_perf.md +++ b/src/doc/rustc-dev-guide/src/profiling/with_perf.md @@ -4,8 +4,7 @@ This is a guide for how to profile rustc with [perf](https://perf.wiki.kernel.or ## Initial steps -- Get a clean checkout of rust-lang/master, or whatever it is you want - to profile. +- Get a clean checkout of rust-lang/rust - Set the following settings in your `bootstrap.toml`: - `rust.debuginfo-level = 1` - enables line debuginfo - `rust.jemalloc = false` - lets you do memory use profiling with valgrind diff --git a/src/doc/rustc-dev-guide/src/tests/best-practices.md b/src/doc/rustc-dev-guide/src/tests/best-practices.md index efc626035b79d..10372c36ac99e 100644 --- a/src/doc/rustc-dev-guide/src/tests/best-practices.md +++ b/src/doc/rustc-dev-guide/src/tests/best-practices.md @@ -71,7 +71,7 @@ related tests. > //! Regression test for . > ``` > -> One exception to this rule is [crashes tests]: there it is canonical that +> One exception to this rule is [crash tests]: there it is canonical that > tests are named only after issue numbers because its purpose is to track > snippets from which issues no longer ICE/crash, and they would either be > removed or converted into proper ui/other tests in the fix PRs. @@ -199,4 +199,4 @@ See [LLVM FileCheck guide][FileCheck] for details. [compiletest directives]: ./directives.md [`run-make`]: ./compiletest.md#run-make-tests [FileCheck]: https://llvm.org/docs/CommandGuide/FileCheck.html -[crashes tests]: ./compiletest.md#crashes-tests +[crash tests]: ./compiletest.md#crash-tests diff --git a/src/doc/rustc-dev-guide/src/tests/ci.md b/src/doc/rustc-dev-guide/src/tests/ci.md index a8cc959124ff6..6c0b5c2e84554 100644 --- a/src/doc/rustc-dev-guide/src/tests/ci.md +++ b/src/doc/rustc-dev-guide/src/tests/ci.md @@ -1,18 +1,18 @@ # Testing with CI The primary goal of our CI system is to ensure that the `master` branch of -`rust-lang/rust` is always in a valid state and passes our test suite. +`rust-lang/rust` is always in a valid state by passing our test suite. From a high-level point of view, when you open a pull request at `rust-lang/rust`, the following will happen: - A small [subset](#pull-request-builds) of tests and checks are run after each - push to the PR. This should help catching common errors. + push to the PR. This should help catch common errors. - When the PR is approved, the [bors] bot enqueues the PR into a [merge queue]. - Once the PR gets to the front of the queue, bors will create a merge commit and run the [full test suite](#auto-builds) on it. The merge commit either contains only one specific PR or it can be a ["rollup"](#rollups) which - combines multiple PRs together, to save CI costs. + combines multiple PRs together, to reduce CI costs and merge delays. - Once the whole test suite finishes, two things can happen. Either CI fails with an error that needs to be addressed by the developer, or CI succeeds and the merge commit is then pushed to the `master` branch. @@ -38,12 +38,12 @@ input, which contains a declarative configuration of all our CI jobs. > orchestrating the scripts that drive the process. In essence, all CI jobs run `./x test`, `./x dist` or some other command with -different configurations, across various operating systems, targets and +different configurations, across various operating systems, targets, and platforms. There are two broad categories of jobs that are executed, `dist` and non-`dist` jobs. - Dist jobs build a full release of the compiler for a specific platform, - including all the tools we ship through rustup; Those builds are then uploaded + including all the tools we ship through rustup. Those builds are then uploaded to the `rust-lang-ci2` S3 bucket and are available to be locally installed with the [rustup-toolchain-install-master] tool. The same builds are also used for actual releases: our release process basically consists of copying those @@ -70,7 +70,7 @@ these execute the `x86_64-gnu-llvm-X`, `x86_64-gnu-tools`, `pr-check-1`, `pr-che and `tidy` jobs, all running on Linux. These execute a relatively short (~40 minutes) and lightweight test suite that should catch common issues. More specifically, they run a set of lints, they try to perform a cross-compile check -build to Windows mingw (without producing any artifacts) and they test the +build to Windows mingw (without producing any artifacts), and they test the compiler using a *system* version of LLVM. Unfortunately, it would take too many resources to run the full test suite for each commit on every PR. @@ -95,17 +95,16 @@ jobs that exercise various tests across operating systems and targets. The full test suite is quite slow; it can take several hours until all the `auto` CI jobs finish. -Most platforms only run the build steps, some run a restricted set of tests, +Most platforms only run the build steps, some run a restricted set of tests; only a subset run the full suite of tests (see Rust's [platform tiers]). Auto jobs are defined in the `auto` section of [`jobs.yml`]. They are executed -on the `auto` branch under the `rust-lang/rust` repository and -their results can be seen [here](https://github.com/rust-lang/rust/actions), -although usually you will be notified of the result by a comment made by bors on -the corresponding PR. +on the `auto` branch under the `rust-lang/rust` repository, +and the final result will be reported via a comment made by bors on the corresponding PR. +The live results can be seen on [the GitHub Actions workflows page]. At any given time, at most a single `auto` build is being executed. Find out -more [here](#merging-prs-serially-with-bors). +more in [Merging PRs serially with bors](#merging-prs-serially-with-bors). [platform tiers]: https://forge.rust-lang.org/release/platform-support.html#rust-platform-support @@ -125,7 +124,7 @@ There are several use-cases for try builds: when you start a try build). To create a try build and schedule it for a performance benchmark, you can use the `@bors try @rust-timer queue` command combination. -- Check the impact of the PR across the Rust ecosystem, using a [crater] run. +- Check the impact of the PR across the Rust ecosystem, using a [Crater](crater.md) run. Again, a working compiler build is needed for this, which can be produced by the [dist-x86_64-linux] CI job. - Run a specific CI job (e.g. Windows tests) on a PR, to quickly test if it @@ -134,11 +133,11 @@ There are several use-cases for try builds: By default, if you send a comment with `@bors try`, the jobs defined in the `try` section of [`jobs.yml`] will be executed. We call this mode a "fast try build". Such a try build will not execute any tests, and it will allow compilation warnings. It is useful when you want to -get an optimized toolchain as fast as possible, for a crater run or performance benchmarks, +get an optimized toolchain as fast as possible, for a Crater run or performance benchmarks, even if it might not be working fully correctly. If you want to do a full build for the default try job, specify its job name in a job pattern (explained below). -If you want to run custom CI job(s) in a try build and make sure that they pass all tests and do +If you want to run custom CI jobs in a try build and make sure that they pass all tests and do not produce any compilation warnings, you can select CI jobs to be executed by specifying a *job pattern*, which can be used in one of two ways: - You can add a set of `try-job: ` directives to the PR description (described below) and then @@ -151,8 +150,9 @@ which can be used in one of two ways: Each job pattern can either be an exact name of a job or a glob pattern that matches multiple jobs, for example `*msvc*` or `*-alt`. You can start at most 20 jobs in a single try build. When using -glob patterns, you might want to wrap them in backticks (`` ` ``) to avoid GitHub rendering -the pattern as Markdown. +glob patterns in the PR description, you can optionally wrap them in backticks (`` ` ``) to avoid GitHub rendering +the pattern as Markdown if it contains e.g. an asterisk. Note that this escaping will not work when using +the `@bors jobs=` parameter. The job pattern needs to match one or more jobs defined in the `auto` or `optional` sections of [`jobs.yml`]: @@ -189,18 +189,17 @@ of [`jobs.yml`]: > that are exercised this way. Try builds are executed on the `try` branch under the `rust-lang/rust` repository and -their results can be seen [here](https://github.com/rust-lang/rust/actions), +their results can be seen on [the GitHub Actions workflows page], although usually you will be notified of the result by a comment made by bors on the corresponding PR. Multiple try builds can execute concurrently across different PRs, but there can be at most a single try build running on a single PR at any given time. -Note that try builds are handled using the new [bors][new-bors] implementation. +Note that try builds are handled using the [new bors] implementation. [rustc-perf]: https://github.com/rust-lang/rustc-perf -[crater]: https://github.com/rust-lang/crater -[new-bors]: https://github.com/rust-lang/bors +[new bors]: https://github.com/rust-lang/bors ### Modifying CI jobs @@ -210,8 +209,7 @@ If you want to modify what gets executed on our CI, you can simply modify the You can also modify what gets executed temporarily, for example to test a particular platform or configuration that is challenging to test locally (for example, if a Windows build fails, but you don't have access to a Windows -machine). Don't hesitate to use CI resources in such situations to try out a -fix! +machine). Don't hesitate to use CI resources in such situations. You can perform an arbitrary CI job in two ways: - Use the [try build](#try-builds) functionality, and specify the CI jobs that @@ -254,8 +252,8 @@ purposes. Although you are welcome to use CI, just be conscious that this is a shared -resource with limited concurrency. Try not to enable too many jobs at once (one -or two should be sufficient in most cases). +resource with limited concurrency. Try not to enable too many jobs at once; +one or two should be sufficient in most cases. ## Merging PRs serially with bors @@ -279,12 +277,12 @@ by listening for either Commit Statuses or Check Runs. Since the merge commit is based on the latest `master` and only one can be tested at the same time, when the results are green, `master` is fast-forwarded to that merge commit. -Unfortunately testing a single PR at the time, combined with our long CI (~2 -hours for a full run), means we can’t merge too many PRs in a single day, and a -single failure greatly impacts our throughput for the day. The maximum number of +Unfortunately, testing a single PR at a time, combined with our long CI (~2 +hours for a full run), means we can’t merge a lot of PRs in a single day, and a +single failure greatly impacts our throughput. The maximum number of PRs we can merge in a day is around ~10. -The large CI run times and requirement for a large builder pool is largely due +The long CI run times, and requirement for a large builder pool, is largely due to the fact that full release artifacts are built in the `dist-` builders. This is worth it because these release artifacts: @@ -297,12 +295,11 @@ is worth it because these release artifacts: Some PRs don’t need the full test suite to be executed: trivial changes like typo fixes or README improvements *shouldn’t* break the build, and testing every -single one of them for 2+ hours is a big waste of time. To solve this, we +single one of them for 2+ hours would be wasteful. To solve this, we regularly create a "rollup", a PR where we merge several pending trivial PRs so they can be tested together. Rollups are created manually by a team member using the "create a rollup" button on the [merge queue]. The team member uses their -judgment to decide if a PR is risky or not, and are the best tool we have at the -moment to keep the queue in a manageable state. +judgment to decide if a PR is risky or not. ## Docker @@ -315,18 +312,22 @@ platform’s custom [Docker container]. This has a lot of advantages for us: - We can use ancient build environments to ensure maximum binary compatibility, for example [using older CentOS releases][dist-x86_64-linux] on our Linux builders. -- We can avoid reinstalling tools (like QEMU or the Android emulator) every time +- We can avoid reinstalling tools (like QEMU or the Android emulator) every time, thanks to Docker image caching. -- Users can run the same tests in the same environment locally by just running - `cargo run --manifest-path src/ci/citool/Cargo.toml run-local `, which is awesome to debug failures. Note that there are only linux docker images available locally due to licensing and +- Users can run the same tests in the same environment locally by just running this command: + + cargo run --manifest-path src/ci/citool/Cargo.toml run-local + + This is helpful for debugging failures. + Note that there are only Linux Docker images available locally due to licensing and other restrictions. -The docker images prefixed with `dist-` are used for building artifacts while +The Docker images prefixed with `dist-` are used for building artifacts while those without that prefix run tests and checks. We also run tests for less common architectures (mainly Tier 2 and Tier 3 -platforms) in CI. Since those platforms are not x86 we either run everything -inside QEMU or just cross-compile if we don’t want to run the tests for that +platforms) in CI. Since those platforms are not x86, we either run everything +inside QEMU, or we just cross-compile if we don’t want to run the tests for that platform. These builders are running on a special pool of builders set up and maintained @@ -363,41 +364,41 @@ invalidated if one of the following changes: [ghcr.io]: https://github.com/rust-lang/rust/pkgs/container/rust-ci [Docker registry caching]: https://docs.docker.com/build/cache/backends/registry/ -### LLVM caching with sccache +### LLVM caching with Sccache -We build some C/C++ stuff in various CI jobs, and we rely on [sccache] to cache +We build some C/C++ stuff in various CI jobs, and we rely on [Sccache] to cache the intermediate LLVM artifacts. Sccache is a distributed ccache developed by Mozilla, which can use an object storage bucket as the storage backend. -With sccache there's no need to calculate the hash key ourselves. Sccache +With Sccache there's no need to calculate the hash key ourselves. Sccache invalidates the cache automatically when it detects changes to relevant inputs, such as the source code, the version of the compiler, and important environment variables. -So we just pass the sccache wrapper on top of cargo and sccache does the rest. +So we just pass the Sccache wrapper on top of Cargo and Sccache does the rest. -We store the persistent artifacts on the S3 bucket `rust-lang-ci-sccache2`. So -when the CI runs, if sccache sees that LLVM is being compiled with the same C/C++ -compiler and the LLVM source code is the same, sccache retrieves the individual +We store the persistent artifacts on the S3 bucket, `rust-lang-ci-sccache2`. So +when the CI runs, if Sccache sees that LLVM is being compiled with the same C/C++ +compiler and the LLVM source code is the same, Sccache retrieves the individual compiled translation units from S3. [sccache]: https://github.com/mozilla/sccache ## Custom tooling around CI -During the years we developed some custom tooling to improve our CI experience. +During the years, we developed some custom tooling to improve our CI experience. ### Rust Log Analyzer to show the error message in PRs The build logs for `rust-lang/rust` are huge, and it’s not practical to find -what caused the build to fail by looking at the logs. To improve the developers’ -experience we developed a bot called [Rust Log Analyzer][rla] (RLA) that -receives the build logs on failure and extracts the error message automatically, -posting it on the PR. +what caused the build to fail by looking at the logs. +We therefore developed a bot called [Rust Log Analyzer][rla] (RLA) that +receives the build logs on failure, and extracts the error message automatically, +posting it on the PR thread. The bot is not hardcoded to look for error strings, but was trained with a bunch of build failures to recognize which lines are common between builds and which are not. While the generated snippets can be weird sometimes, the bot is pretty -good at identifying the relevant lines even if it’s an error we've never seen +good at identifying the relevant lines, even if it’s an error we've never seen before. [rla]: https://github.com/rust-lang/rust-log-analyzer @@ -429,11 +430,11 @@ More information is available in the [toolstate documentation]. ## Public CI dashboard -To monitor the Rust CI, you can have a look at the [public dashboard] maintained by the infra-team. +To monitor the Rust CI, you can have a look at the [public dashboard] maintained by the infra team. These are some useful panels from the dashboard: -- Pipeline duration: check how long the auto builds takes to run. +- Pipeline duration: check how long the auto builds take to run. - Top slowest jobs: check which jobs are taking the longest to run. - Change in median job duration: check what jobs are slowest than before. Useful to detect regressions. @@ -456,8 +457,7 @@ this: 2. Choose the job you are interested in on the left-hand side. 3. Click on the gear icon and choose "View raw logs" 4. Search for the string "Configure the build" -5. All of the build settings are listed below that starting with the - `configure:` prefix. +5. All of the build settings are listed on the line with the text, `build.configure-args` [GitHub Actions]: https://github.com/rust-lang/rust/actions [`jobs.yml`]: https://github.com/rust-lang/rust/blob/master/src/ci/github-actions/jobs.yml @@ -467,3 +467,4 @@ this: [homu]: https://github.com/rust-lang/homu [merge queue]: https://bors.rust-lang.org/queue/rust [dist-x86_64-linux]: https://github.com/rust-lang/rust/blob/master/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile +[the GitHub Actions workflows page]: https://github.com/rust-lang/rust/actions diff --git a/src/doc/rustc-dev-guide/src/tests/codegen-backend-tests/cg_gcc.md b/src/doc/rustc-dev-guide/src/tests/codegen-backend-tests/cg_gcc.md index 4caf4c0e0eefa..74dbfb7d31b30 100644 --- a/src/doc/rustc-dev-guide/src/tests/codegen-backend-tests/cg_gcc.md +++ b/src/doc/rustc-dev-guide/src/tests/codegen-backend-tests/cg_gcc.md @@ -1,3 +1,56 @@ -# GCC codegen backend tests +# GCC codegen backend -TODO: please add some more information to this page. +If you ran into an error related to tests executed with the GCC codegen backend on CI, +you can use the following command to run tests locally using the GCC backend: + +```bash +./x test tests/ui --set 'rust.codegen-backends = ["llvm", "gcc"]' --test-codegen-backend gcc +``` + +Below, you can find more information about how to configure the GCC backend in bootstrap. + +## Choosing which codegen backends are built + +The `rust.codegen-backends = [...]` bootstrap option affects which codegen backends will be built and +included in the sysroot of the produced `rustc`. To use the GCC codegen backend, `"gcc"` has to +be included in this array in `bootstrap.toml`: + +```toml +rust.codegen-backends = ["llvm", "gcc"] +``` + +If you don't want to change your `bootstrap.toml` file, you can alternatively run your `x` +commands with `--set rust.codegen-backends=["llvm", "gcc"]'`. For example: + +```bash +./x build --set 'rust.codegen-backends=["llvm", "gcc"]' +``` + +The first backend in the `codegen-backends` array will determine which backend will be used as the +*default backend* of the built `rustc`. This also determines which backend will be used to compile the +stage 1 standard library (or anything built in stage 2+). To produce `rustc` that uses the GCC backend +by default, you can thus put `"gcc"` as the first element of this array: + +```bash +./x build --set 'rust.codegen-backends=["gcc"]' library +``` + +## Choosing the codegen backend used in tests + +To run compiler tests with the GCC codegen backend being used to build the test Rust programs, you can use the +`--test-codegen-backend` flag: + +```bash +./x test tests/ui --test-codegen-backend gcc +``` + +Note that in order for this to work, the tested compiler must have the GCC codegen backend available in its sysroot +directory. You can achieve that using the [instructions above](#choosing-which-codegen-backends-are-built). + +## Downloading GCC from CI + +The `gcc.download-ci-gcc` bootstrap option controls if GCC (which is a dependency of the GCC codegen backend) +will be downloaded from CI or built locally. The default value is `true`, which will download GCC from CI +if there are no local changes to the GCC sources and the given host target is available on CI. + +Note that GCC can currently only be downloaded from CI for the `x86_64-unknown-linux-gnu` target. diff --git a/src/doc/rustc-dev-guide/src/tests/compiletest.md b/src/doc/rustc-dev-guide/src/tests/compiletest.md index a4a729935fa47..0234b394c2a05 100644 --- a/src/doc/rustc-dev-guide/src/tests/compiletest.md +++ b/src/doc/rustc-dev-guide/src/tests/compiletest.md @@ -72,7 +72,7 @@ The following test suites are available, with links for more information: | [`mir-opt`](#mir-opt-tests) | Check MIR generation and optimizations | | [`coverage`](#coverage-tests) | Check coverage instrumentation | | [`coverage-run-rustdoc`](#coverage-tests) | `coverage` tests that also run instrumented doctests | -| [`crashes`](#crashes-tests) | Check that the compiler ICEs/panics/crashes on certain inputs to catch accidental fixes | +| [`crashes`](#crash-tests) | Check that the compiler ICEs/panics/crashes on certain inputs to catch accidental fixes | ### General purpose test suite @@ -557,7 +557,7 @@ only running the main `coverage` suite. [`src/tools/coverage-dump`]: https://github.com/rust-lang/rust/tree/master/src/tools/coverage-dump [`tests/coverage-run-rustdoc`]: https://github.com/rust-lang/rust/tree/master/tests/coverage-run-rustdoc -### Crashes tests +### Crash tests [`tests/crashes`] serve as a collection of tests that are expected to cause the compiler to ICE, panic or crash in some other way, so that accidental fixes are @@ -580,13 +580,13 @@ recommended to include test cases from several issues in a single PR. When you do so, each issue number should be noted in the file name (`12345.rs` should suffice) and also inside the file by means of a `//@ known-bug: #12345` directive. Please [label][labeling] the relevant issues with `S-bug-has-test` -afterwards. +once your PR is merged. If you happen to fix one of the crashes, please move it to a fitting subdirectory in `tests/ui` and give it a meaningful name. Please add a doc comment at the top of the file explaining why this test exists, even better if you can briefly explain how the example causes rustc to crash previously and -what was done to prevent rustc to ICE/panic/crash. +what was done to prevent rustc to ICE / panic / crash. Adding diff --git a/src/doc/rustc-dev-guide/src/tests/crater.md b/src/doc/rustc-dev-guide/src/tests/crater.md index 9d4ac87daf36a..96bb5a4f2ae67 100644 --- a/src/doc/rustc-dev-guide/src/tests/crater.md +++ b/src/doc/rustc-dev-guide/src/tests/crater.md @@ -8,30 +8,30 @@ stable compiler versions. ## When to run Crater -You should request a crater run if your PR makes large changes to the compiler +You should request a Crater run if your PR makes large changes to the compiler or could cause breakage. If you are unsure, feel free to ask your PR's reviewer. ## Requesting Crater Runs -The rust team maintains a few machines that can be used for running crater runs -on the changes introduced by a PR. If your PR needs a crater run, leave a +The Rust team maintains a few machines that can be used for Crater runs +on the changes introduced by a PR. If your PR needs a Crater run, leave a comment for the triage team in the PR thread. Please inform the team whether you -require a "check-only" crater run, a "build only" crater run, or a -"build-and-test" crater run. The difference is primarily in time; the -conservative (if you're not sure) option is to go for the build-and-test run. If +require a "check-only" Crater run, a "build only" Crater run, or a +"build-and-test" Crater run. The difference is primarily in time; +if you're not sure, go for the build-and-test run. If making changes that will only have an effect at compile-time (e.g., implementing -a new trait) then you only need a check run. +a new trait), then you only need a check run. Your PR will be enqueued by the triage team and the results will be posted when -they are ready. Check runs will take around ~3-4 days, with the other two taking +they are ready. Check runs will take around ~3-4 days, and the other two taking 5-6 days on average. -While crater is really useful, it is also important to be aware of a few +While Crater is really useful, it is also important to be aware of a few caveats: - Not all code is on crates.io! There is a lot of code in repos on GitHub and elsewhere. Also, companies may not wish to publish their code. Thus, a - successful crater run is not a magically green light that there will be no + successful Crater run does not mean there will be no breakage; you still need to be careful. - Crater only runs Linux builds on x86_64. Thus, other architectures and @@ -41,5 +41,5 @@ caveats: the crate doesn't compile any more (e.g. used old nightly features), has broken or flaky tests, requires network access, or other reasons. -- Before crater can be run, `@bors try` needs to succeed in building artifacts. - This means that if your code doesn't compile, you cannot run crater. +- Before Crater can be run, `@bors try` needs to succeed in building artifacts. + This means that if your code doesn't compile, you cannot run Crater. diff --git a/src/doc/rustc-dev-guide/src/tracing.md b/src/doc/rustc-dev-guide/src/tracing.md index 5e5b81fc65b22..a7cdab73e7973 100644 --- a/src/doc/rustc-dev-guide/src/tracing.md +++ b/src/doc/rustc-dev-guide/src/tracing.md @@ -109,7 +109,7 @@ Miri, use `MIRI_LOG` instead. You get the idea :) See the [`tracing`] crate's docs, and specifically the docs for [`debug!`] to see the full syntax you can use. (Note: unlike the compiler, the [`tracing`] -crate and its examples use the `RUST_LOG` environment variable. rustc, rustdoc, +crate and its examples use the `RUSTC_LOG` environment variable. rustc, rustdoc, and other tools set custom environment variables.) **Note that unless you use a very strict filter, the logger will emit a lot of diff --git a/src/doc/unstable-book/src/compiler-flags/branch-protection.md b/src/doc/unstable-book/src/compiler-flags/branch-protection.md index f0cc44a07f30d..c15567dcac2ee 100644 --- a/src/doc/unstable-book/src/compiler-flags/branch-protection.md +++ b/src/doc/unstable-book/src/compiler-flags/branch-protection.md @@ -13,6 +13,7 @@ It takes some combination of the following values, separated by a `,`. - `leaf` - Enable pointer authentication for all functions, including leaf functions. - `b-key` - Sign return addresses with key B, instead of the default key A. - `bti` - Enable branch target identification. +- `gcs` - Enable guarded control stack support. `leaf`, `b-key` and `pc` are only valid if `pac-ret` was previously specified. For example, `-Z branch-protection=bti,pac-ret,leaf` is valid, but diff --git a/src/librustdoc/passes/lint/html_tags.rs b/src/librustdoc/passes/lint/html_tags.rs index da09117b1bba7..136ff258048bf 100644 --- a/src/librustdoc/passes/lint/html_tags.rs +++ b/src/librustdoc/passes/lint/html_tags.rs @@ -364,6 +364,7 @@ impl TagParser { } else { if !self.tag_name.is_empty() { self.in_attrs = true; + // range of the entire tag within dox let mut r = Range { start: range.start + start_pos, end: range.start + pos }; if c == '>' { // In case we have a tag without attribute, we can consider the span to @@ -381,7 +382,7 @@ impl TagParser { for (new_pos, c) in text[pos..].char_indices() { if !c.is_whitespace() { if c == '>' { - r.end = range.start + new_pos + 1; + r.end = range.start + pos + new_pos + 1; found = true; } else if c == '<' { self.handle_lt_in_tag(range.clone(), pos + new_pos, f); diff --git a/src/tools/miri/src/intrinsics/math.rs b/src/tools/miri/src/intrinsics/math.rs index b9c99f2859468..0cc4342f0d55d 100644 --- a/src/tools/miri/src/intrinsics/math.rs +++ b/src/tools/miri/src/intrinsics/math.rs @@ -1,4 +1,3 @@ -use rand::Rng; use rustc_apfloat::{self, Float, FloatConvert, Round}; use rustc_middle::mir; use rustc_middle::ty::{self, FloatTy}; @@ -39,46 +38,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "sqrtf64" => sqrt::(this, args, dest)?, "sqrtf128" => sqrt::(this, args, dest)?, - "fmaf32" => { - let [a, b, c] = check_intrinsic_arg_count(args)?; - let a = this.read_scalar(a)?.to_f32()?; - let b = this.read_scalar(b)?.to_f32()?; - let c = this.read_scalar(c)?.to_f32()?; - let res = a.mul_add(b, c).value; - let res = this.adjust_nan(res, &[a, b, c]); - this.write_scalar(res, dest)?; - } - "fmaf64" => { - let [a, b, c] = check_intrinsic_arg_count(args)?; - let a = this.read_scalar(a)?.to_f64()?; - let b = this.read_scalar(b)?.to_f64()?; - let c = this.read_scalar(c)?.to_f64()?; - let res = a.mul_add(b, c).value; - let res = this.adjust_nan(res, &[a, b, c]); - this.write_scalar(res, dest)?; - } - - "fmuladdf32" => { - let [a, b, c] = check_intrinsic_arg_count(args)?; - let a = this.read_scalar(a)?.to_f32()?; - let b = this.read_scalar(b)?.to_f32()?; - let c = this.read_scalar(c)?.to_f32()?; - let fuse: bool = this.machine.float_nondet && this.machine.rng.get_mut().random(); - let res = if fuse { a.mul_add(b, c).value } else { ((a * b).value + c).value }; - let res = this.adjust_nan(res, &[a, b, c]); - this.write_scalar(res, dest)?; - } - "fmuladdf64" => { - let [a, b, c] = check_intrinsic_arg_count(args)?; - let a = this.read_scalar(a)?.to_f64()?; - let b = this.read_scalar(b)?.to_f64()?; - let c = this.read_scalar(c)?.to_f64()?; - let fuse: bool = this.machine.float_nondet && this.machine.rng.get_mut().random(); - let res = if fuse { a.mul_add(b, c).value } else { ((a * b).value + c).value }; - let res = this.adjust_nan(res, &[a, b, c]); - this.write_scalar(res, dest)?; - } - #[rustfmt::skip] | "fadd_fast" | "fsub_fast" diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 04c8bee72c038..d307636e782fc 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -1293,6 +1293,11 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { ecx.equal_float_min_max(a, b) } + #[inline(always)] + fn float_fuse_mul_add(ecx: &mut InterpCx<'tcx, Self>) -> bool { + ecx.machine.float_nondet && ecx.machine.rng.get_mut().random() + } + #[inline(always)] fn ub_checks(ecx: &InterpCx<'tcx, Self>) -> InterpResult<'tcx, bool> { interp_ok(ecx.tcx.sess.ub_checks()) diff --git a/tests/assembly-llvm/aarch64-pointer-auth.rs b/tests/assembly-llvm/aarch64-pointer-auth.rs index 56a26df469f35..e1ca6d775813d 100644 --- a/tests/assembly-llvm/aarch64-pointer-auth.rs +++ b/tests/assembly-llvm/aarch64-pointer-auth.rs @@ -1,10 +1,13 @@ // Test that PAC instructions are emitted when branch-protection is specified. //@ add-core-stubs -//@ revisions: PACRET PAUTHLR_NOP PAUTHLR +//@ revisions: GCS PACRET PAUTHLR_NOP PAUTHLR //@ assembly-output: emit-asm //@ needs-llvm-components: aarch64 //@ compile-flags: --target aarch64-unknown-linux-gnu +//@ [GCS] min-llvm-version: 21 +//@ [GCS] ignore-apple (XCode version needs updating) +//@ [GCS] compile-flags: -Z branch-protection=gcs //@ [PACRET] compile-flags: -Z branch-protection=pac-ret,leaf //@ [PAUTHLR_NOP] compile-flags: -Z branch-protection=pac-ret,pc,leaf //@ [PAUTHLR] compile-flags: -C target-feature=+pauth-lr -Z branch-protection=pac-ret,pc,leaf @@ -17,6 +20,7 @@ extern crate minicore; use minicore::*; +// GCS: .aeabi_attribute 2, 1 // Tag_Feature_GCS // PACRET: hint #25 // PACRET: hint #29 // PAUTHLR_NOP: hint #25 diff --git a/tests/codegen-llvm/branch-protection.rs b/tests/codegen-llvm/branch-protection.rs index d67e494cc0d65..f92259c941cef 100644 --- a/tests/codegen-llvm/branch-protection.rs +++ b/tests/codegen-llvm/branch-protection.rs @@ -1,9 +1,10 @@ // Test that the correct module flags are emitted with different branch protection flags. //@ add-core-stubs -//@ revisions: BTI PACRET LEAF BKEY PAUTHLR PAUTHLR_BKEY PAUTHLR_LEAF PAUTHLR_BTI NONE +//@ revisions: BTI GCS PACRET LEAF BKEY PAUTHLR PAUTHLR_BKEY PAUTHLR_LEAF PAUTHLR_BTI NONE //@ needs-llvm-components: aarch64 //@ [BTI] compile-flags: -Z branch-protection=bti +//@ [GCS] compile-flags: -Z branch-protection=gcs //@ [PACRET] compile-flags: -Z branch-protection=pac-ret //@ [LEAF] compile-flags: -Z branch-protection=pac-ret,leaf //@ [BKEY] compile-flags: -Z branch-protection=pac-ret,b-key @@ -32,6 +33,9 @@ pub fn test() {} // BTI: !"sign-return-address-all", i32 0 // BTI: !"sign-return-address-with-bkey", i32 0 +// GCS: attributes [[ATTR]] = {{.*}} "guarded-control-stack" +// GCS: !"guarded-control-stack", i32 1 + // PACRET: attributes [[ATTR]] = {{.*}} "sign-return-address"="non-leaf" // PACRET-SAME: "sign-return-address-key"="a_key" // PACRET: !"branch-target-enforcement", i32 0 diff --git a/tests/codegen-llvm/global-allocator-attributes.rs b/tests/codegen-llvm/global-allocator-attributes.rs new file mode 100644 index 0000000000000..472ca77207500 --- /dev/null +++ b/tests/codegen-llvm/global-allocator-attributes.rs @@ -0,0 +1,41 @@ +//@ compile-flags: -C opt-level=3 +#![crate_type = "lib"] + +mod foobar { + use std::alloc::{GlobalAlloc, Layout}; + + struct Allocator; + + unsafe impl GlobalAlloc for Allocator { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + // CHECK-LABEL: ; __rustc::__rust_alloc + // CHECK-NEXT: ; Function Attrs: {{.*}}allockind("alloc,uninitialized,aligned") allocsize(0){{.*}} + // CHECK-NEXT: define{{.*}} noalias{{.*}} ptr @{{.*}}__rust_alloc(i[[SIZE:[0-9]+]] {{.*}}%size, i[[SIZE]] allocalign{{.*}} %align) + panic!() + } + + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + // CHECK-LABEL: ; __rustc::__rust_dealloc + // CHECK-NEXT: ; Function Attrs: {{.*}}allockind("free"){{.*}} + // CHECK-NEXT: define{{.*}} void @{{.*}}__rust_dealloc(ptr allocptr{{.*}} %ptr, i[[SIZE]] {{.*}} %size, i[[SIZE]] {{.*}} %align) + panic!() + } + + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { + // CHECK-LABEL: ; __rustc::__rust_realloc + // CHECK-NEXT: ; Function Attrs: {{.*}}allockind("realloc,aligned") allocsize(3){{.*}} + // CHECK-NEXT: define{{.*}} noalias{{.*}} ptr @{{.*}}__rust_realloc(ptr allocptr{{.*}} %ptr, i[[SIZE]] {{.*}} %size, i[[SIZE]] allocalign{{.*}} %align, i[[SIZE]] {{.*}} %new_size) + panic!() + } + + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { + // CHECK-LABEL: ; __rustc::__rust_alloc_zeroed + // CHECK-NEXT: ; Function Attrs: {{.*}}allockind("alloc,zeroed,aligned") allocsize(0){{.*}} + // CHECK-NEXT: define{{.*}} noalias{{.*}} ptr @{{.*}}__rust_alloc_zeroed(i[[SIZE]] {{.*}} %size, i[[SIZE]] allocalign{{.*}} %align) + panic!() + } + } + + #[global_allocator] + static GLOBAL: Allocator = Allocator; +} diff --git a/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs b/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs index 0a2186b095389..2ac5fdee063c2 100644 --- a/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs +++ b/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs @@ -1,12 +1,14 @@ // `-Z branch protection` is an unstable compiler feature which adds pointer-authentication // code (PAC), a useful hashing measure for verifying that pointers have not been modified. // This test checks that compilation and execution is successful when this feature is activated, -// with some of its possible extra arguments (bti, pac-ret, leaf) when doing LTO. +// with some of its possible extra arguments (bti, gcs, pac-ret, leaf) when doing LTO. // See https://github.com/rust-lang/rust/pull/88354 //@ needs-force-clang-based-tests //@ only-aarch64 // Reason: branch protection is not supported on other architectures +//@ ignore-apple +// Reason: XCode needs updating to support gcs //@ ignore-cross-compile // Reason: the compiled binary is executed @@ -19,7 +21,7 @@ fn main() { clang() .arg("-v") .lto("thin") - .arg("-mbranch-protection=bti+pac-ret+b-key+leaf") + .arg("-mbranch-protection=bti+gcs+pac-ret+b-key+leaf") .arg("-c") .out_exe("test.o") .input("test.c") @@ -30,7 +32,7 @@ fn main() { .opt_level("2") .linker(&env_var("CLANG")) .link_arg("-fuse-ld=lld") - .arg("-Zbranch-protection=bti,pac-ret,leaf") + .arg("-Zbranch-protection=bti,gcs,pac-ret,leaf") .input("test.rs") .output("test.bin") .run(); diff --git a/tests/run-make/pointer-auth-link-with-c/rmake.rs b/tests/run-make/pointer-auth-link-with-c/rmake.rs index a4d7454e5755a..1ddcb79d64ff4 100644 --- a/tests/run-make/pointer-auth-link-with-c/rmake.rs +++ b/tests/run-make/pointer-auth-link-with-c/rmake.rs @@ -1,11 +1,13 @@ // `-Z branch protection` is an unstable compiler feature which adds pointer-authentication // code (PAC), a useful hashing measure for verifying that pointers have not been modified. // This test checks that compilation and execution is successful when this feature is activated, -// with some of its possible extra arguments (bti, pac-ret, pc, leaf, b-key). +// with some of its possible extra arguments (bti, gcs, pac-ret, pc, leaf, b-key). // See https://github.com/rust-lang/rust/pull/88354 //@ only-aarch64 // Reason: branch protection is not supported on other architectures +//@ ignore-apple +// Reason: XCode needs updating to support gcs //@ ignore-cross-compile // Reason: the compiled binary is executed @@ -13,17 +15,17 @@ use run_make_support::{build_native_static_lib, cc, is_windows_msvc, llvm_ar, ru fn main() { build_native_static_lib("test"); - rustc().arg("-Zbranch-protection=bti,pac-ret,leaf").input("test.rs").run(); + rustc().arg("-Zbranch-protection=bti,gcs,pac-ret,leaf").input("test.rs").run(); run("test"); cc().arg("-v") .arg("-c") .out_exe("test") .input("test.c") - .arg("-mbranch-protection=bti+pac-ret+leaf") + .arg("-mbranch-protection=bti+gcs+pac-ret+leaf") .run(); let obj_file = if is_windows_msvc() { "test.obj" } else { "test" }; llvm_ar().obj_to_ar().output_input("libtest.a", &obj_file).run(); - rustc().arg("-Zbranch-protection=bti,pac-ret,leaf").input("test.rs").run(); + rustc().arg("-Zbranch-protection=bti,gcs,pac-ret,leaf").input("test.rs").run(); run("test"); // FIXME: +pc was only recently added to LLVM diff --git a/tests/rustdoc-ui/lints/invalid-html-tags-ice-146890.rs b/tests/rustdoc-ui/lints/invalid-html-tags-ice-146890.rs new file mode 100644 index 0000000000000..d7efc201e7e39 --- /dev/null +++ b/tests/rustdoc-ui/lints/invalid-html-tags-ice-146890.rs @@ -0,0 +1,25 @@ +// this test ensures that bad HTML with multiline tags doesn't cause an ICE +// regression test for https://github.com/rust-lang/rust/issues/146890 +#[deny(rustdoc::invalid_html_tags)] + +/// +/// +/// +///
key +/// +/// value +/// +///
+pub fn foo() {} diff --git a/tests/rustdoc-ui/lints/invalid-html-tags-ice-146890.stderr b/tests/rustdoc-ui/lints/invalid-html-tags-ice-146890.stderr new file mode 100644 index 0000000000000..64a82b3a952aa --- /dev/null +++ b/tests/rustdoc-ui/lints/invalid-html-tags-ice-146890.stderr @@ -0,0 +1,38 @@ +error: unopened HTML tag `TD` + --> $DIR/invalid-html-tags-ice-146890.rs:12:5 + | +LL | /// + | |_____^ + | +note: the lint level is defined here + --> $DIR/invalid-html-tags-ice-146890.rs:3:8 + | +LL | #[deny(rustdoc::invalid_html_tags)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unopened HTML tag `TD` + --> $DIR/invalid-html-tags-ice-146890.rs:18:5 + | +LL | /// + | |_____^ + +error: unclosed HTML tag `TH` + --> $DIR/invalid-html-tags-ice-146890.rs:9:5 + | +LL | /// $DIR/invalid-html-tags-ice-146890.rs:15:5 + | +LL | /// $DIR/unclosed-6.rs:1:1 + | +LL | / --- +LL | | +LL | | 🦀--- +LL | | --- +... | +LL | | + | |_^ + | +note: frontmatter opening here was not closed + --> $DIR/unclosed-6.rs:1:1 + | +LL | --- + | ^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGS.stderr b/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGS.stderr index dae08119dbc68..277111a41f29c 100644 --- a/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGS.stderr +++ b/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGS.stderr @@ -1,2 +1,2 @@ -error: incorrect value `leaf` for unstable option `branch-protection` - a `,` separated combination of `bti`, `pac-ret`, followed by a combination of `pc`, `b-key`, or `leaf` was expected +error: incorrect value `leaf` for unstable option `branch-protection` - a `,` separated combination of `bti`, `gcs`, `pac-ret`, (optionally with `pc`, `b-key`, `leaf` if `pac-ret` is set) was expected diff --git a/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGSPC.stderr b/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGSPC.stderr index 13f79e94674b2..e1ade01d2fe76 100644 --- a/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGSPC.stderr +++ b/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGSPC.stderr @@ -1,2 +1,2 @@ -error: incorrect value `pc` for unstable option `branch-protection` - a `,` separated combination of `bti`, `pac-ret`, followed by a combination of `pc`, `b-key`, or `leaf` was expected +error: incorrect value `pc` for unstable option `branch-protection` - a `,` separated combination of `bti`, `gcs`, `pac-ret`, (optionally with `pc`, `b-key`, `leaf` if `pac-ret` is set) was expected diff --git a/tests/ui/lifetimes/temporary-lifetime-extension-tuple-ctor.rs b/tests/ui/lifetimes/temporary-lifetime-extension-tuple-ctor.rs index bb537f855a4ab..7de786dff3b77 100644 --- a/tests/ui/lifetimes/temporary-lifetime-extension-tuple-ctor.rs +++ b/tests/ui/lifetimes/temporary-lifetime-extension-tuple-ctor.rs @@ -1,4 +1,4 @@ -//@ edition:2024 +//@ reference: destructors.scope.lifetime-extension.exprs fn temp() -> String { String::from("Hello") @@ -22,7 +22,7 @@ fn main() { let a = &temp(); let b = Some(&temp()); let c = Option::Some::<&String>(&temp()); - use Option::Some as S; + use std::option::Option::Some as S; let d = S(&temp()); let e = X(&temp()); let f = Some(Ok::<_, ()>(std::borrow::Cow::Borrowed(if true { @@ -31,6 +31,6 @@ fn main() { panic!() }))); let some = Some; // Turn the ctor into a regular function. - let g = some(&temp()); //~ERROR temporary value dropped while borrowe + let g = some(&temp()); //~ERROR temporary value dropped while borrowed println!("{a:?} {b:?} {c:?} {d:?} {e:?} {f:?} {g:?}"); } diff --git a/tests/ui/suggestions/non_copy_move_out_of_tuple.rs b/tests/ui/suggestions/non_copy_move_out_of_tuple.rs new file mode 100644 index 0000000000000..baf15dba33a96 --- /dev/null +++ b/tests/ui/suggestions/non_copy_move_out_of_tuple.rs @@ -0,0 +1,8 @@ +// Regression test for #146537. + +struct NonCopy; +fn main() { + let tuple = &(NonCopy,); + let b: NonCopy; + (b,) = *tuple; //~ ERROR: cannot move out of `tuple.0` which is behind a shared reference [E0507] +} diff --git a/tests/ui/suggestions/non_copy_move_out_of_tuple.stderr b/tests/ui/suggestions/non_copy_move_out_of_tuple.stderr new file mode 100644 index 0000000000000..62f24324fcc17 --- /dev/null +++ b/tests/ui/suggestions/non_copy_move_out_of_tuple.stderr @@ -0,0 +1,26 @@ +error[E0507]: cannot move out of `tuple.0` which is behind a shared reference + --> $DIR/non_copy_move_out_of_tuple.rs:7:12 + | +LL | (b,) = *tuple; + | - ^^^^^^ + | | + | data moved here + | move occurs because the place has type `NonCopy`, which does not implement the `Copy` trait + | +note: if `NonCopy` implemented `Clone`, you could clone the value + --> $DIR/non_copy_move_out_of_tuple.rs:3:1 + | +LL | struct NonCopy; + | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | (b,) = *tuple; + | - you could clone this value +help: consider removing the dereference here + | +LL - (b,) = *tuple; +LL + (b,) = tuple; + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/type-inference/box_has_sigdrop.rs b/tests/ui/type-inference/box_has_sigdrop.rs new file mode 100644 index 0000000000000..3e801197a78e6 --- /dev/null +++ b/tests/ui/type-inference/box_has_sigdrop.rs @@ -0,0 +1,9 @@ +//@ should-fail +//@ compile-flags: -Wrust-2021-incompatible-closure-captures +// Inference, canonicalization, and significant drops should work nicely together. +// Related issue: #86868 + +fn main() { + let mut state = 0; + Box::new(move || state) +} diff --git a/tests/ui/type-inference/box_has_sigdrop.stderr b/tests/ui/type-inference/box_has_sigdrop.stderr new file mode 100644 index 0000000000000..b61b6322c107f --- /dev/null +++ b/tests/ui/type-inference/box_has_sigdrop.stderr @@ -0,0 +1,17 @@ +error[E0308]: mismatched types + --> $DIR/box_has_sigdrop.rs:8:5 + | +LL | fn main() { + | - expected `()` because of default return type +LL | let mut state = 0; +LL | Box::new(move || state) + | ^^^^^^^^^^^^^^^^^^^^^^^- help: consider using a semicolon here: `;` + | | + | expected `()`, found `Box<{closure@box_has_sigdrop.rs:8:14}>` + | + = note: expected unit type `()` + found struct `Box<{closure@$DIR/box_has_sigdrop.rs:8:14: 8:21}>` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/type-inference/has_sigdrop.rs b/tests/ui/type-inference/dropper_has_sigdrop.rs similarity index 100% rename from tests/ui/type-inference/has_sigdrop.rs rename to tests/ui/type-inference/dropper_has_sigdrop.rs