Auto merge of #148507 - Zalathar:rollup-vvz4knr, r=Zalathar
Rollup of 6 pull requests Successful merges: - rust-lang/rust#147355 (Add alignment parameter to `simd_masked_{load,store}`) - rust-lang/rust#147925 (Fix tests for big-endian) - rust-lang/rust#148341 (compiler: Fix a couple issues around cargo feature unification) - rust-lang/rust#148371 (Dogfood `trim_{suffix|prefix}` in compiler) - rust-lang/rust#148495 (Implement Path::is_empty) - rust-lang/rust#148502 (rustc-dev-guide subtree update) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
8e0b68e63c
59 changed files with 1889 additions and 474 deletions
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
use cranelift_codegen::ir::immediates::Offset32;
|
||||
use rustc_abi::Endian;
|
||||
use rustc_middle::ty::SimdAlign;
|
||||
|
||||
use super::*;
|
||||
use crate::prelude::*;
|
||||
|
|
@ -960,6 +961,15 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
|
|||
let lane_clif_ty = fx.clif_type(val_lane_ty).unwrap();
|
||||
let ptr_val = ptr.load_scalar(fx);
|
||||
|
||||
let alignment = generic_args[3].expect_const().to_value().valtree.unwrap_branch()[0]
|
||||
.unwrap_leaf()
|
||||
.to_simd_alignment();
|
||||
|
||||
let memflags = match alignment {
|
||||
SimdAlign::Unaligned => MemFlags::new().with_notrap(),
|
||||
_ => MemFlags::trusted(),
|
||||
};
|
||||
|
||||
for lane_idx in 0..val_lane_count {
|
||||
let val_lane = val.value_lane(fx, lane_idx).load_scalar(fx);
|
||||
let mask_lane = mask.value_lane(fx, lane_idx).load_scalar(fx);
|
||||
|
|
@ -972,7 +982,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
|
|||
|
||||
fx.bcx.switch_to_block(if_enabled);
|
||||
let offset = lane_idx as i32 * lane_clif_ty.bytes() as i32;
|
||||
fx.bcx.ins().store(MemFlags::trusted(), val_lane, ptr_val, Offset32::new(offset));
|
||||
fx.bcx.ins().store(memflags, val_lane, ptr_val, Offset32::new(offset));
|
||||
fx.bcx.ins().jump(next, &[]);
|
||||
|
||||
fx.bcx.seal_block(next);
|
||||
|
|
@ -996,6 +1006,15 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
|
|||
let lane_clif_ty = fx.clif_type(val_lane_ty).unwrap();
|
||||
let ret_lane_layout = fx.layout_of(ret_lane_ty);
|
||||
|
||||
let alignment = generic_args[3].expect_const().to_value().valtree.unwrap_branch()[0]
|
||||
.unwrap_leaf()
|
||||
.to_simd_alignment();
|
||||
|
||||
let memflags = match alignment {
|
||||
SimdAlign::Unaligned => MemFlags::new().with_notrap(),
|
||||
_ => MemFlags::trusted(),
|
||||
};
|
||||
|
||||
for lane_idx in 0..ptr_lane_count {
|
||||
let val_lane = val.value_lane(fx, lane_idx).load_scalar(fx);
|
||||
let ptr_lane = ptr.value_lane(fx, lane_idx).load_scalar(fx);
|
||||
|
|
@ -1011,7 +1030,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
|
|||
fx.bcx.seal_block(if_disabled);
|
||||
|
||||
fx.bcx.switch_to_block(if_enabled);
|
||||
let res = fx.bcx.ins().load(lane_clif_ty, MemFlags::trusted(), ptr_lane, 0);
|
||||
let res = fx.bcx.ins().load(lane_clif_ty, memflags, ptr_lane, 0);
|
||||
fx.bcx.ins().jump(next, &[res.into()]);
|
||||
|
||||
fx.bcx.switch_to_block(if_disabled);
|
||||
|
|
|
|||
|
|
@ -453,7 +453,7 @@ fn report_inline_asm(
|
|||
llvm::DiagnosticLevel::Warning => Level::Warning,
|
||||
llvm::DiagnosticLevel::Note | llvm::DiagnosticLevel::Remark => Level::Note,
|
||||
};
|
||||
let msg = msg.strip_prefix("error: ").unwrap_or(&msg).to_string();
|
||||
let msg = msg.trim_prefix("error: ").to_string();
|
||||
cgcx.diag_emitter.inline_asm_error(span, msg, level, source);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use rustc_hir::def_id::LOCAL_CRATE;
|
|||
use rustc_hir::{self as hir};
|
||||
use rustc_middle::mir::BinOp;
|
||||
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv, LayoutOf};
|
||||
use rustc_middle::ty::{self, GenericArgsRef, Instance, Ty, TyCtxt, TypingEnv};
|
||||
use rustc_middle::ty::{self, GenericArgsRef, Instance, SimdAlign, Ty, TyCtxt, TypingEnv};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
use rustc_symbol_mangling::{mangle_internal_symbol, symbol_name_for_instance_in_crate};
|
||||
|
|
@ -1840,8 +1840,21 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
return Ok(call);
|
||||
}
|
||||
|
||||
fn llvm_alignment<'ll, 'tcx>(
|
||||
bx: &mut Builder<'_, 'll, 'tcx>,
|
||||
alignment: SimdAlign,
|
||||
vector_ty: Ty<'tcx>,
|
||||
element_ty: Ty<'tcx>,
|
||||
) -> u64 {
|
||||
match alignment {
|
||||
SimdAlign::Unaligned => 1,
|
||||
SimdAlign::Element => bx.align_of(element_ty).bytes(),
|
||||
SimdAlign::Vector => bx.align_of(vector_ty).bytes(),
|
||||
}
|
||||
}
|
||||
|
||||
if name == sym::simd_masked_load {
|
||||
// simd_masked_load(mask: <N x i{M}>, pointer: *_ T, values: <N x T>) -> <N x T>
|
||||
// simd_masked_load<_, _, _, const ALIGN: SimdAlign>(mask: <N x i{M}>, pointer: *_ T, values: <N x T>) -> <N x T>
|
||||
// * N: number of elements in the input vectors
|
||||
// * T: type of the element to load
|
||||
// * M: any integer width is supported, will be truncated to i1
|
||||
|
|
@ -1849,6 +1862,10 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
// those lanes whose `mask` bit is enabled.
|
||||
// The memory addresses corresponding to the “off” lanes are not accessed.
|
||||
|
||||
let alignment = fn_args[3].expect_const().to_value().valtree.unwrap_branch()[0]
|
||||
.unwrap_leaf()
|
||||
.to_simd_alignment();
|
||||
|
||||
// The element type of the "mask" argument must be a signed integer type of any width
|
||||
let mask_ty = in_ty;
|
||||
let (mask_len, mask_elem) = (in_len, in_elem);
|
||||
|
|
@ -1905,7 +1922,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
let mask = vector_mask_to_bitmask(bx, args[0].immediate(), m_elem_bitwidth, mask_len);
|
||||
|
||||
// Alignment of T, must be a constant integer value:
|
||||
let alignment = bx.align_of(values_elem).bytes();
|
||||
let alignment = llvm_alignment(bx, alignment, values_ty, values_elem);
|
||||
|
||||
let llvm_pointer = bx.type_ptr();
|
||||
|
||||
|
|
@ -1932,7 +1949,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
}
|
||||
|
||||
if name == sym::simd_masked_store {
|
||||
// simd_masked_store(mask: <N x i{M}>, pointer: *mut T, values: <N x T>) -> ()
|
||||
// simd_masked_store<_, _, _, const ALIGN: SimdAlign>(mask: <N x i{M}>, pointer: *mut T, values: <N x T>) -> ()
|
||||
// * N: number of elements in the input vectors
|
||||
// * T: type of the element to load
|
||||
// * M: any integer width is supported, will be truncated to i1
|
||||
|
|
@ -1940,6 +1957,10 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
// those lanes whose `mask` bit is enabled.
|
||||
// The memory addresses corresponding to the “off” lanes are not accessed.
|
||||
|
||||
let alignment = fn_args[3].expect_const().to_value().valtree.unwrap_branch()[0]
|
||||
.unwrap_leaf()
|
||||
.to_simd_alignment();
|
||||
|
||||
// The element type of the "mask" argument must be a signed integer type of any width
|
||||
let mask_ty = in_ty;
|
||||
let (mask_len, mask_elem) = (in_len, in_elem);
|
||||
|
|
@ -1990,7 +2011,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
let mask = vector_mask_to_bitmask(bx, args[0].immediate(), m_elem_bitwidth, mask_len);
|
||||
|
||||
// Alignment of T, must be a constant integer value:
|
||||
let alignment = bx.align_of(values_elem).bytes();
|
||||
let alignment = llvm_alignment(bx, alignment, values_ty, values_elem);
|
||||
|
||||
let llvm_pointer = bx.type_ptr();
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#![feature(macro_derive)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![feature(slice_as_array)]
|
||||
#![feature(trim_prefix_suffix)]
|
||||
#![feature(try_blocks)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
use either::Either;
|
||||
use rustc_abi::Endian;
|
||||
use rustc_abi::{BackendRepr, Endian};
|
||||
use rustc_apfloat::ieee::{Double, Half, Quad, Single};
|
||||
use rustc_apfloat::{Float, Round};
|
||||
use rustc_middle::mir::interpret::{InterpErrorKind, UndefinedBehaviorInfo};
|
||||
use rustc_middle::ty::FloatTy;
|
||||
use rustc_middle::mir::interpret::{InterpErrorKind, Pointer, UndefinedBehaviorInfo};
|
||||
use rustc_middle::ty::{FloatTy, SimdAlign};
|
||||
use rustc_middle::{bug, err_ub_format, mir, span_bug, throw_unsup_format, ty};
|
||||
use rustc_span::{Symbol, sym};
|
||||
use tracing::trace;
|
||||
|
||||
use super::{
|
||||
ImmTy, InterpCx, InterpResult, Machine, MinMax, MulAddType, OpTy, PlaceTy, Provenance, Scalar,
|
||||
Size, interp_ok, throw_ub_format,
|
||||
Size, TyAndLayout, assert_matches, interp_ok, throw_ub_format,
|
||||
};
|
||||
use crate::interpret::Writeable;
|
||||
|
||||
|
|
@ -644,6 +644,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
}
|
||||
}
|
||||
sym::simd_masked_load => {
|
||||
let dest_layout = dest.layout;
|
||||
|
||||
let (mask, mask_len) = self.project_to_simd(&args[0])?;
|
||||
let ptr = self.read_pointer(&args[1])?;
|
||||
let (default, default_len) = self.project_to_simd(&args[2])?;
|
||||
|
|
@ -652,6 +654,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
assert_eq!(dest_len, mask_len);
|
||||
assert_eq!(dest_len, default_len);
|
||||
|
||||
self.check_simd_ptr_alignment(
|
||||
ptr,
|
||||
dest_layout,
|
||||
generic_args[3].expect_const().to_value().valtree.unwrap_branch()[0]
|
||||
.unwrap_leaf()
|
||||
.to_simd_alignment(),
|
||||
)?;
|
||||
|
||||
for i in 0..dest_len {
|
||||
let mask = self.read_immediate(&self.project_index(&mask, i)?)?;
|
||||
let default = self.read_immediate(&self.project_index(&default, i)?)?;
|
||||
|
|
@ -660,7 +670,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
let val = if simd_element_to_bool(mask)? {
|
||||
// Size * u64 is implemented as always checked
|
||||
let ptr = ptr.wrapping_offset(dest.layout.size * i, self);
|
||||
let place = self.ptr_to_mplace(ptr, dest.layout);
|
||||
// we have already checked the alignment requirements
|
||||
let place = self.ptr_to_mplace_unaligned(ptr, dest.layout);
|
||||
self.read_immediate(&place)?
|
||||
} else {
|
||||
default
|
||||
|
|
@ -675,6 +686,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
|
||||
assert_eq!(mask_len, vals_len);
|
||||
|
||||
self.check_simd_ptr_alignment(
|
||||
ptr,
|
||||
args[2].layout,
|
||||
generic_args[3].expect_const().to_value().valtree.unwrap_branch()[0]
|
||||
.unwrap_leaf()
|
||||
.to_simd_alignment(),
|
||||
)?;
|
||||
|
||||
for i in 0..vals_len {
|
||||
let mask = self.read_immediate(&self.project_index(&mask, i)?)?;
|
||||
let val = self.read_immediate(&self.project_index(&vals, i)?)?;
|
||||
|
|
@ -682,7 +701,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
if simd_element_to_bool(mask)? {
|
||||
// Size * u64 is implemented as always checked
|
||||
let ptr = ptr.wrapping_offset(val.layout.size * i, self);
|
||||
let place = self.ptr_to_mplace(ptr, val.layout);
|
||||
// we have already checked the alignment requirements
|
||||
let place = self.ptr_to_mplace_unaligned(ptr, val.layout);
|
||||
self.write_immediate(*val, &place)?
|
||||
};
|
||||
}
|
||||
|
|
@ -753,6 +773,30 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
FloatTy::F128 => self.float_minmax::<Quad>(left, right, op)?,
|
||||
})
|
||||
}
|
||||
|
||||
fn check_simd_ptr_alignment(
|
||||
&self,
|
||||
ptr: Pointer<Option<M::Provenance>>,
|
||||
vector_layout: TyAndLayout<'tcx>,
|
||||
alignment: SimdAlign,
|
||||
) -> InterpResult<'tcx> {
|
||||
assert_matches!(vector_layout.backend_repr, BackendRepr::SimdVector { .. });
|
||||
|
||||
let align = match alignment {
|
||||
ty::SimdAlign::Unaligned => {
|
||||
// The pointer is supposed to be unaligned, so no check is required.
|
||||
return interp_ok(());
|
||||
}
|
||||
ty::SimdAlign::Element => {
|
||||
// Take the alignment of the only field, which is an array and therefore has the same
|
||||
// alignment as the element type.
|
||||
vector_layout.field(self, 0).align.abi
|
||||
}
|
||||
ty::SimdAlign::Vector => vector_layout.align.abi,
|
||||
};
|
||||
|
||||
self.check_ptr_align(ptr, align)
|
||||
}
|
||||
}
|
||||
|
||||
fn simd_bitmask_index(idx: u32, vec_len: u32, endianness: Endian) -> u32 {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#![feature(panic_backtrace_config)]
|
||||
#![feature(panic_update_hook)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![feature(trim_prefix_suffix)]
|
||||
#![feature(try_blocks)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
|
|
@ -466,7 +467,7 @@ pub enum Compilation {
|
|||
fn handle_explain(early_dcx: &EarlyDiagCtxt, registry: Registry, code: &str, color: ColorConfig) {
|
||||
// Allow "E0123" or "0123" form.
|
||||
let upper_cased_code = code.to_ascii_uppercase();
|
||||
if let Ok(code) = upper_cased_code.strip_prefix('E').unwrap_or(&upper_cased_code).parse::<u32>()
|
||||
if let Ok(code) = upper_cased_code.trim_prefix('E').parse::<u32>()
|
||||
&& code <= ErrCode::MAX_AS_U32
|
||||
&& let Ok(description) = registry.try_find_description(ErrCode::from_u32(code))
|
||||
{
|
||||
|
|
@ -1267,7 +1268,7 @@ fn warn_on_confusing_output_filename_flag(
|
|||
if let Some(name) = matches.opt_str("o")
|
||||
&& let Some(suspect) = args.iter().find(|arg| arg.starts_with("-o") && *arg != "-o")
|
||||
{
|
||||
let filename = suspect.strip_prefix("-").unwrap_or(suspect);
|
||||
let filename = suspect.trim_prefix("-");
|
||||
let optgroups = config::rustc_optgroups();
|
||||
let fake_args = ["optimize", "o0", "o1", "o2", "o3", "ofast", "og", "os", "oz"];
|
||||
|
||||
|
|
|
|||
|
|
@ -695,8 +695,8 @@ pub(crate) fn check_intrinsic_type(
|
|||
(1, 0, vec![param(0), param(0), param(0)], param(0))
|
||||
}
|
||||
sym::simd_gather => (3, 0, vec![param(0), param(1), param(2)], param(0)),
|
||||
sym::simd_masked_load => (3, 0, vec![param(0), param(1), param(2)], param(2)),
|
||||
sym::simd_masked_store => (3, 0, vec![param(0), param(1), param(2)], tcx.types.unit),
|
||||
sym::simd_masked_load => (3, 1, vec![param(0), param(1), param(2)], param(2)),
|
||||
sym::simd_masked_store => (3, 1, vec![param(0), param(1), param(2)], tcx.types.unit),
|
||||
sym::simd_scatter => (3, 0, vec![param(0), param(1), param(2)], tcx.types.unit),
|
||||
sym::simd_insert | sym::simd_insert_dyn => {
|
||||
(2, 0, vec![param(0), tcx.types.u32, param(1)], param(0))
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#![feature(iter_intersperse)]
|
||||
#![feature(iter_order_by)]
|
||||
#![feature(never_type)]
|
||||
#![feature(trim_prefix_suffix)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
mod _match;
|
||||
|
|
|
|||
|
|
@ -2551,7 +2551,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
// If this is a floating point literal that ends with '.',
|
||||
// get rid of it to stop this from becoming a member access.
|
||||
let snippet = snippet.strip_suffix('.').unwrap_or(&snippet);
|
||||
let snippet = snippet.trim_suffix('.');
|
||||
err.span_suggestion(
|
||||
lit.span,
|
||||
format!(
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ edition = "2024"
|
|||
rustc_index_macros = { path = "../rustc_index_macros" }
|
||||
rustc_macros = { path = "../rustc_macros", optional = true }
|
||||
rustc_serialize = { path = "../rustc_serialize", optional = true }
|
||||
smallvec = "1.8.1"
|
||||
smallvec = { version = "1.8.1", optional = true }
|
||||
# tidy-alphabetical-end
|
||||
|
||||
[features]
|
||||
|
|
@ -17,6 +17,7 @@ default = ["nightly"]
|
|||
nightly = [
|
||||
"dep:rustc_macros",
|
||||
"dep:rustc_serialize",
|
||||
"dep:smallvec",
|
||||
"rustc_index_macros/nightly",
|
||||
]
|
||||
rustc_randomized_layouts = []
|
||||
|
|
|
|||
|
|
@ -39,6 +39,15 @@ pub enum AtomicOrdering {
|
|||
SeqCst = 4,
|
||||
}
|
||||
|
||||
/// An enum to represent the compiler-side view of `intrinsics::simd::SimdAlign`.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum SimdAlign {
|
||||
// These values must match `intrinsics::simd::SimdAlign`!
|
||||
Unaligned = 0,
|
||||
Element = 1,
|
||||
Vector = 2,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for ConstInt {
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let Self { int, signed, is_ptr_sized_integral } = *self;
|
||||
|
|
@ -350,6 +359,21 @@ impl ScalarInt {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_simd_alignment(self) -> SimdAlign {
|
||||
use SimdAlign::*;
|
||||
let val = self.to_u32();
|
||||
if val == Unaligned as u32 {
|
||||
Unaligned
|
||||
} else if val == Element as u32 {
|
||||
Element
|
||||
} else if val == Vector as u32 {
|
||||
Vector
|
||||
} else {
|
||||
panic!("not a valid simd alignment")
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts the `ScalarInt` to `bool`.
|
||||
/// Panics if the `size` of the `ScalarInt` is not equal to 1 byte.
|
||||
/// Errors if it is not a valid `bool`.
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ pub use self::closure::{
|
|||
};
|
||||
pub use self::consts::{
|
||||
AnonConstKind, AtomicOrdering, Const, ConstInt, ConstKind, ConstToValTreeResult, Expr,
|
||||
ExprKind, ScalarInt, UnevaluatedConst, ValTree, ValTreeKind, Value,
|
||||
ExprKind, ScalarInt, SimdAlign, UnevaluatedConst, ValTree, ValTreeKind, Value,
|
||||
};
|
||||
pub use self::context::{
|
||||
CtxtInterners, CurrentGcx, Feed, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt, TyCtxtFeed, tls,
|
||||
|
|
|
|||
|
|
@ -2608,7 +2608,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||
let (span, text) = match path.segments.first() {
|
||||
Some(seg) if let Some(name) = seg.ident.as_str().strip_prefix("let") => {
|
||||
// a special case for #117894
|
||||
let name = name.strip_prefix('_').unwrap_or(name);
|
||||
let name = name.trim_prefix('_');
|
||||
(ident_span, format!("let {name}"))
|
||||
}
|
||||
_ => (ident_span.shrink_to_lo(), "let ".to_string()),
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#![feature(ptr_as_ref_unchecked)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![feature(trim_prefix_suffix)]
|
||||
#![recursion_limit = "256"]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
|
|
|
|||
|
|
@ -400,10 +400,10 @@ fn preprocess_link(link: &str) -> Box<str> {
|
|||
let link = link.split('#').next().unwrap();
|
||||
let link = link.trim();
|
||||
let link = link.rsplit('@').next().unwrap();
|
||||
let link = link.strip_suffix("()").unwrap_or(link);
|
||||
let link = link.strip_suffix("{}").unwrap_or(link);
|
||||
let link = link.strip_suffix("[]").unwrap_or(link);
|
||||
let link = if link != "!" { link.strip_suffix('!').unwrap_or(link) } else { link };
|
||||
let link = link.trim_suffix("()");
|
||||
let link = link.trim_suffix("{}");
|
||||
let link = link.trim_suffix("[]");
|
||||
let link = if link != "!" { link.trim_suffix('!') } else { link };
|
||||
let link = link.trim();
|
||||
strip_generics_from_path(link).unwrap_or_else(|_| link.into())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,6 @@ proc-macro = true
|
|||
# tidy-alphabetical-start
|
||||
proc-macro2 = "1"
|
||||
quote = "1"
|
||||
syn = { version = "2.0.9", features = ["full"] }
|
||||
syn = { version = "2.0.9", features = ["full", "visit-mut"] }
|
||||
synstructure = "0.13.0"
|
||||
# tidy-alphabetical-end
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
//!
|
||||
//! In this module, a "vector" is any `repr(simd)` type.
|
||||
|
||||
use crate::marker::ConstParamTy;
|
||||
|
||||
/// Inserts an element into a vector, returning the updated vector.
|
||||
///
|
||||
/// `T` must be a vector with element type `U`, and `idx` must be `const`.
|
||||
|
|
@ -377,6 +379,19 @@ pub unsafe fn simd_gather<T, U, V>(val: T, ptr: U, mask: V) -> T;
|
|||
#[rustc_nounwind]
|
||||
pub unsafe fn simd_scatter<T, U, V>(val: T, ptr: U, mask: V);
|
||||
|
||||
/// A type for alignment options for SIMD masked load/store intrinsics.
|
||||
#[derive(Debug, ConstParamTy, PartialEq, Eq)]
|
||||
pub enum SimdAlign {
|
||||
// These values must match the compiler's `SimdAlign` defined in
|
||||
// `rustc_middle/src/ty/consts/int.rs`!
|
||||
/// No alignment requirements on the pointer
|
||||
Unaligned = 0,
|
||||
/// The pointer must be aligned to the element type of the SIMD vector
|
||||
Element = 1,
|
||||
/// The pointer must be aligned to the SIMD vector type
|
||||
Vector = 2,
|
||||
}
|
||||
|
||||
/// Reads a vector of pointers.
|
||||
///
|
||||
/// `T` must be a vector.
|
||||
|
|
@ -392,13 +407,12 @@ pub unsafe fn simd_scatter<T, U, V>(val: T, ptr: U, mask: V);
|
|||
/// `val`.
|
||||
///
|
||||
/// # Safety
|
||||
/// Unmasked values in `T` must be readable as if by `<ptr>::read` (e.g. aligned to the element
|
||||
/// type).
|
||||
/// `ptr` must be aligned according to the `ALIGN` parameter, see [`SimdAlign`] for details.
|
||||
///
|
||||
/// `mask` must only contain `0` or `!0` values.
|
||||
#[rustc_intrinsic]
|
||||
#[rustc_nounwind]
|
||||
pub unsafe fn simd_masked_load<V, U, T>(mask: V, ptr: U, val: T) -> T;
|
||||
pub unsafe fn simd_masked_load<V, U, T, const ALIGN: SimdAlign>(mask: V, ptr: U, val: T) -> T;
|
||||
|
||||
/// Writes to a vector of pointers.
|
||||
///
|
||||
|
|
@ -414,13 +428,12 @@ pub unsafe fn simd_masked_load<V, U, T>(mask: V, ptr: U, val: T) -> T;
|
|||
/// Otherwise if the corresponding value in `mask` is `0`, do nothing.
|
||||
///
|
||||
/// # Safety
|
||||
/// Unmasked values in `T` must be writeable as if by `<ptr>::write` (e.g. aligned to the element
|
||||
/// type).
|
||||
/// `ptr` must be aligned according to the `ALIGN` parameter, see [`SimdAlign`] for details.
|
||||
///
|
||||
/// `mask` must only contain `0` or `!0` values.
|
||||
#[rustc_intrinsic]
|
||||
#[rustc_nounwind]
|
||||
pub unsafe fn simd_masked_store<V, U, T>(mask: V, ptr: U, val: T);
|
||||
pub unsafe fn simd_masked_store<V, U, T, const ALIGN: SimdAlign>(mask: V, ptr: U, val: T);
|
||||
|
||||
/// Adds two simd vectors elementwise, with saturation.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -474,7 +474,14 @@ where
|
|||
or: Self,
|
||||
) -> Self {
|
||||
// SAFETY: The safety of reading elements through `ptr` is ensured by the caller.
|
||||
unsafe { core::intrinsics::simd::simd_masked_load(enable.to_int(), ptr, or) }
|
||||
unsafe {
|
||||
core::intrinsics::simd::simd_masked_load::<
|
||||
_,
|
||||
_,
|
||||
_,
|
||||
{ core::intrinsics::simd::SimdAlign::Element },
|
||||
>(enable.to_int(), ptr, or)
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads from potentially discontiguous indices in `slice` to construct a SIMD vector.
|
||||
|
|
@ -723,7 +730,14 @@ where
|
|||
#[inline]
|
||||
pub unsafe fn store_select_ptr(self, ptr: *mut T, enable: Mask<<T as SimdElement>::Mask, N>) {
|
||||
// SAFETY: The safety of writing elements through `ptr` is ensured by the caller.
|
||||
unsafe { core::intrinsics::simd::simd_masked_store(enable.to_int(), ptr, self) }
|
||||
unsafe {
|
||||
core::intrinsics::simd::simd_masked_store::<
|
||||
_,
|
||||
_,
|
||||
_,
|
||||
{ core::intrinsics::simd::SimdAlign::Element },
|
||||
>(enable.to_int(), ptr, self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes the values in a SIMD vector to potentially discontiguous indices in `slice`.
|
||||
|
|
|
|||
|
|
@ -2756,6 +2756,28 @@ impl Path {
|
|||
iter_after(self.components().rev(), child.components().rev()).is_some()
|
||||
}
|
||||
|
||||
/// Checks whether the `Path` is empty.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(path_is_empty)]
|
||||
/// use std::path::Path;
|
||||
///
|
||||
/// let path = Path::new("");
|
||||
/// assert!(path.is_empty());
|
||||
///
|
||||
/// let path = Path::new("foo");
|
||||
/// assert!(!path.is_empty());
|
||||
///
|
||||
/// let path = Path::new(".");
|
||||
/// assert!(!path.is_empty());
|
||||
/// ```
|
||||
#[unstable(feature = "path_is_empty", issue = "148494")]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.as_os_str().is_empty()
|
||||
}
|
||||
|
||||
/// Extracts the stem (non-extension) portion of [`self.file_name`].
|
||||
///
|
||||
/// [`self.file_name`]: Path::file_name
|
||||
|
|
|
|||
|
|
@ -82,3 +82,9 @@ jobs:
|
|||
git add .
|
||||
git commit -m "Deploy ${GITHUB_SHA} to gh-pages"
|
||||
git push --quiet -f "https://x-token:${{ secrets.GITHUB_TOKEN }}@github.com/${GITHUB_REPOSITORY}" HEAD:gh-pages
|
||||
|
||||
- name: Check if files comply with semantic line breaks
|
||||
continue-on-error: true
|
||||
run: |
|
||||
# using split_inclusive that uses regex feature that uses an unstable feature
|
||||
RUSTC_BOOTSTRAP=1 cargo run --manifest-path ci/sembr/Cargo.toml src
|
||||
|
|
|
|||
1
src/doc/rustc-dev-guide/.gitignore
vendored
1
src/doc/rustc-dev-guide/.gitignore
vendored
|
|
@ -1,6 +1,7 @@
|
|||
book
|
||||
|
||||
ci/date-check/target/
|
||||
ci/sembr/target/
|
||||
|
||||
# Generated by check-in.sh
|
||||
pulls.json
|
||||
|
|
|
|||
466
src/doc/rustc-dev-guide/ci/sembr/Cargo.lock
Normal file
466
src/doc/rustc-dev-guide/ci/sembr/Cargo.lock
Normal file
|
|
@ -0,0 +1,466 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"is_terminal_polyfill",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2"
|
||||
dependencies = [
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"once_cell_polyfill",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
|
||||
|
||||
[[package]]
|
||||
name = "bstr"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c2cfd7bf8a6017ddaa4e32ffe7403d547790db06bd171c1c53926faab501623"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a4c05b9e80c5ccd3a7ef080ad7b6ba7d6fc00a985b8b157197075677c82c7a0"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.49"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
|
||||
dependencies = [
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||
|
||||
[[package]]
|
||||
name = "globset"
|
||||
version = "0.4.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"bstr",
|
||||
"log",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
|
||||
dependencies = [
|
||||
"foldhash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "ignore"
|
||||
version = "0.4.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81776e6f9464432afcc28d03e52eb101c93b6f0566f52aef2427663e700f0403"
|
||||
dependencies = [
|
||||
"crossbeam-deque",
|
||||
"globset",
|
||||
"log",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"same-file",
|
||||
"walkdir",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "imara-diff"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f01d462f766df78ab820dd06f5eb700233c51f0f4c2e846520eaf4ba6aa5c5c"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell_polyfill"
|
||||
version = "1.70.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.103"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.12.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sembr"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"ignore",
|
||||
"imara-diff",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_core"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.108"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.60.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.61.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.53.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
|
||||
16
src/doc/rustc-dev-guide/ci/sembr/Cargo.toml
Normal file
16
src/doc/rustc-dev-guide/ci/sembr/Cargo.toml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
[package]
|
||||
name = "sembr"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1"
|
||||
ignore = "0.4"
|
||||
imara-diff = "0.2"
|
||||
|
||||
[dependencies.regex]
|
||||
version = "1"
|
||||
features = ["pattern"]
|
||||
|
||||
[dependencies.clap]
|
||||
version = "4"
|
||||
features = ["derive"]
|
||||
291
src/doc/rustc-dev-guide/ci/sembr/src/main.rs
Normal file
291
src/doc/rustc-dev-guide/ci/sembr/src/main.rs
Normal file
|
|
@ -0,0 +1,291 @@
|
|||
use std::path::PathBuf;
|
||||
use std::sync::LazyLock;
|
||||
use std::{fs, process};
|
||||
|
||||
use anyhow::Result;
|
||||
use clap::Parser;
|
||||
use ignore::Walk;
|
||||
use imara_diff::{Algorithm, BasicLineDiffPrinter, Diff, InternedInput, UnifiedDiffConfig};
|
||||
use regex::Regex;
|
||||
|
||||
#[derive(Parser)]
|
||||
struct Cli {
|
||||
/// File or directory to check
|
||||
path: PathBuf,
|
||||
#[arg(long)]
|
||||
/// Modify files that do not comply
|
||||
overwrite: bool,
|
||||
/// Applies to lines that are to be split
|
||||
#[arg(long, default_value_t = 100)]
|
||||
line_length_limit: usize,
|
||||
#[arg(long)]
|
||||
show_diff: bool,
|
||||
}
|
||||
|
||||
static REGEX_IGNORE: LazyLock<Regex> =
|
||||
LazyLock::new(|| Regex::new(r"^\s*(\d\.|\-|\*)\s+").unwrap());
|
||||
static REGEX_IGNORE_END: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"(\.|\?|;|!)$").unwrap());
|
||||
static REGEX_IGNORE_LINK_TARGETS: LazyLock<Regex> =
|
||||
LazyLock::new(|| Regex::new(r"^\[.+\]: ").unwrap());
|
||||
static REGEX_SPLIT: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"(\.|[^r]\?|;|!)\s+").unwrap());
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let cli = Cli::parse();
|
||||
let mut compliant = Vec::new();
|
||||
let mut not_compliant = Vec::new();
|
||||
let mut made_compliant = Vec::new();
|
||||
for result in Walk::new(cli.path) {
|
||||
let entry = result?;
|
||||
if entry.file_type().expect("no stdin").is_dir() {
|
||||
continue;
|
||||
}
|
||||
let path = entry.into_path();
|
||||
if let Some(extension) = path.extension() {
|
||||
if extension != "md" {
|
||||
continue;
|
||||
}
|
||||
let old = fs::read_to_string(&path)?;
|
||||
let new = lengthen_lines(&comply(&old), cli.line_length_limit);
|
||||
if new == old {
|
||||
compliant.push(path.clone());
|
||||
} else if cli.overwrite {
|
||||
fs::write(&path, new)?;
|
||||
made_compliant.push(path.clone());
|
||||
} else if cli.show_diff {
|
||||
println!("{}:", path.display());
|
||||
show_diff(&old, &new);
|
||||
println!("---");
|
||||
} else {
|
||||
not_compliant.push(path.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
if !compliant.is_empty() {
|
||||
display("compliant", &compliant);
|
||||
}
|
||||
if !made_compliant.is_empty() {
|
||||
display("made compliant", &made_compliant);
|
||||
}
|
||||
if !not_compliant.is_empty() {
|
||||
display("not compliant", ¬_compliant);
|
||||
process::exit(1);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn show_diff(old: &str, new: &str) {
|
||||
let input = InternedInput::new(old, new);
|
||||
let mut diff = Diff::compute(Algorithm::Histogram, &input);
|
||||
diff.postprocess_lines(&input);
|
||||
let diff = diff
|
||||
.unified_diff(&BasicLineDiffPrinter(&input.interner), UnifiedDiffConfig::default(), &input)
|
||||
.to_string();
|
||||
print!("{diff}");
|
||||
}
|
||||
|
||||
fn display(header: &str, paths: &[PathBuf]) {
|
||||
println!("{header}:");
|
||||
for element in paths {
|
||||
println!("- {}", element.display());
|
||||
}
|
||||
}
|
||||
|
||||
fn ignore(line: &str, in_code_block: bool) -> bool {
|
||||
in_code_block
|
||||
|| line.to_lowercase().contains("e.g.")
|
||||
|| line.contains("i.e.")
|
||||
|| line.contains('|')
|
||||
|| line.trim_start().starts_with('>')
|
||||
|| line.starts_with('#')
|
||||
|| line.trim().is_empty()
|
||||
|| REGEX_IGNORE.is_match(line)
|
||||
|| REGEX_IGNORE_LINK_TARGETS.is_match(line)
|
||||
}
|
||||
|
||||
fn comply(content: &str) -> String {
|
||||
let content: Vec<_> = content.lines().map(std::borrow::ToOwned::to_owned).collect();
|
||||
let mut new_content = content.clone();
|
||||
let mut new_n = 0;
|
||||
let mut in_code_block = false;
|
||||
for (n, line) in content.into_iter().enumerate() {
|
||||
if n != 0 {
|
||||
new_n += 1;
|
||||
}
|
||||
if line.trim_start().starts_with("```") {
|
||||
in_code_block = !in_code_block;
|
||||
continue;
|
||||
}
|
||||
if ignore(&line, in_code_block) {
|
||||
continue;
|
||||
}
|
||||
if REGEX_SPLIT.is_match(&line) {
|
||||
let indent = line.find(|ch: char| !ch.is_whitespace()).unwrap();
|
||||
let new_lines: Vec<_> = line
|
||||
.split_inclusive(&*REGEX_SPLIT)
|
||||
.map(|portion| format!("{:indent$}{}", "", portion.trim()))
|
||||
.collect();
|
||||
new_content.splice(new_n..=new_n, new_lines.clone());
|
||||
new_n += new_lines.len() - 1;
|
||||
}
|
||||
}
|
||||
new_content.join("\n") + "\n"
|
||||
}
|
||||
|
||||
fn lengthen_lines(content: &str, limit: usize) -> String {
|
||||
let content: Vec<_> = content.lines().map(std::borrow::ToOwned::to_owned).collect();
|
||||
let mut new_content = content.clone();
|
||||
let mut new_n = 0;
|
||||
let mut in_code_block = false;
|
||||
let mut skip_next = false;
|
||||
for (n, line) in content.iter().enumerate() {
|
||||
if skip_next {
|
||||
skip_next = false;
|
||||
continue;
|
||||
}
|
||||
if n != 0 {
|
||||
new_n += 1;
|
||||
}
|
||||
if line.trim_start().starts_with("```") {
|
||||
in_code_block = !in_code_block;
|
||||
continue;
|
||||
}
|
||||
if ignore(line, in_code_block) || REGEX_SPLIT.is_match(line) {
|
||||
continue;
|
||||
}
|
||||
let Some(next_line) = content.get(n + 1) else {
|
||||
continue;
|
||||
};
|
||||
if ignore(next_line, in_code_block) || REGEX_IGNORE_END.is_match(line) {
|
||||
continue;
|
||||
}
|
||||
if line.len() + next_line.len() < limit {
|
||||
new_content[new_n] = format!("{line} {}", next_line.trim_start());
|
||||
new_content.remove(new_n + 1);
|
||||
skip_next = true;
|
||||
}
|
||||
}
|
||||
new_content.join("\n") + "\n"
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sembr() {
|
||||
let original = "\
|
||||
# some. heading
|
||||
must! be; split? and. normalizes space
|
||||
1. ignore numbered
|
||||
ignore | tables
|
||||
ignore e.g. and
|
||||
ignore i.e. and
|
||||
ignore E.g. too
|
||||
- ignore. list
|
||||
* ignore. list
|
||||
```
|
||||
some code. block
|
||||
```
|
||||
sentence with *italics* should not be ignored. truly.
|
||||
";
|
||||
let expected = "\
|
||||
# some. heading
|
||||
must!
|
||||
be;
|
||||
split?
|
||||
and.
|
||||
normalizes space
|
||||
1. ignore numbered
|
||||
ignore | tables
|
||||
ignore e.g. and
|
||||
ignore i.e. and
|
||||
ignore E.g. too
|
||||
- ignore. list
|
||||
* ignore. list
|
||||
```
|
||||
some code. block
|
||||
```
|
||||
sentence with *italics* should not be ignored.
|
||||
truly.
|
||||
";
|
||||
assert_eq!(expected, comply(original));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_prettify() {
|
||||
let original = "\
|
||||
do not split
|
||||
short sentences
|
||||
";
|
||||
let expected = "\
|
||||
do not split short sentences
|
||||
";
|
||||
assert_eq!(expected, lengthen_lines(original, 50));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_prettify_prefix_spaces() {
|
||||
let original = "\
|
||||
do not split
|
||||
short sentences
|
||||
";
|
||||
let expected = "\
|
||||
do not split short sentences
|
||||
";
|
||||
assert_eq!(expected, lengthen_lines(original, 50));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_prettify_ignore_link_targets() {
|
||||
let original = "\
|
||||
[a target]: https://example.com
|
||||
[another target]: https://example.com
|
||||
";
|
||||
assert_eq!(original, lengthen_lines(original, 100));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sembr_then_prettify() {
|
||||
let original = "\
|
||||
hi there. do
|
||||
not split
|
||||
short sentences.
|
||||
hi again.
|
||||
";
|
||||
let expected = "\
|
||||
hi there.
|
||||
do
|
||||
not split
|
||||
short sentences.
|
||||
hi again.
|
||||
";
|
||||
let processed = comply(original);
|
||||
assert_eq!(expected, processed);
|
||||
let expected = "\
|
||||
hi there.
|
||||
do not split
|
||||
short sentences.
|
||||
hi again.
|
||||
";
|
||||
let processed = lengthen_lines(&processed, 50);
|
||||
assert_eq!(expected, processed);
|
||||
let expected = "\
|
||||
hi there.
|
||||
do not split short sentences.
|
||||
hi again.
|
||||
";
|
||||
let processed = lengthen_lines(&processed, 50);
|
||||
assert_eq!(expected, processed);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sembr_question_mark() {
|
||||
let original = "\
|
||||
o? whatever
|
||||
r? @reviewer
|
||||
r? @reviewer
|
||||
";
|
||||
let expected = "\
|
||||
o?
|
||||
whatever
|
||||
r? @reviewer
|
||||
r? @reviewer
|
||||
";
|
||||
assert_eq!(expected, comply(original));
|
||||
}
|
||||
|
|
@ -1 +1 @@
|
|||
b1b464d6f61ec8c4e609c1328106378c066a9729
|
||||
c5dabe8cf798123087d094f06417f5a767ca73e8
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ The detailed documentation for the `std::autodiff` module is available at [std::
|
|||
Differentiable programming is used in various fields like numerical computing, [solid mechanics][ratel], [computational chemistry][molpipx], [fluid dynamics][waterlily] or for Neural Network training via Backpropagation, [ODE solver][diffsol], [differentiable rendering][libigl], [quantum computing][catalyst], and climate simulations.
|
||||
|
||||
[ratel]: https://gitlab.com/micromorph/ratel
|
||||
[molpipx]: https://arxiv.org/abs/2411.17011v
|
||||
[molpipx]: https://arxiv.org/abs/2411.17011
|
||||
[waterlily]: https://github.com/WaterLily-jl/WaterLily.jl
|
||||
[diffsol]: https://github.com/martinjrobins/diffsol
|
||||
[libigl]: https://github.com/alecjacobson/libigl-enzyme-example?tab=readme-ov-file#run
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
## Bug reports
|
||||
|
||||
While bugs are unfortunate, they're a reality in software. We can't fix what we
|
||||
don't know about, so please report liberally. If you're not sure if something
|
||||
is a bug or not, feel free to file a bug anyway.
|
||||
While bugs are unfortunate, they're a reality in software.
|
||||
We can't fix what we don't know about, so please report liberally.
|
||||
If you're not sure if something is a bug, feel free to open an issue anyway.
|
||||
|
||||
**If you believe reporting your bug publicly represents a security risk to Rust users,
|
||||
please follow our [instructions for reporting security vulnerabilities][vuln]**.
|
||||
|
|
@ -12,16 +12,18 @@ please follow our [instructions for reporting security vulnerabilities][vuln]**.
|
|||
[vuln]: https://www.rust-lang.org/policies/security
|
||||
|
||||
If you're using the nightly channel, please check if the bug exists in the
|
||||
latest toolchain before filing your bug. It might be fixed already.
|
||||
latest toolchain before filing your bug.
|
||||
It might be fixed already.
|
||||
|
||||
If you have the chance, before reporting a bug, please [search existing issues],
|
||||
as it's possible that someone else has already reported your error. This doesn't
|
||||
always work, and sometimes it's hard to know what to search for, so consider this
|
||||
extra credit. We won't mind if you accidentally file a duplicate report.
|
||||
as it's possible that someone else has already reported your error.
|
||||
This doesn't always work, and sometimes it's hard to know what to search for, so consider this
|
||||
extra credit.
|
||||
We won't mind if you accidentally file a duplicate report.
|
||||
|
||||
Similarly, to help others who encountered the bug find your issue, consider
|
||||
filing an issue with a descriptive title, which contains information that might
|
||||
be unique to it. This can be the language or compiler feature used, the
|
||||
filing an issue with a descriptive title, which contains information that might be unique to it.
|
||||
This can be the language or compiler feature used, the
|
||||
conditions that trigger the bug, or part of the error message if there is any.
|
||||
An example could be: **"impossible case reached" on lifetime inference for impl
|
||||
Trait in return position**.
|
||||
|
|
@ -31,14 +33,15 @@ in the appropriate provided template.
|
|||
|
||||
## Bug fixes or "normal" code changes
|
||||
|
||||
For most PRs, no special procedures are needed. You can just [open a PR], and it
|
||||
will be reviewed, approved, and merged. This includes most bug fixes,
|
||||
refactorings, and other user-invisible changes. The next few sections talk
|
||||
about exceptions to this rule.
|
||||
For most PRs, no special procedures are needed.
|
||||
You can just [open a PR], and it will be reviewed, approved, and merged.
|
||||
This includes most bug fixes, refactorings, and other user-invisible changes.
|
||||
The next few sections talk about exceptions to this rule.
|
||||
|
||||
Also, note that it is perfectly acceptable to open WIP PRs or GitHub [Draft PRs].
|
||||
Some people prefer to do this so they can get feedback along the
|
||||
way or share their code with a collaborator. Others do this so they can utilize
|
||||
way or share their code with a collaborator.
|
||||
Others do this so they can utilize
|
||||
the CI to build and test their PR (e.g. when developing on a slow machine).
|
||||
|
||||
[open a PR]: #pull-requests
|
||||
|
|
@ -46,9 +49,9 @@ the CI to build and test their PR (e.g. when developing on a slow machine).
|
|||
|
||||
## New features
|
||||
|
||||
Rust has strong backwards-compatibility guarantees. Thus, new features can't
|
||||
just be implemented directly in stable Rust. Instead, we have 3 release
|
||||
channels: stable, beta, and nightly.
|
||||
Rust has strong backwards-compatibility guarantees.
|
||||
Thus, new features can't just be implemented directly in stable Rust.
|
||||
Instead, we have 3 release channels: stable, beta, and nightly.
|
||||
|
||||
- **Stable**: this is the latest stable release for general usage.
|
||||
- **Beta**: this is the next release (will be stable within 6 weeks).
|
||||
|
|
@ -65,35 +68,36 @@ Breaking changes have a [dedicated section][Breaking Changes] in the dev-guide.
|
|||
|
||||
### Major changes
|
||||
|
||||
The compiler team has a special process for large changes, whether or not they
|
||||
cause breakage. This process is called a Major Change Proposal (MCP). MCP is a
|
||||
relatively lightweight mechanism for getting feedback on large changes to the
|
||||
The compiler team has a special process for large changes, whether or not they cause breakage.
|
||||
This process is called a Major Change Proposal (MCP).
|
||||
MCP is a relatively lightweight mechanism for getting feedback on large changes to the
|
||||
compiler (as opposed to a full RFC or a design meeting with the team).
|
||||
|
||||
Example of things that might require MCPs include major refactorings, changes
|
||||
to important types, or important changes to how the compiler does something, or
|
||||
smaller user-facing changes.
|
||||
|
||||
**When in doubt, ask on [Zulip]. It would be a shame to put a lot of work
|
||||
into a PR that ends up not getting merged!** [See this document][mcpinfo] for
|
||||
more info on MCPs.
|
||||
**When in doubt, ask [on Zulip].
|
||||
It would be a shame to put a lot of work
|
||||
into a PR that ends up not getting merged!** [See this document][mcpinfo] for more info on MCPs.
|
||||
|
||||
[mcpinfo]: https://forge.rust-lang.org/compiler/proposals-and-stabilization.html#how-do-i-submit-an-mcp
|
||||
[zulip]: https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler
|
||||
[on Zulip]: https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler
|
||||
|
||||
### Performance
|
||||
|
||||
Compiler performance is important. We have put a lot of effort over the last
|
||||
few years into [gradually improving it][perfdash].
|
||||
Compiler performance is important.
|
||||
We have put a lot of effort over the last few years into [gradually improving it][perfdash].
|
||||
|
||||
[perfdash]: https://perf.rust-lang.org/dashboard.html
|
||||
|
||||
If you suspect that your change may cause a performance regression (or
|
||||
improvement), you can request a "perf run" (and your reviewer may also request one
|
||||
before approving). This is yet another bot that will compile a collection of
|
||||
benchmarks on a compiler with your changes. The numbers are reported
|
||||
[here][perf], and you can see a comparison of your changes against the latest
|
||||
master.
|
||||
before approving).
|
||||
This is yet another bot that will compile a collection of
|
||||
benchmarks on a compiler with your changes.
|
||||
The numbers are reported
|
||||
[here][perf], and you can see a comparison of your changes against the latest master.
|
||||
|
||||
> For an introduction to the performance of Rust code in general
|
||||
> which would also be useful in rustc development, see [The Rust Performance Book].
|
||||
|
|
@ -104,11 +108,11 @@ master.
|
|||
## Pull requests
|
||||
|
||||
Pull requests (or PRs for short) are the primary mechanism we use to change Rust.
|
||||
GitHub itself has some [great documentation][about-pull-requests] on using the
|
||||
Pull Request feature. We use the "fork and pull" model [described here][development-models],
|
||||
GitHub itself has some [great documentation][about-pull-requests] on using the Pull Request feature.
|
||||
We use the ["fork and pull" model][development-models],
|
||||
where contributors push changes to their personal fork and create pull requests to
|
||||
bring those changes into the source repository. We have more info about how to use git
|
||||
when contributing to Rust under [the git section](./git.md).
|
||||
bring those changes into the source repository.
|
||||
We have [a chapter](git.md) on how to use Git when contributing to Rust.
|
||||
|
||||
> **Advice for potentially large, complex, cross-cutting and/or very domain-specific changes**
|
||||
>
|
||||
|
|
@ -150,7 +154,8 @@ when contributing to Rust under [the git section](./git.md).
|
|||
### Keeping your branch up-to-date
|
||||
|
||||
The CI in rust-lang/rust applies your patches directly against the current master,
|
||||
not against the commit your branch is based on. This can lead to unexpected failures
|
||||
not against the commit your branch is based on.
|
||||
This can lead to unexpected failures
|
||||
if your branch is outdated, even when there are no explicit merge conflicts.
|
||||
|
||||
Update your branch only when needed: when you have merge conflicts, upstream CI is broken and blocking your green PR, or a maintainer requests it.
|
||||
|
|
@ -159,30 +164,31 @@ During review, make incremental commits to address feedback.
|
|||
Prefer to squash or rebase only at the end, or when a reviewer requests it.
|
||||
|
||||
When updating, use `git push --force-with-lease` and leave a brief comment explaining what changed.
|
||||
Some repos prefer merging from `upstream/master` instead of rebasing; follow the project's conventions.
|
||||
Some repos prefer merging from `upstream/master` instead of rebasing;
|
||||
follow the project's conventions.
|
||||
See [keeping things up to date](git.md#keeping-things-up-to-date) for detailed instructions.
|
||||
|
||||
After rebasing, it's recommended to [run the relevant tests locally](tests/intro.md) to catch any issues before CI runs.
|
||||
|
||||
### r?
|
||||
|
||||
All pull requests are reviewed by another person. We have a bot,
|
||||
[@rustbot], that will automatically assign a random person
|
||||
All pull requests are reviewed by another person.
|
||||
We have a bot, [@rustbot], that will automatically assign a random person
|
||||
to review your request based on which files you changed.
|
||||
|
||||
If you want to request that a specific person reviews your pull request, you
|
||||
can add an `r?` to the pull request description or in a comment. For example,
|
||||
if you want to ask a review to @awesome-reviewer, add
|
||||
can add an `r?` to the pull request description or in a comment.
|
||||
For example, if you want to ask a review by @awesome-reviewer,
|
||||
add the following to the end of the pull request description:
|
||||
|
||||
r? @awesome-reviewer
|
||||
|
||||
to the end of the pull request description, and [@rustbot] will assign
|
||||
them instead of a random person. This is entirely optional.
|
||||
[@rustbot] will then assign the PR to that reviewer instead of a random person.
|
||||
This is entirely optional.
|
||||
|
||||
You can also assign a random reviewer from a specific team by writing `r? rust-lang/groupname`.
|
||||
As an example,
|
||||
if you were making a diagnostics change,
|
||||
then you could get a reviewer from the diagnostics team by adding:
|
||||
As an example, if you were making a diagnostics change,
|
||||
you could get a reviewer from the diagnostics team by adding:
|
||||
|
||||
r? rust-lang/diagnostics
|
||||
|
||||
|
|
@ -209,15 +215,15 @@ or the list of teams in the [rust-lang teams database].
|
|||
> the author is ready for a review,
|
||||
> and this PR will be queued again in the reviewer's queue.
|
||||
|
||||
Please note that the reviewers are humans, who for the most part work on `rustc`
|
||||
in their free time. This means that they can take some time to respond and review
|
||||
your PR. It also means that reviewers can miss some PRs that are assigned to them.
|
||||
Please note that the reviewers are humans, who for the most part work on `rustc` in their free time.
|
||||
This means that they can take some time to respond and review your PR.
|
||||
It also means that reviewers can miss some PRs that are assigned to them.
|
||||
|
||||
To try to move PRs forward, the Triage WG regularly goes through all PRs that
|
||||
are waiting for review and haven't been discussed for at least 2 weeks. If you
|
||||
don't get a review within 2 weeks, feel free to ask the Triage WG on
|
||||
Zulip ([#t-release/triage]). They have knowledge of when to ping, who might be
|
||||
on vacation, etc.
|
||||
are waiting for review and haven't been discussed for at least 2 weeks.
|
||||
If you don't get a review within 2 weeks, feel free to ask the Triage WG on
|
||||
Zulip ([#t-release/triage]).
|
||||
They have knowledge of when to ping, who might be on vacation, etc.
|
||||
|
||||
The reviewer may request some changes using the GitHub code review interface.
|
||||
They may also request special procedures for some PRs.
|
||||
|
|
@ -230,7 +236,8 @@ See [Crater] and [Breaking Changes] chapters for some examples of such procedure
|
|||
### CI
|
||||
|
||||
In addition to being reviewed by a human, pull requests are automatically tested,
|
||||
thanks to continuous integration (CI). Basically, every time you open and update
|
||||
thanks to continuous integration (CI).
|
||||
Basically, every time you open and update
|
||||
a pull request, CI builds the compiler and tests it against the
|
||||
[compiler test suite], and also performs other tests such as checking that
|
||||
your pull request is in compliance with Rust's style guidelines.
|
||||
|
|
@ -240,58 +247,64 @@ without going through a first review cycle, and also helps reviewers stay aware
|
|||
of the status of a particular pull request.
|
||||
|
||||
Rust has plenty of CI capacity, and you should never have to worry about wasting
|
||||
computational resources each time you push a change. It is also perfectly fine
|
||||
(and even encouraged!) to use the CI to test your changes if it can help your
|
||||
productivity. In particular, we don't recommend running the full `./x test` suite locally,
|
||||
computational resources each time you push a change.
|
||||
It is also perfectly fine
|
||||
(and even encouraged!) to use the CI to test your changes if it can help your productivity.
|
||||
In particular, we don't recommend running the full `./x test` suite locally,
|
||||
since it takes a very long time to execute.
|
||||
|
||||
### r+
|
||||
|
||||
After someone has reviewed your pull request, they will leave an annotation
|
||||
on the pull request with an `r+`. It will look something like this:
|
||||
on the pull request with an `r+`.
|
||||
It will look something like this:
|
||||
|
||||
@bors r+
|
||||
|
||||
This tells [@bors], our lovable integration bot, that your pull request has
|
||||
been approved. The PR then enters the [merge queue], where [@bors]
|
||||
will run *all* the tests on *every* platform we support. If it all works out,
|
||||
[@bors] will merge your code into `master` and close the pull request.
|
||||
This tells [@bors], our lovable integration bot, that your pull request has been approved.
|
||||
The PR then enters the [merge queue], where [@bors]
|
||||
will run *all* the tests on *every* platform we support.
|
||||
If it all works out, [@bors] will merge your code into `master` and close the pull request.
|
||||
|
||||
Depending on the scale of the change, you may see a slightly different form of `r+`:
|
||||
|
||||
@bors r+ rollup
|
||||
|
||||
The additional `rollup` tells [@bors] that this change should always be "rolled up".
|
||||
Changes that are rolled up are tested and merged alongside other PRs, to
|
||||
speed the process up. Typically only small changes that are expected not to conflict
|
||||
Changes that are rolled up are tested and merged alongside other PRs, to speed the process up.
|
||||
Typically, only small changes that are expected not to conflict
|
||||
with one another are marked as "always roll up".
|
||||
|
||||
Be patient; this can take a while and the queue can sometimes be long. PRs are never merged by hand.
|
||||
Be patient;
|
||||
this can take a while and the queue can sometimes be long.
|
||||
Also, note that PRs are never merged by hand.
|
||||
|
||||
[@rustbot]: https://github.com/rustbot
|
||||
[@bors]: https://github.com/bors
|
||||
|
||||
### Opening a PR
|
||||
|
||||
You are now ready to file a pull request? Great! Here are a few points you
|
||||
should be aware of.
|
||||
You are now ready to file a pull request (PR)?
|
||||
Great!
|
||||
Here are a few points you should be aware of.
|
||||
|
||||
All pull requests should be filed against the `master` branch,
|
||||
unless you know for sure that you should target a different branch.
|
||||
|
||||
Make sure your pull request is in compliance with Rust's style guidelines by running
|
||||
Run some style checks before you submit the PR:
|
||||
|
||||
$ ./x test tidy --bless
|
||||
./x test tidy --bless
|
||||
|
||||
We recommend to make this check before every pull request (and every new commit
|
||||
in a pull request); you can add [git hooks]
|
||||
before every push to make sure you never forget to make this check.
|
||||
We recommend to make this check before every pull request (and every new commit in a pull request);
|
||||
you can add [git hooks] before every push to make sure you never forget to make this check.
|
||||
The CI will also run tidy and will fail if tidy fails.
|
||||
|
||||
Rust follows a _no merge-commit policy_, meaning, when you encounter merge
|
||||
conflicts you are expected to always rebase instead of merging. E.g. always use
|
||||
rebase when bringing the latest changes from the master branch to your feature
|
||||
branch. If your PR contains merge commits, it will get marked as `has-merge-commits`.
|
||||
Rust follows a _no merge-commit policy_,
|
||||
meaning that when you encounter merge conflicts,
|
||||
you are expected to always rebase instead of merging.
|
||||
For example,
|
||||
always use rebase when bringing the latest changes from the master branch to your feature branch.
|
||||
If your PR contains merge commits, it will get marked as `has-merge-commits`.
|
||||
Once you have removed the merge commits, e.g., through an interactive rebase, you
|
||||
should remove the label again:
|
||||
|
||||
|
|
@ -300,13 +313,14 @@ should remove the label again:
|
|||
See [this chapter][labeling] for more details.
|
||||
|
||||
If you encounter merge conflicts or when a reviewer asks you to perform some
|
||||
changes, your PR will get marked as `S-waiting-on-author`. When you resolve
|
||||
them, you should use `@rustbot` to mark it as `S-waiting-on-review`:
|
||||
changes, your PR will get marked as `S-waiting-on-author`.
|
||||
When you resolve them, you should use `@rustbot` to mark it as `S-waiting-on-review`:
|
||||
|
||||
@rustbot ready
|
||||
|
||||
GitHub allows [closing issues using keywords][closing-keywords]. This feature
|
||||
should be used to keep the issue tracker tidy. However, it is generally preferred
|
||||
GitHub allows [closing issues using keywords][closing-keywords].
|
||||
This feature should be used to keep the issue tracker tidy.
|
||||
However, it is generally preferred
|
||||
to put the "closes #123" text in the PR description rather than the issue commit;
|
||||
particularly during rebasing, citing the issue number in the commit can "spam"
|
||||
the issue in question.
|
||||
|
|
@ -319,9 +333,10 @@ Please update the PR description while still mentioning the issue somewhere.
|
|||
For example, you could write `Fixes (after beta backport) #NNN.`.
|
||||
|
||||
As for further actions, please keep a sharp look-out for a PR whose title begins with
|
||||
`[beta]` or `[stable]` and which backports the PR in question. When that one gets
|
||||
merged, the relevant issue can be closed. The closing comment should mention all
|
||||
PRs that were involved. If you don't have the permissions to close the issue, please
|
||||
`[beta]` or `[stable]` and which backports the PR in question.
|
||||
When that one gets merged, the relevant issue can be closed.
|
||||
The closing comment should mention all PRs that were involved.
|
||||
If you don't have the permissions to close the issue, please
|
||||
leave a comment on the original PR asking the reviewer to close it for you.
|
||||
|
||||
[labeling]: ./rustbot.md#issue-relabeling
|
||||
|
|
@ -330,11 +345,13 @@ leave a comment on the original PR asking the reviewer to close it for you.
|
|||
### Reverting a PR
|
||||
|
||||
When a PR leads to miscompile, significant performance regressions, or other critical issues, we may
|
||||
want to revert that PR with a regression test case. You can also check out the [revert policy] on
|
||||
want to revert that PR with a regression test case.
|
||||
You can also check out the [revert policy] on
|
||||
Forge docs (which is mainly targeted for reviewers, but contains useful info for PR authors too).
|
||||
|
||||
If the PR contains huge changes, it can be challenging to revert, making it harder to review
|
||||
incremental fixes in subsequent updates. Or if certain code in that PR is heavily depended upon by
|
||||
incremental fixes in subsequent updates.
|
||||
Or if certain code in that PR is heavily depended upon by
|
||||
subsequent PRs, reverting it can become difficult.
|
||||
|
||||
In such cases, we can identify the problematic code and disable it for some input, as shown in [#128271][#128271].
|
||||
|
|
@ -352,7 +369,8 @@ This section has moved to ["Using External Repositories"](./external-repos.md).
|
|||
|
||||
## Writing documentation
|
||||
|
||||
Documentation improvements are very welcome. The source of `doc.rust-lang.org`
|
||||
Documentation improvements are very welcome.
|
||||
The source of `doc.rust-lang.org`
|
||||
is located in [`src/doc`] in the tree, and standard API documentation is generated
|
||||
from the source code itself (e.g. [`library/std/src/lib.rs`][std-root]). Documentation pull requests
|
||||
function in the same way as other pull requests.
|
||||
|
|
@ -370,8 +388,8 @@ Results should appear in `build/host/doc`, as well as automatically open in your
|
|||
See [Building Documentation](./building/compiler-documenting.md#building-documentation) for more
|
||||
information.
|
||||
|
||||
You can also use `rustdoc` directly to check small fixes. For example,
|
||||
`rustdoc src/doc/reference.md` will render reference to `doc/reference.html`.
|
||||
You can also use `rustdoc` directly to check small fixes.
|
||||
For example, `rustdoc src/doc/reference.md` will render reference to `doc/reference.html`.
|
||||
The CSS might be messed up, but you can verify that the HTML is right.
|
||||
|
||||
Please notice that we don't accept typography/spellcheck fixes to **internal documentation**
|
||||
|
|
@ -389,18 +407,25 @@ There are issues for beginners and advanced compiler devs alike!
|
|||
Just a few things to keep in mind:
|
||||
|
||||
- Please try to avoid overly long lines and use semantic line breaks (where you break the line after each sentence).
|
||||
There is no strict limit on line lengths; let the sentence or part of the sentence flow to its proper end on the same line.
|
||||
There is no strict limit on line lengths;
|
||||
let the sentence or part of the sentence flow to its proper end on the same line.
|
||||
|
||||
You can use a tool in ci/sembr to help with this.
|
||||
Its help output can be seen with this command:
|
||||
|
||||
```console
|
||||
cargo run --manifest-path ci/sembr/Cargo.toml -- --help
|
||||
```
|
||||
|
||||
- When contributing text to the guide, please contextualize the information with some time period
|
||||
and/or a reason so that the reader knows how much to trust the information.
|
||||
Aim to provide a reasonable amount of context, possibly including but not limited to:
|
||||
|
||||
- A reason for why the data may be out of date other than "change",
|
||||
- A reason for why the text may be out of date other than "change",
|
||||
as change is a constant across the project.
|
||||
|
||||
- The date the comment was added, e.g. instead of writing _"Currently, ..."_
|
||||
or _"As of now, ..."_,
|
||||
consider adding the date, in one of the following formats:
|
||||
or _"As of now, ..."_, consider adding the date, in one of the following formats:
|
||||
- Jan 2021
|
||||
- January 2021
|
||||
- jan 2021
|
||||
|
|
@ -410,24 +435,23 @@ Just a few things to keep in mind:
|
|||
that generates a monthly report showing those that are over 6 months old
|
||||
([example](https://github.com/rust-lang/rustc-dev-guide/issues/2052)).
|
||||
|
||||
For the action to pick the date,
|
||||
add a special annotation before specifying the date:
|
||||
For the action to pick the date, add a special annotation before specifying the date:
|
||||
|
||||
```md
|
||||
<!-- date-check --> Apr 2025
|
||||
<!-- date-check --> Nov 2025
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```md
|
||||
As of <!-- date-check --> Apr 2025, the foo did the bar.
|
||||
As of <!-- date-check --> Nov 2025, the foo did the bar.
|
||||
```
|
||||
|
||||
For cases where the date should not be part of the visible rendered output,
|
||||
use the following instead:
|
||||
|
||||
```md
|
||||
<!-- date-check: Apr 2025 -->
|
||||
<!-- date-check: Nov 2025 -->
|
||||
```
|
||||
|
||||
- A link to a relevant WG, tracking issue, `rustc` rustdoc page, or similar, that may provide
|
||||
|
|
@ -435,8 +459,7 @@ Just a few things to keep in mind:
|
|||
outdated.
|
||||
|
||||
- If a text grows rather long (more than a few page scrolls) or complicated (more than four
|
||||
subsections),
|
||||
it might benefit from having a Table of Contents at the beginning,
|
||||
subsections), it might benefit from having a Table of Contents at the beginning,
|
||||
which you can auto-generate by including the `<!-- toc -->` marker at the top.
|
||||
|
||||
#### ⚠️ Note: Where to contribute `rustc-dev-guide` changes
|
||||
|
|
|
|||
|
|
@ -7,18 +7,18 @@ 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 catch 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
|
||||
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 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.
|
||||
|
||||
If you want to modify what gets executed on CI, see [Modifying CI
|
||||
jobs](#modifying-ci-jobs).
|
||||
If you want to modify what gets executed on CI, see [Modifying CI jobs](#modifying-ci-jobs).
|
||||
|
||||
## CI workflow
|
||||
|
||||
|
|
@ -26,10 +26,10 @@ jobs](#modifying-ci-jobs).
|
|||
|
||||
Our CI is primarily executed on [GitHub Actions], with a single workflow defined
|
||||
in [`.github/workflows/ci.yml`], which contains a bunch of steps that are
|
||||
unified for all CI jobs that we execute. When a commit is pushed to a
|
||||
corresponding branch or a PR, the workflow executes the
|
||||
[`src/ci/citool`] crate, which dynamically generates the specific CI
|
||||
jobs that should be executed. This script uses the [`jobs.yml`] file as an
|
||||
unified for all CI jobs that we execute.
|
||||
When a commit is pushed to a corresponding branch or a PR, the workflow executes the
|
||||
[`src/ci/citool`] crate, which dynamically generates the specific CI jobs that should be executed.
|
||||
This script uses the [`jobs.yml`] file as an
|
||||
input, which contains a declarative configuration of all our CI jobs.
|
||||
|
||||
> Almost all build steps shell out to separate scripts. This keeps the CI fairly
|
||||
|
|
@ -38,21 +38,22 @@ 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
|
||||
platforms. There are two broad categories of jobs that are executed, `dist` and
|
||||
non-`dist` jobs.
|
||||
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
|
||||
with the [rustup-toolchain-install-master] tool.
|
||||
The same builds are also used
|
||||
for actual releases: our release process basically consists of copying those
|
||||
artifacts from `rust-lang-ci2` to the production endpoint and signing them.
|
||||
- Non-dist jobs run our full test suite on the platform, and the test suite of
|
||||
all the tools we ship through rustup; The amount of stuff we test depends on
|
||||
all the tools we ship through rustup;
|
||||
The amount of stuff we test depends on
|
||||
the platform (for example some tests are run only on Tier 1 platforms), and
|
||||
some quicker platforms are grouped together on the same builder to avoid
|
||||
wasting CI resources.
|
||||
some quicker platforms are grouped together on the same builder to avoid wasting CI resources.
|
||||
|
||||
Based on an input event (usually a push to a branch), we execute one of three
|
||||
kinds of builds (sets of jobs).
|
||||
|
|
@ -65,13 +66,15 @@ kinds of builds (sets of jobs).
|
|||
|
||||
### Pull Request builds
|
||||
|
||||
After each push to a pull request, a set of `pr` jobs are executed. Currently,
|
||||
these execute the `x86_64-gnu-llvm-X`, `x86_64-gnu-tools`, `pr-check-1`, `pr-check-2`
|
||||
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
|
||||
After each push to a pull request, a set of `pr` jobs are executed.
|
||||
Currently, these execute the `x86_64-gnu-llvm-X`, `x86_64-gnu-tools`, `pr-check-1`, `pr-check-2`
|
||||
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
|
||||
compiler using a *system* version of LLVM. Unfortunately, it would take too many
|
||||
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.
|
||||
|
||||
> **Note on doc comments**
|
||||
|
|
@ -84,27 +87,28 @@ resources to run the full test suite for each commit on every PR.
|
|||
> Thus, it is a good idea to run `./x doc xxx` locally for any doc comment
|
||||
> changes to help catch these early.
|
||||
|
||||
PR jobs are defined in the `pr` section of [`jobs.yml`]. Their results can be observed
|
||||
PR jobs are defined in the `pr` section of [`jobs.yml`].
|
||||
Their results can be observed
|
||||
directly on the PR, in the "CI checks" section at the bottom of the PR page.
|
||||
|
||||
### Auto builds
|
||||
|
||||
Before a commit can be merged into the `master` branch, it needs to pass our
|
||||
complete test suite. We call this an `auto` build. This build runs tens of CI
|
||||
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.
|
||||
Before a commit can be merged into the `master` branch, it needs to pass our complete test suite.
|
||||
We call this an `auto` build.
|
||||
This build runs tens of CI 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;
|
||||
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,
|
||||
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 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 in [Merging PRs serially with bors](#merging-prs-serially-with-bors).
|
||||
At any given time, at most a single `auto` build is being executed.
|
||||
Find out 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
|
||||
|
||||
|
|
@ -112,7 +116,8 @@ more in [Merging PRs serially with bors](#merging-prs-serially-with-bors).
|
|||
|
||||
Sometimes we want to run a subset of the test suite on CI for a given PR, or
|
||||
build a set of compiler artifacts from that PR, without attempting to merge it.
|
||||
We call this a "try build". A try build is started after a user with the proper
|
||||
We call this a "try build".
|
||||
A try build is started after a user with the proper
|
||||
permissions posts a PR comment with the `@bors try` command.
|
||||
|
||||
There are several use-cases for try builds:
|
||||
|
|
@ -121,9 +126,9 @@ There are several use-cases for try builds:
|
|||
For this, a working compiler build is needed, which can be generated with a
|
||||
try build that runs the [dist-x86_64-linux] CI job, which builds an optimized
|
||||
version of the compiler on Linux (this job is currently executed by default
|
||||
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.
|
||||
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](crater.md) run.
|
||||
Again, a working compiler build is needed for this, which can be produced by
|
||||
the [dist-x86_64-linux] CI job.
|
||||
|
|
@ -131,25 +136,32 @@ There are several use-cases for try builds:
|
|||
passes the test suite executed by that job.
|
||||
|
||||
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
|
||||
[`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,
|
||||
even if it might not be working fully correctly. If you want to do a full build for the default try job,
|
||||
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 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: <job pattern>` directives to the PR description (described below) and then
|
||||
simply run `@bors try`. CI will read these directives and run the jobs that you have specified. This is
|
||||
simply run `@bors try`.
|
||||
CI will read these directives and run the jobs that you have specified.
|
||||
This is
|
||||
useful if you want to rerun the same set of try jobs multiple times, after incrementally modifying a PR.
|
||||
- You can specify the job pattern using the `jobs` parameter of the try command: `@bors try jobs=<job pattern>`.
|
||||
This is useful for one-off try builds with specific jobs. Note that the `jobs` parameter has a higher priority
|
||||
than the PR description directives.
|
||||
This is useful for one-off try builds with specific jobs.
|
||||
Note that the `jobs` parameter has a higher priority than the PR description directives.
|
||||
- There can also be multiple patterns specified, e.g. `@bors try jobs=job1,job2,job3`.
|
||||
|
||||
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
|
||||
for example `*msvc*` or `*-alt`.
|
||||
You can start at most 20 jobs in a single try build.
|
||||
When using
|
||||
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.
|
||||
|
|
@ -208,20 +220,20 @@ 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.
|
||||
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.
|
||||
|
||||
You can perform an arbitrary CI job in two ways:
|
||||
- Use the [try build](#try-builds) functionality, and specify the CI jobs that
|
||||
you want to be executed in try builds in your PR description.
|
||||
- Modify the [`pr`](#pull-request-builds) section of `jobs.yml` to specify which
|
||||
CI jobs should be executed after each push to your PR. This might be faster
|
||||
than repeatedly starting try builds.
|
||||
CI jobs should be executed after each push to your PR.
|
||||
This might be faster than repeatedly starting try builds.
|
||||
|
||||
To modify the jobs executed after each push to a PR, you can simply copy one of
|
||||
the job definitions from the `auto` section to the `pr` section. For example,
|
||||
the `x86_64-msvc` job is responsible for running the 64-bit MSVC tests. You can
|
||||
copy it to the `pr` section to cause it to be executed after a commit is pushed
|
||||
the job definitions from the `auto` section to the `pr` section.
|
||||
For example, the `x86_64-msvc` job is responsible for running the 64-bit MSVC tests.
|
||||
You can copy it to the `pr` section to cause it to be executed after a commit is pushed
|
||||
to your PR, like this:
|
||||
|
||||
```yaml
|
||||
|
|
@ -238,8 +250,8 @@ pr:
|
|||
<<: *job-windows-8c
|
||||
```
|
||||
|
||||
Then you can commit the file and push it to your PR branch on GitHub. GitHub
|
||||
Actions should then execute this CI job after each push to your PR.
|
||||
Then you can commit the file and push it to your PR branch on GitHub.
|
||||
GitHub Actions should then execute this CI job after each push to your PR.
|
||||
|
||||
<div class="warning">
|
||||
|
||||
|
|
@ -247,12 +259,12 @@ Actions should then execute this CI job after each push to your PR.
|
|||
you have made to `jobs.yml`, if they were supposed to be temporary!**
|
||||
|
||||
A good practice is to prefix `[WIP]` in PR title while still running try jobs
|
||||
and `[DO NOT MERGE]` in the commit that modifies the CI jobs for testing
|
||||
purposes.
|
||||
and `[DO NOT MERGE]` in the commit that modifies the CI jobs for testing purposes.
|
||||
</div>
|
||||
|
||||
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;
|
||||
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
|
||||
|
|
@ -265,26 +277,28 @@ after the build happened.
|
|||
|
||||
To ensure a `master` branch that works all the time, we forbid manual merges.
|
||||
Instead, all PRs have to be approved through our bot, [bors] (the software
|
||||
behind it is called [homu]). All the approved PRs are put in a [merge queue]
|
||||
(sorted by priority and creation date) and are automatically tested one at the
|
||||
time. If all the builders are green, the PR is merged, otherwise the failure is
|
||||
behind it is called [homu]).
|
||||
All the approved PRs are put in a [merge queue]
|
||||
(sorted by priority and creation date) and are automatically tested one at the time.
|
||||
If all the builders are green, the PR is merged, otherwise the failure is
|
||||
recorded and the PR will have to be re-approved again.
|
||||
|
||||
Bors doesn’t interact with CI services directly, but it works by pushing the
|
||||
merge commit it wants to test to specific branches (like `auto` or `try`), which
|
||||
are configured to execute CI checks. Bors then detects the outcome of the build
|
||||
by listening for either Commit Statuses or Check Runs. Since the merge commit is
|
||||
are configured to execute CI checks.
|
||||
Bors then detects the outcome of the build 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 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.
|
||||
single failure greatly impacts our throughput.
|
||||
The maximum number of PRs we can merge in a day is around ~10.
|
||||
|
||||
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:
|
||||
to the fact that full release artifacts are built in the `dist-` builders.
|
||||
This is worth it because these release artifacts:
|
||||
|
||||
- Allow perf testing even at a later date.
|
||||
- Allow bisection when bugs are discovered later.
|
||||
|
|
@ -295,23 +309,23 @@ 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 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.
|
||||
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.
|
||||
|
||||
## Docker
|
||||
|
||||
All CI jobs, except those on macOS and Windows, are executed inside that
|
||||
platform’s custom [Docker container]. This has a lot of advantages for us:
|
||||
platform’s custom [Docker container].
|
||||
This has a lot of advantages for us:
|
||||
|
||||
- The build environment is consistent regardless of the changes of the
|
||||
underlying image (switching from the trusty image to xenial was painless for
|
||||
us).
|
||||
underlying image (switching from the trusty image to xenial was painless 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.
|
||||
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,
|
||||
thanks to Docker image caching.
|
||||
- Users can run the same tests in the same environment locally by just running this command:
|
||||
|
|
@ -325,13 +339,11 @@ platform’s custom [Docker container]. This has a lot of advantages for us:
|
|||
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 we just cross-compile if we don’t want to run the tests for that
|
||||
platform.
|
||||
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 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
|
||||
for us by GitHub.
|
||||
These builders are running on a special pool of builders set up and maintained for us by GitHub.
|
||||
|
||||
[Docker container]: https://github.com/rust-lang/rust/tree/HEAD/src/ci/docker
|
||||
|
||||
|
|
@ -341,16 +353,16 @@ Our CI workflow uses various caching mechanisms, mainly for two things:
|
|||
|
||||
### Docker images caching
|
||||
|
||||
The Docker images we use to run most of the Linux-based builders take a *long*
|
||||
time to fully build. To speed up the build, we cache them using [Docker registry
|
||||
caching], with the intermediate artifacts being stored on [ghcr.io]. We also
|
||||
push the built Docker images to ghcr, so that they can be reused by other tools
|
||||
(rustup) or by developers running the Docker build locally (to speed up their
|
||||
build).
|
||||
The Docker images we use to run most of the Linux-based builders take a *long* time to fully build.
|
||||
To speed up the build, we cache them using [Docker registry
|
||||
caching], with the intermediate artifacts being stored on [ghcr.io].
|
||||
We also push the built Docker images to ghcr, so that they can be reused by other tools
|
||||
(rustup) or by developers running the Docker build locally (to speed up their build).
|
||||
|
||||
Since we test multiple, diverged branches (`master`, `beta` and `stable`), we
|
||||
can’t rely on a single cache for the images, otherwise builds on a branch would
|
||||
override the cache for the others. Instead, we store the images under different
|
||||
override the cache for the others.
|
||||
Instead, we store the images under different
|
||||
tags, identifying them with a custom hash made from the contents of all the
|
||||
Dockerfiles and related scripts.
|
||||
|
||||
|
|
@ -367,17 +379,17 @@ invalidated if one of the following changes:
|
|||
### LLVM caching with Sccache
|
||||
|
||||
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
|
||||
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
|
||||
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.
|
||||
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.
|
||||
|
||||
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++
|
||||
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.
|
||||
|
||||
|
|
@ -396,26 +408,28 @@ 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
|
||||
before.
|
||||
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 before.
|
||||
|
||||
[rla]: https://github.com/rust-lang/rust-log-analyzer
|
||||
|
||||
### Toolstate to support allowed failures
|
||||
|
||||
The `rust-lang/rust` repo doesn’t only test the compiler on its CI, but also a
|
||||
variety of tools and documentation. Some documentation is pulled in via git
|
||||
submodules. If we blocked merging rustc PRs on the documentation being fixed, we
|
||||
variety of tools and documentation.
|
||||
Some documentation is pulled in via git submodules.
|
||||
If we blocked merging rustc PRs on the documentation being fixed, we
|
||||
would be stuck in a chicken-and-egg problem, because the documentation's CI
|
||||
would not pass since updating it would need the not-yet-merged version of rustc
|
||||
to test against (and we usually require CI to be passing).
|
||||
|
||||
To avoid the problem, submodules are allowed to fail, and their status is
|
||||
recorded in [rust-toolstate]. When a submodule breaks, a bot automatically pings
|
||||
recorded in [rust-toolstate].
|
||||
When a submodule breaks, a bot automatically pings
|
||||
the maintainers so they know about the breakage, and it records the failure on
|
||||
the toolstate repository. The release process will then ignore broken tools on
|
||||
the toolstate repository.
|
||||
The release process will then ignore broken tools on
|
||||
nightly, removing them from the shipped nightlies.
|
||||
|
||||
While tool failures are allowed most of the time, they’re automatically
|
||||
|
|
@ -448,8 +462,8 @@ To learn more about the dashboard, see the [Datadog CI docs].
|
|||
## Determining the CI configuration
|
||||
|
||||
If you want to determine which `bootstrap.toml` settings are used in CI for a
|
||||
particular job, it is probably easiest to just look at the build log. To do
|
||||
this:
|
||||
particular job, it is probably easiest to just look at the build log.
|
||||
To do this:
|
||||
|
||||
1. Go to
|
||||
<https://github.com/rust-lang/rust/actions?query=branch%3Aauto+is%3Asuccess>
|
||||
|
|
|
|||
|
|
@ -21,7 +21,8 @@ you can use the following command to run UI tests locally using the GCC backend,
|
|||
|
||||
If a different test suite has failed on CI, you will have to modify the `tests/ui` part.
|
||||
|
||||
To reproduce the whole CI job locally, you can run `cargo run --manifest-path src/ci/citool/Cargo.toml run-local x86_64-gnu-gcc`. See [Testing with Docker](../docker.md) for more information.
|
||||
To reproduce the whole CI job locally, you can run `cargo run --manifest-path src/ci/citool/Cargo.toml run-local x86_64-gnu-gcc`.
|
||||
See [Testing with Docker](../docker.md) for more information.
|
||||
|
||||
### What to do in case of a GCC job failure?
|
||||
|
||||
|
|
@ -32,23 +33,26 @@ If fixing a compiler test that fails with the GCC backend is non-trivial, you ca
|
|||
## 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`:
|
||||
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:
|
||||
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
|
||||
*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
|
||||
|
|
@ -69,7 +73,8 @@ Note that in order for this to work, the tested compiler must have the GCC codeg
|
|||
## 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
|
||||
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.
|
||||
|
||||
## Running tests of the backend itself
|
||||
|
|
|
|||
|
|
@ -1,16 +1,15 @@
|
|||
# `minicore` test auxiliary: using `core` stubs
|
||||
|
||||
<!-- date-check Oct 2024 -->
|
||||
<!-- date-check: Oct 2025 -->
|
||||
|
||||
[`tests/auxiliary/minicore.rs`][`minicore`] is a test auxiliary for
|
||||
ui/codegen/assembly test suites. It provides `core` stubs for tests that need to
|
||||
[`tests/auxiliary/minicore.rs`][`minicore`] is a test auxiliary for ui/codegen/assembly test suites.
|
||||
It provides `core` stubs for tests that need to
|
||||
build for cross-compiled targets but do not need/want to run.
|
||||
|
||||
<div class="warning">
|
||||
|
||||
Please note that [`minicore`] is only intended for `core` items, and explicitly
|
||||
**not** `std` or `alloc` items because `core` items are applicable to a wider
|
||||
range of tests.
|
||||
**not** `std` or `alloc` items because `core` items are applicable to a wider range of tests.
|
||||
|
||||
</div>
|
||||
|
||||
|
|
@ -41,8 +40,8 @@ by more than one test.
|
|||
|
||||
## Staying in sync with `core`
|
||||
|
||||
The `minicore` items must be kept up to date with `core`. For consistent
|
||||
diagnostic output between using `core` and `minicore`, any `diagnostic`
|
||||
The `minicore` items must be kept up to date with `core`.
|
||||
For consistent diagnostic output between using `core` and `minicore`, any `diagnostic`
|
||||
attributes (e.g. `on_unimplemented`) should be replicated exactly in `minicore`.
|
||||
|
||||
## Example codegen test that uses `minicore`
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
# Walkthrough: a typical contribution
|
||||
|
||||
There are _a lot_ of ways to contribute to the Rust compiler, including fixing
|
||||
bugs, improving performance, helping design features, providing feedback on
|
||||
existing features, etc. This chapter does not claim to scratch the surface.
|
||||
Instead, it walks through the design and implementation of a new feature. Not
|
||||
all of the steps and processes described here are needed for every
|
||||
bugs, improving performance, helping design features, providing feedback on existing features, etc.
|
||||
This chapter does not claim to scratch the surface.
|
||||
Instead, it walks through the design and implementation of a new feature.
|
||||
Not all of the steps and processes described here are needed for every
|
||||
contribution, and I will try to point those out as they arise.
|
||||
|
||||
In general, if you are interested in making a contribution and aren't sure
|
||||
|
|
@ -12,8 +12,8 @@ where to start, please feel free to ask!
|
|||
|
||||
## Overview
|
||||
|
||||
The feature I will discuss in this chapter is the `?` Kleene operator for
|
||||
macros. Basically, we want to be able to write something like this:
|
||||
The feature I will discuss in this chapter is the `?` Kleene operator for macros.
|
||||
Basically, we want to be able to write something like this:
|
||||
|
||||
```rust,ignore
|
||||
macro_rules! foo {
|
||||
|
|
@ -36,25 +36,30 @@ fn main() {
|
|||
So basically, the `$(pat)?` matcher in the macro means "this pattern can occur
|
||||
0 or 1 times", similar to other regex syntaxes.
|
||||
|
||||
There were a number of steps to go from an idea to stable Rust feature. Here is
|
||||
a quick list. We will go through each of these in order below. As I mentioned
|
||||
before, not all of these are needed for every type of contribution.
|
||||
There were a number of steps to go from an idea to stable Rust feature.
|
||||
Here is a quick list.
|
||||
We will go through each of these in order below.
|
||||
As I mentioned before, not all of these are needed for every type of contribution.
|
||||
|
||||
- **Idea discussion/Pre-RFC** A Pre-RFC is an early draft or design discussion
|
||||
of a feature. This stage is intended to flesh out the design space a bit and
|
||||
get a grasp on the different merits and problems with an idea. It's a great
|
||||
way to get early feedback on your idea before presenting it to the wider
|
||||
audience. You can find the original discussion [here][prerfc].
|
||||
of a feature.
|
||||
This stage is intended to flesh out the design space a bit and
|
||||
get a grasp on the different merits and problems with an idea.
|
||||
It's a great way to get early feedback on your idea before presenting it to the wider
|
||||
audience.
|
||||
You can find the original discussion [here][prerfc].
|
||||
- **RFC** This is when you formally present your idea to the community for
|
||||
consideration. You can find the RFC [here][rfc].
|
||||
consideration.
|
||||
You can find the RFC [here][rfc].
|
||||
- **Implementation** Implement your idea unstably in the compiler. You can
|
||||
find the original implementation [here][impl1].
|
||||
- **Possibly iterate/refine** As the community gets experience with your
|
||||
feature on the nightly compiler and in `std`, there may be additional
|
||||
feedback about design choice that might be adjusted. This particular feature
|
||||
went [through][impl2] a [number][impl3] of [iterations][impl4].
|
||||
feedback about design choice that might be adjusted.
|
||||
This particular feature went [through][impl2] a [number][impl3] of [iterations][impl4].
|
||||
- **Stabilization** When your feature has baked enough, a Rust team member may
|
||||
[propose to stabilize it][merge]. If there is consensus, this is done.
|
||||
[propose to stabilize it][merge].
|
||||
If there is consensus, this is done.
|
||||
- **Relax** Your feature is now a stable Rust feature!
|
||||
|
||||
[prerfc]: https://internals.rust-lang.org/t/pre-rfc-at-most-one-repetition-macro-patterns/6557
|
||||
|
|
@ -75,58 +80,63 @@ before, not all of these are needed for every type of contribution.
|
|||
|
||||
[rfcwhen]: https://github.com/rust-lang/rfcs#when-you-need-to-follow-this-process
|
||||
|
||||
An RFC is a document that describes the feature or change you are proposing in
|
||||
detail. Anyone can write an RFC; the process is the same for everyone,
|
||||
including Rust team members.
|
||||
An RFC is a document that describes the feature or change you are proposing in detail.
|
||||
Anyone can write an RFC;
|
||||
the process is the same for everyone, including Rust team members.
|
||||
|
||||
To open an RFC, open a PR on the
|
||||
[rust-lang/rfcs](https://github.com/rust-lang/rfcs) repo on GitHub. You can
|
||||
find detailed instructions in the
|
||||
To open an RFC, open a PR on the [rust-lang/rfcs](https://github.com/rust-lang/rfcs) repo on GitHub.
|
||||
You can find detailed instructions in the
|
||||
[README](https://github.com/rust-lang/rfcs#what-the-process-is).
|
||||
|
||||
Before opening an RFC, you should do the research to "flesh out" your idea.
|
||||
Hastily-proposed RFCs tend not to be accepted. You should generally have a good
|
||||
description of the motivation, impact, disadvantages, and potential
|
||||
Hastily-proposed RFCs tend not to be accepted.
|
||||
You should generally have a good description of the motivation, impact, disadvantages, and potential
|
||||
interactions with other features.
|
||||
|
||||
If that sounds like a lot of work, it's because it is. But no fear! Even if
|
||||
you're not a compiler hacker, you can get great feedback by doing a _pre-RFC_.
|
||||
This is an _informal_ discussion of the idea. The best place to do this is
|
||||
internals.rust-lang.org. Your post doesn't have to follow any particular
|
||||
structure. It doesn't even need to be a cohesive idea. Generally, you will get
|
||||
tons of feedback that you can integrate back to produce a good RFC.
|
||||
If that sounds like a lot of work, it's because it is.
|
||||
But no fear!
|
||||
Even if you're not a compiler hacker, you can get great feedback by doing a _pre-RFC_.
|
||||
This is an _informal_ discussion of the idea.
|
||||
The best place to do this is internals.rust-lang.org.
|
||||
Your post doesn't have to follow any particular structure.
|
||||
It doesn't even need to be a cohesive idea.
|
||||
Generally, you will get tons of feedback that you can integrate back to produce a good RFC.
|
||||
|
||||
(Another pro-tip: try searching the RFCs repo and internals for prior related
|
||||
ideas. A lot of times an idea has already been considered and was either
|
||||
rejected or postponed to be tried again later. This can save you and everybody
|
||||
else some time)
|
||||
(Another pro-tip: try searching the RFCs repo and internals for prior related ideas.
|
||||
A lot of times an idea has already been considered and was either
|
||||
rejected or postponed to be tried again later.
|
||||
This can save you and everybody else some time)
|
||||
|
||||
In the case of our example, a participant in the pre-RFC thread pointed out a
|
||||
syntax ambiguity and a potential resolution. Also, the overall feedback seemed
|
||||
positive. In this case, the discussion converged pretty quickly, but for some
|
||||
syntax ambiguity and a potential resolution.
|
||||
Also, the overall feedback seemed positive.
|
||||
In this case, the discussion converged pretty quickly, but for some
|
||||
ideas, a lot more discussion can happen (e.g. see [this RFC][nonascii] which
|
||||
received a whopping 684 comments!). If that happens, don't be discouraged; it
|
||||
means the community is interested in your idea, but it perhaps needs some
|
||||
received a whopping 684 comments!).
|
||||
If that happens, don't be discouraged;
|
||||
it means the community is interested in your idea, but it perhaps needs some
|
||||
adjustments.
|
||||
|
||||
[nonascii]: https://github.com/rust-lang/rfcs/pull/2457
|
||||
|
||||
The RFC for our `?` macro feature did receive some discussion on the RFC thread
|
||||
too. As with most RFCs, there were a few questions that we couldn't answer by
|
||||
discussion: we needed experience using the feature to decide. Such questions
|
||||
are listed in the "Unresolved Questions" section of the RFC. Also, over the
|
||||
course of the RFC discussion, you will probably want to update the RFC document
|
||||
The RFC for our `?` macro feature did receive some discussion on the RFC thread too.
|
||||
As with most RFCs, there were a few questions that we couldn't answer by
|
||||
discussion: we needed experience using the feature to decide.
|
||||
Such questions are listed in the "Unresolved Questions" section of the RFC.
|
||||
Also, over the course of the RFC discussion, you will probably want to update the RFC document
|
||||
itself to reflect the course of the discussion (e.g. new alternatives or prior
|
||||
work may be added or you may decide to change parts of the proposal itself).
|
||||
|
||||
In the end, when the discussion seems to reach a consensus and die down a bit,
|
||||
a Rust team member may propose to move to "final comment period" (FCP) with one
|
||||
of three possible dispositions. This means that they want the other members of
|
||||
the appropriate teams to review and comment on the RFC. More discussion may
|
||||
ensue, which may result in more changes or unresolved questions being added. At
|
||||
some point, when everyone is satisfied, the RFC enters the FCP, which is the
|
||||
last chance for people to bring up objections. When the FCP is over, the
|
||||
disposition is adopted. Here are the three possible dispositions:
|
||||
of three possible dispositions.
|
||||
This means that they want the other members of
|
||||
the appropriate teams to review and comment on the RFC.
|
||||
More discussion may ensue, which may result in more changes or unresolved questions being added.
|
||||
At some point, when everyone is satisfied, the RFC enters the FCP, which is the
|
||||
last chance for people to bring up objections.
|
||||
When the FCP is over, the disposition is adopted.
|
||||
Here are the three possible dispositions:
|
||||
|
||||
- _Merge_: accept the feature. Here is the proposal to merge for our [`?` macro
|
||||
feature][rfcmerge].
|
||||
|
|
@ -136,14 +146,14 @@ disposition is adopted. Here are the three possible dispositions:
|
|||
will go a different direction.
|
||||
- _Postpone_: there is interest in going this direction but not at the moment.
|
||||
This happens most often because the appropriate Rust team doesn't have the
|
||||
bandwidth to shepherd the feature through the process to stabilization. Often
|
||||
this is the case when the feature doesn't fit into the team's roadmap.
|
||||
bandwidth to shepherd the feature through the process to stabilization.
|
||||
Often this is the case when the feature doesn't fit into the team's roadmap.
|
||||
Postponed ideas may be revisited later.
|
||||
|
||||
[rfcmerge]: https://github.com/rust-lang/rfcs/pull/2298#issuecomment-360582667
|
||||
|
||||
When an RFC is merged, the PR is merged into the RFCs repo. A new _tracking
|
||||
issue_ is created in the [rust-lang/rust] repo to track progress on the feature
|
||||
When an RFC is merged, the PR is merged into the RFCs repo.
|
||||
A new _tracking issue_ is created in the [rust-lang/rust] repo to track progress on the feature
|
||||
and discuss unresolved questions, implementation progress and blockers, etc.
|
||||
Here is the tracking issue on for our [`?` macro feature][tracking].
|
||||
|
||||
|
|
@ -158,93 +168,98 @@ To make a change to the compiler, open a PR against the [rust-lang/rust] repo.
|
|||
[rust-lang/rust]: https://github.com/rust-lang/rust
|
||||
|
||||
Depending on the feature/change/bug fix/improvement, implementation may be
|
||||
relatively-straightforward or it may be a major undertaking. You can always ask
|
||||
for help or mentorship from more experienced compiler devs. Also, you don't
|
||||
have to be the one to implement your feature; but keep in mind that if you
|
||||
don't, it might be a while before someone else does.
|
||||
relatively-straightforward or it may be a major undertaking.
|
||||
You can always ask for help or mentorship from more experienced compiler devs.
|
||||
Also, you don't have to be the one to implement your feature;
|
||||
but keep in mind that if you don't, it might be a while before someone else does.
|
||||
|
||||
For the `?` macro feature, I needed to go understand the relevant parts of
|
||||
macro expansion in the compiler. Personally, I find that [improving the
|
||||
macro expansion in the compiler.
|
||||
Personally, I find that [improving the
|
||||
comments][comments] in the code is a helpful way of making sure I understand
|
||||
it, but you don't have to do that if you don't want to.
|
||||
|
||||
[comments]: https://github.com/rust-lang/rust/pull/47732
|
||||
|
||||
I then [implemented][impl1] the original feature, as described in the RFC. When
|
||||
a new feature is implemented, it goes behind a _feature gate_, which means that
|
||||
you have to use `#![feature(my_feature_name)]` to use the feature. The feature
|
||||
gate is removed when the feature is stabilized.
|
||||
I then [implemented][impl1] the original feature, as described in the RFC.
|
||||
When a new feature is implemented, it goes behind a _feature gate_, which means that
|
||||
you have to use `#![feature(my_feature_name)]` to use the feature.
|
||||
The feature gate is removed when the feature is stabilized.
|
||||
|
||||
**Most bug fixes and improvements** don't require a feature gate. You can just
|
||||
make your changes/improvements.
|
||||
|
||||
When you open a PR on the [rust-lang/rust], a bot will assign your PR to a
|
||||
reviewer. If there is a particular Rust team member you are working with, you can
|
||||
When you open a PR on the [rust-lang/rust], a bot will assign your PR to a reviewer.
|
||||
If there is a particular Rust team member you are working with, you can
|
||||
request that reviewer by leaving a comment on the thread with `r?
|
||||
@reviewer-github-id` (e.g. `r? @eddyb`). If you don't know who to request,
|
||||
don't request anyone; the bot will assign someone automatically based on which files you changed.
|
||||
don't request anyone;
|
||||
the bot will assign someone automatically based on which files you changed.
|
||||
|
||||
The reviewer may request changes before they approve your PR, they may mark the PR with label
|
||||
"S-waiting-on-author" after leaving comments, this means that the PR is blocked on you to make
|
||||
some requested changes. When you finished iterating on the changes, you can mark the PR as
|
||||
some requested changes.
|
||||
When you finished iterating on the changes, you can mark the PR as
|
||||
`S-waiting-on-review` again by leaving a comment with `@rustbot ready`, this will remove the
|
||||
`S-waiting-on-author` label and add the `S-waiting-on-review` label.
|
||||
|
||||
Feel free to ask questions or discuss things you don't understand or disagree with. However,
|
||||
recognize that the PR won't be merged unless someone on the Rust team approves
|
||||
it. If a reviewer leave a comment like `r=me after fixing ...`, that means they approve the PR and
|
||||
Feel free to ask questions or discuss things you don't understand or disagree with.
|
||||
However, recognize that the PR won't be merged unless someone on the Rust team approves
|
||||
it.
|
||||
If a reviewer leave a comment like `r=me after fixing ...`, that means they approve the PR and
|
||||
you can merge it with comment with `@bors r=reviewer-github-id`(e.g. `@bors r=eddyb`) to merge it
|
||||
after fixing trivial issues. Note that `r=someone` requires permission and bors could say
|
||||
something like "🔑 Insufficient privileges..." when commenting `r=someone`. In that case,
|
||||
you have to ask the reviewer to revisit your PR.
|
||||
after fixing trivial issues.
|
||||
Note that `r=someone` requires permission and bors could say
|
||||
something like "🔑 Insufficient privileges..." when commenting `r=someone`.
|
||||
In that case, you have to ask the reviewer to revisit your PR.
|
||||
|
||||
When your reviewer approves the PR, it will go into a queue for yet another bot
|
||||
called `@bors`. `@bors` manages the CI build/merge queue. When your PR reaches
|
||||
the head of the `@bors` queue, `@bors` will test out the merge by running all
|
||||
tests against your PR on GitHub Actions. This takes a lot of time to
|
||||
finish. If all tests pass, the PR is merged and becomes part of the next
|
||||
nightly compiler!
|
||||
When your reviewer approves the PR, it will go into a queue for yet another bot called `@bors`.
|
||||
`@bors` manages the CI build/merge queue.
|
||||
When your PR reaches the head of the `@bors` queue, `@bors` will test out the merge by running all
|
||||
tests against your PR on GitHub Actions.
|
||||
This takes a lot of time to finish.
|
||||
If all tests pass, the PR is merged and becomes part of the next nightly compiler!
|
||||
|
||||
There are a couple of things that may happen for some PRs during the review process
|
||||
|
||||
- If the change is substantial enough, the reviewer may request an FCP on
|
||||
the PR. This gives all members of the appropriate team a chance to review the
|
||||
changes.
|
||||
the PR.
|
||||
This gives all members of the appropriate team a chance to review the changes.
|
||||
- If the change may cause breakage, the reviewer may request a [crater] run.
|
||||
This compiles the compiler with your changes and then attempts to compile all
|
||||
crates on crates.io with your modified compiler. This is a great smoke test
|
||||
crates on crates.io with your modified compiler.
|
||||
This is a great smoke test
|
||||
to check if you introduced a change to compiler behavior that affects a large
|
||||
portion of the ecosystem.
|
||||
- If the diff of your PR is large or the reviewer is busy, your PR may have
|
||||
some merge conflicts with other PRs that happen to get merged first. You
|
||||
should fix these merge conflicts using the normal git procedures.
|
||||
some merge conflicts with other PRs that happen to get merged first.
|
||||
You should fix these merge conflicts using the normal git procedures.
|
||||
|
||||
[crater]: ./tests/crater.html
|
||||
|
||||
If you are not doing a new feature or something like that (e.g. if you are
|
||||
fixing a bug), then that's it! Thanks for your contribution :)
|
||||
fixing a bug), then that's it!
|
||||
Thanks for your contribution :)
|
||||
|
||||
## Refining your implementation
|
||||
|
||||
As people get experience with your new feature on nightly, slight changes may
|
||||
be proposed and unresolved questions may become resolved. Updates/changes go
|
||||
through the same process for implementing any other changes, as described
|
||||
be proposed and unresolved questions may become resolved.
|
||||
Updates/changes go through the same process for implementing any other changes, as described
|
||||
above (i.e. submit a PR, go through review, wait for `@bors`, etc).
|
||||
|
||||
Some changes may be major enough to require an FCP and some review by Rust team
|
||||
members.
|
||||
Some changes may be major enough to require an FCP and some review by Rust team members.
|
||||
|
||||
For the `?` macro feature, we went through a few different iterations after the
|
||||
original implementation: [1][impl2], [2][impl3], [3][impl4].
|
||||
|
||||
Along the way, we decided that `?` should not take a separator, which was
|
||||
previously an unresolved question listed in the RFC. We also changed the
|
||||
disambiguation strategy: we decided to remove the ability to use `?` as a
|
||||
previously an unresolved question listed in the RFC.
|
||||
We also changed the disambiguation strategy: we decided to remove the ability to use `?` as a
|
||||
separator token for other repetition operators (e.g. `+` or `*`). However,
|
||||
since this was a breaking change, we decided to do it over an edition boundary.
|
||||
Thus, the new feature can be enabled only in edition 2018. These deviations
|
||||
from the original RFC required [another
|
||||
FCP](https://github.com/rust-lang/rust/issues/51934).
|
||||
from the original RFC required [another FCP](https://github.com/rust-lang/rust/issues/51934).
|
||||
|
||||
## Stabilization
|
||||
|
||||
|
|
@ -264,8 +279,8 @@ The stabilization report for our feature is [here][stabrep].
|
|||
[stabrep]: https://github.com/rust-lang/rust/issues/48075#issuecomment-433243048
|
||||
|
||||
After this, [a PR is made][stab] to remove the feature gate, enabling the feature by
|
||||
default (on the 2018 edition). A note is added to the [Release notes][relnotes]
|
||||
about the feature.
|
||||
default (on the 2018 edition).
|
||||
A note is added to the [Release notes][relnotes] about the feature.
|
||||
|
||||
[stab]: https://github.com/rust-lang/rust/pull/56245
|
||||
|
||||
|
|
|
|||
|
|
@ -264,9 +264,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
|
|||
</pre>\
|
||||
</div>",
|
||||
added_classes = added_classes.join(" "),
|
||||
text = Escape(
|
||||
original_text.strip_suffix('\n').unwrap_or(&original_text)
|
||||
),
|
||||
text = Escape(original_text.trim_suffix('\n')),
|
||||
)
|
||||
.into(),
|
||||
));
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@ impl SourceCollector<'_, '_> {
|
|||
};
|
||||
|
||||
// Remove the utf-8 BOM if any
|
||||
let contents = contents.strip_prefix('\u{feff}').unwrap_or(&contents);
|
||||
let contents = contents.trim_prefix('\u{feff}');
|
||||
|
||||
let shared = &self.cx.shared;
|
||||
// Create the intermediate directories
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#![feature(iter_order_by)]
|
||||
#![feature(rustc_private)]
|
||||
#![feature(test)]
|
||||
#![feature(trim_prefix_suffix)]
|
||||
#![warn(rustc::internal)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
#![feature(core_intrinsics, portable_simd)]
|
||||
|
||||
use std::intrinsics::simd::*;
|
||||
use std::simd::*;
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let buf = [0u32; 5];
|
||||
//~v ERROR: accessing memory with alignment
|
||||
simd_masked_load::<_, _, _, { SimdAlign::Element }>(
|
||||
i32x4::splat(-1),
|
||||
// This is not i32-aligned
|
||||
buf.as_ptr().byte_offset(1),
|
||||
i32x4::splat(0),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required
|
||||
--> tests/fail/intrinsics/simd_masked_load_element_misaligned.rs:LL:CC
|
||||
|
|
||||
LL | / simd_masked_load::<_, _, _, { SimdAlign::Element }>(
|
||||
LL | | i32x4::splat(-1),
|
||||
LL | | // This is not i32-aligned
|
||||
LL | | buf.as_ptr().byte_offset(1),
|
||||
LL | | i32x4::splat(0),
|
||||
LL | | );
|
||||
| |_________^ Undefined Behavior occurred here
|
||||
|
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
#![feature(core_intrinsics, portable_simd)]
|
||||
|
||||
use std::intrinsics::simd::*;
|
||||
use std::simd::*;
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let buf = Simd::<i32, 8>::splat(0);
|
||||
//~v ERROR: accessing memory with alignment
|
||||
simd_masked_load::<_, _, _, { SimdAlign::Vector }>(
|
||||
i32x4::splat(-1),
|
||||
// This is i32-aligned but not i32x4-aligned.
|
||||
buf.as_array()[1..].as_ptr(),
|
||||
i32x4::splat(0),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required
|
||||
--> tests/fail/intrinsics/simd_masked_load_vector_misaligned.rs:LL:CC
|
||||
|
|
||||
LL | / simd_masked_load::<_, _, _, { SimdAlign::Vector }>(
|
||||
LL | | i32x4::splat(-1),
|
||||
LL | | // This is i32-aligned but not i32x4-aligned.
|
||||
LL | | buf.as_array()[1..].as_ptr(),
|
||||
LL | | i32x4::splat(0),
|
||||
LL | | );
|
||||
| |_________^ Undefined Behavior occurred here
|
||||
|
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
#![feature(core_intrinsics, portable_simd)]
|
||||
|
||||
use std::intrinsics::simd::*;
|
||||
use std::simd::*;
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let mut buf = [0u32; 5];
|
||||
//~v ERROR: accessing memory with alignment
|
||||
simd_masked_store::<_, _, _, { SimdAlign::Element }>(
|
||||
i32x4::splat(-1),
|
||||
// This is not i32-aligned
|
||||
buf.as_mut_ptr().byte_offset(1),
|
||||
i32x4::splat(0),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required
|
||||
--> tests/fail/intrinsics/simd_masked_store_element_misaligned.rs:LL:CC
|
||||
|
|
||||
LL | / simd_masked_store::<_, _, _, { SimdAlign::Element }>(
|
||||
LL | | i32x4::splat(-1),
|
||||
LL | | // This is not i32-aligned
|
||||
LL | | buf.as_mut_ptr().byte_offset(1),
|
||||
LL | | i32x4::splat(0),
|
||||
LL | | );
|
||||
| |_________^ Undefined Behavior occurred here
|
||||
|
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
#![feature(core_intrinsics, portable_simd)]
|
||||
|
||||
use std::intrinsics::simd::*;
|
||||
use std::simd::*;
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let mut buf = Simd::<i32, 8>::splat(0);
|
||||
//~v ERROR: accessing memory with alignment
|
||||
simd_masked_store::<_, _, _, { SimdAlign::Vector }>(
|
||||
i32x4::splat(-1),
|
||||
// This is i32-aligned but not i32x4-aligned.
|
||||
buf.as_mut_array()[1..].as_mut_ptr(),
|
||||
i32x4::splat(0),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required
|
||||
--> tests/fail/intrinsics/simd_masked_store_vector_misaligned.rs:LL:CC
|
||||
|
|
||||
LL | / simd_masked_store::<_, _, _, { SimdAlign::Vector }>(
|
||||
LL | | i32x4::splat(-1),
|
||||
LL | | // This is i32-aligned but not i32x4-aligned.
|
||||
LL | | buf.as_mut_array()[1..].as_mut_ptr(),
|
||||
LL | | i32x4::splat(0),
|
||||
LL | | );
|
||||
| |_________^ Undefined Behavior occurred here
|
||||
|
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -936,26 +936,93 @@ fn simd_float_intrinsics() {
|
|||
}
|
||||
|
||||
fn simd_masked_loadstore() {
|
||||
use intrinsics::*;
|
||||
|
||||
// The buffer is deliberarely too short, so reading the last element would be UB.
|
||||
let buf = [3i32; 3];
|
||||
let default = i32x4::splat(0);
|
||||
let mask = i32x4::from_array([!0, !0, !0, 0]);
|
||||
let vals = unsafe { intrinsics::simd_masked_load(mask, buf.as_ptr(), default) };
|
||||
let vals =
|
||||
unsafe { simd_masked_load::<_, _, _, { SimdAlign::Element }>(mask, buf.as_ptr(), default) };
|
||||
assert_eq!(vals, i32x4::from_array([3, 3, 3, 0]));
|
||||
// Also read in a way that the *first* element is OOB.
|
||||
let mask2 = i32x4::from_array([0, !0, !0, !0]);
|
||||
let vals =
|
||||
unsafe { intrinsics::simd_masked_load(mask2, buf.as_ptr().wrapping_sub(1), default) };
|
||||
let vals = unsafe {
|
||||
simd_masked_load::<_, _, _, { SimdAlign::Element }>(
|
||||
mask2,
|
||||
buf.as_ptr().wrapping_sub(1),
|
||||
default,
|
||||
)
|
||||
};
|
||||
assert_eq!(vals, i32x4::from_array([0, 3, 3, 3]));
|
||||
|
||||
// The buffer is deliberarely too short, so writing the last element would be UB.
|
||||
let mut buf = [42i32; 3];
|
||||
let vals = i32x4::from_array([1, 2, 3, 4]);
|
||||
unsafe { intrinsics::simd_masked_store(mask, buf.as_mut_ptr(), vals) };
|
||||
unsafe { simd_masked_store::<_, _, _, { SimdAlign::Element }>(mask, buf.as_mut_ptr(), vals) };
|
||||
assert_eq!(buf, [1, 2, 3]);
|
||||
// Also write in a way that the *first* element is OOB.
|
||||
unsafe { intrinsics::simd_masked_store(mask2, buf.as_mut_ptr().wrapping_sub(1), vals) };
|
||||
unsafe {
|
||||
simd_masked_store::<_, _, _, { SimdAlign::Element }>(
|
||||
mask2,
|
||||
buf.as_mut_ptr().wrapping_sub(1),
|
||||
vals,
|
||||
)
|
||||
};
|
||||
assert_eq!(buf, [2, 3, 4]);
|
||||
|
||||
// we use a purposely misaliged buffer to make sure Miri doesn't error in this case
|
||||
let buf = [0x03030303_i32; 5];
|
||||
let default = i32x4::splat(0);
|
||||
let mask = i32x4::splat(!0);
|
||||
let vals = unsafe {
|
||||
simd_masked_load::<_, _, _, { SimdAlign::Unaligned }>(
|
||||
mask,
|
||||
buf.as_ptr().byte_offset(1), // this is guaranteed to be unaligned
|
||||
default,
|
||||
)
|
||||
};
|
||||
assert_eq!(vals, i32x4::splat(0x03030303));
|
||||
|
||||
let mut buf = [0i32; 5];
|
||||
let mask = i32x4::splat(!0);
|
||||
unsafe {
|
||||
simd_masked_store::<_, _, _, { SimdAlign::Unaligned }>(
|
||||
mask,
|
||||
buf.as_mut_ptr().byte_offset(1), // this is guaranteed to be unaligned
|
||||
vals,
|
||||
)
|
||||
};
|
||||
assert_eq!(
|
||||
buf,
|
||||
[
|
||||
i32::from_ne_bytes([0, 3, 3, 3]),
|
||||
0x03030303,
|
||||
0x03030303,
|
||||
0x03030303,
|
||||
i32::from_ne_bytes([3, 0, 0, 0])
|
||||
]
|
||||
);
|
||||
|
||||
// `repr(simd)` types like `Simd<T, N>` have the correct alignment for vectors
|
||||
let buf = i32x4::splat(3);
|
||||
let default = i32x4::splat(0);
|
||||
let mask = i32x4::splat(!0);
|
||||
let vals = unsafe {
|
||||
simd_masked_load::<_, _, _, { SimdAlign::Vector }>(
|
||||
mask,
|
||||
&raw const buf as *const i32,
|
||||
default,
|
||||
)
|
||||
};
|
||||
assert_eq!(vals, buf);
|
||||
|
||||
let mut buf = i32x4::splat(0);
|
||||
let mask = i32x4::splat(!0);
|
||||
unsafe {
|
||||
simd_masked_store::<_, _, _, { SimdAlign::Vector }>(mask, &raw mut buf as *mut i32, vals)
|
||||
};
|
||||
assert_eq!(buf, vals);
|
||||
}
|
||||
|
||||
fn simd_ops_non_pow2() {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: --crate-type=lib -Copt-level=3 -C panic=abort
|
||||
|
||||
#![feature(no_core, lang_items, repr_simd, intrinsics)]
|
||||
#![feature(no_core, lang_items, repr_simd, intrinsics, adt_const_params)]
|
||||
#![no_core]
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
|
|
@ -35,7 +35,7 @@ pub struct f64x4([f64; 4]);
|
|||
pub struct m64x4([i64; 4]);
|
||||
|
||||
#[rustc_intrinsic]
|
||||
unsafe fn simd_masked_load<M, P, T>(mask: M, pointer: P, values: T) -> T;
|
||||
unsafe fn simd_masked_load<M, P, T, const ALIGN: SimdAlign>(mask: M, pointer: P, values: T) -> T;
|
||||
|
||||
// CHECK-LABEL: load_i8x16
|
||||
#[no_mangle]
|
||||
|
|
@ -56,7 +56,11 @@ pub unsafe extern "C" fn load_i8x16(mask: m8x16, pointer: *const i8) -> i8x16 {
|
|||
// x86-avx512-NOT: vpsllw
|
||||
// x86-avx512: vpmovb2m k1, xmm0
|
||||
// x86-avx512-NEXT: vmovdqu8 xmm0 {k1} {z}, xmmword ptr [rdi]
|
||||
simd_masked_load(mask, pointer, i8x16([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]))
|
||||
simd_masked_load::<_, _, _, { SimdAlign::Element }>(
|
||||
mask,
|
||||
pointer,
|
||||
i8x16([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
|
||||
)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: load_f32x8
|
||||
|
|
@ -68,7 +72,29 @@ pub unsafe extern "C" fn load_f32x8(mask: m32x8, pointer: *const f32) -> f32x8 {
|
|||
// x86-avx512-NOT: vpslld
|
||||
// x86-avx512: vpmovd2m k1, ymm0
|
||||
// x86-avx512-NEXT: vmovups ymm0 {k1} {z}, ymmword ptr [rdi]
|
||||
simd_masked_load(mask, pointer, f32x8([0_f32, 0_f32, 0_f32, 0_f32, 0_f32, 0_f32, 0_f32, 0_f32]))
|
||||
simd_masked_load::<_, _, _, { SimdAlign::Element }>(
|
||||
mask,
|
||||
pointer,
|
||||
f32x8([0_f32, 0_f32, 0_f32, 0_f32, 0_f32, 0_f32, 0_f32, 0_f32]),
|
||||
)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: load_f32x8_aligned
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn load_f32x8_aligned(mask: m32x8, pointer: *const f32) -> f32x8 {
|
||||
// x86-avx2-NOT: vpslld
|
||||
// x86-avx2: vmaskmovps ymm0, ymm0, ymmword ptr [rdi]
|
||||
//
|
||||
// x86-avx512-NOT: vpslld
|
||||
// x86-avx512: vpmovd2m k1, ymm0
|
||||
// x86-avx512-NEXT: vmovaps ymm0 {k1} {z}, ymmword ptr [rdi]
|
||||
//
|
||||
// this aligned version should generate `movaps` instead of `movups`
|
||||
simd_masked_load::<_, _, _, { SimdAlign::Vector }>(
|
||||
mask,
|
||||
pointer,
|
||||
f32x8([0_f32, 0_f32, 0_f32, 0_f32, 0_f32, 0_f32, 0_f32, 0_f32]),
|
||||
)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: load_f64x4
|
||||
|
|
@ -79,5 +105,9 @@ pub unsafe extern "C" fn load_f64x4(mask: m64x4, pointer: *const f64) -> f64x4 {
|
|||
//
|
||||
// x86-avx512-NOT: vpsllq
|
||||
// x86-avx512: vpmovq2m k1, ymm0
|
||||
simd_masked_load(mask, pointer, f64x4([0_f64, 0_f64, 0_f64, 0_f64]))
|
||||
simd_masked_load::<_, _, _, { SimdAlign::Element }>(
|
||||
mask,
|
||||
pointer,
|
||||
f64x4([0_f64, 0_f64, 0_f64, 0_f64]),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: --crate-type=lib -Copt-level=3 -C panic=abort
|
||||
|
||||
#![feature(no_core, lang_items, repr_simd, intrinsics)]
|
||||
#![feature(no_core, lang_items, repr_simd, intrinsics, adt_const_params)]
|
||||
#![no_core]
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
|
|
@ -35,7 +35,7 @@ pub struct f64x4([f64; 4]);
|
|||
pub struct m64x4([i64; 4]);
|
||||
|
||||
#[rustc_intrinsic]
|
||||
unsafe fn simd_masked_store<M, P, T>(mask: M, pointer: P, values: T);
|
||||
unsafe fn simd_masked_store<M, P, T, const ALIGN: SimdAlign>(mask: M, pointer: P, values: T);
|
||||
|
||||
// CHECK-LABEL: store_i8x16
|
||||
#[no_mangle]
|
||||
|
|
@ -54,7 +54,7 @@ pub unsafe extern "C" fn store_i8x16(mask: m8x16, pointer: *mut i8, value: i8x16
|
|||
// x86-avx512-NOT: vpsllw
|
||||
// x86-avx512: vpmovb2m k1, xmm0
|
||||
// x86-avx512-NEXT: vmovdqu8 xmmword ptr [rdi] {k1}, xmm1
|
||||
simd_masked_store(mask, pointer, value)
|
||||
simd_masked_store::<_, _, _, { SimdAlign::Element }>(mask, pointer, value)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: store_f32x8
|
||||
|
|
@ -66,7 +66,21 @@ pub unsafe extern "C" fn store_f32x8(mask: m32x8, pointer: *mut f32, value: f32x
|
|||
// x86-avx512-NOT: vpslld
|
||||
// x86-avx512: vpmovd2m k1, ymm0
|
||||
// x86-avx512-NEXT: vmovups ymmword ptr [rdi] {k1}, ymm1
|
||||
simd_masked_store(mask, pointer, value)
|
||||
simd_masked_store::<_, _, _, { SimdAlign::Element }>(mask, pointer, value)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: store_f32x8_aligned
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn store_f32x8_aligned(mask: m32x8, pointer: *mut f32, value: f32x8) {
|
||||
// x86-avx2-NOT: vpslld
|
||||
// x86-avx2: vmaskmovps ymmword ptr [rdi], ymm0, ymm1
|
||||
//
|
||||
// x86-avx512-NOT: vpslld
|
||||
// x86-avx512: vpmovd2m k1, ymm0
|
||||
// x86-avx512-NEXT: vmovaps ymmword ptr [rdi] {k1}, ymm1
|
||||
//
|
||||
// this aligned version should generate `movaps` instead of `movups`
|
||||
simd_masked_store::<_, _, _, { SimdAlign::Vector }>(mask, pointer, value)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: store_f64x4
|
||||
|
|
@ -78,5 +92,5 @@ pub unsafe extern "C" fn store_f64x4(mask: m64x4, pointer: *mut f64, value: f64x
|
|||
// x86-avx512-NOT: vpsllq
|
||||
// x86-avx512: vpmovq2m k1, ymm0
|
||||
// x86-avx512-NEXT: vmovupd ymmword ptr [rdi] {k1}, ymm1
|
||||
simd_masked_store(mask, pointer, value)
|
||||
simd_masked_store::<_, _, _, { SimdAlign::Element }>(mask, pointer, value)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -261,3 +261,17 @@ pub enum c_void {
|
|||
__variant1,
|
||||
__variant2,
|
||||
}
|
||||
|
||||
#[lang = "const_param_ty"]
|
||||
#[diagnostic::on_unimplemented(message = "`{Self}` can't be used as a const parameter type")]
|
||||
pub trait ConstParamTy_ {}
|
||||
|
||||
pub enum SimdAlign {
|
||||
// These values must match the compiler's `SimdAlign` defined in
|
||||
// `rustc_middle/src/ty/consts/int.rs`!
|
||||
Unaligned = 0,
|
||||
Element = 1,
|
||||
Vector = 2,
|
||||
}
|
||||
|
||||
impl ConstParamTy_ for SimdAlign {}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
mod minisimd;
|
||||
use minisimd::*;
|
||||
|
||||
use std::intrinsics::simd::simd_masked_load;
|
||||
use std::intrinsics::simd::{SimdAlign, simd_masked_load};
|
||||
|
||||
pub type Vec2<T> = Simd<T, 2>;
|
||||
pub type Vec4<T> = Simd<T, 4>;
|
||||
|
|
@ -23,8 +23,45 @@ pub unsafe fn load_f32x2(mask: Vec2<i32>, pointer: *const f32, values: Vec2<f32>
|
|||
// CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
|
||||
// CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
|
||||
// LLVM21: call <2 x float> @llvm.masked.load.v2f32.p0(ptr {{.*}}, i32 4, <2 x i1> [[B]], <2 x float> {{.*}})
|
||||
// ^^^^^
|
||||
// LLVM22: call <2 x float> @llvm.masked.load.v2f32.p0(ptr align 4 {{.*}}, <2 x i1> [[B]], <2 x float> {{.*}})
|
||||
simd_masked_load(mask, pointer, values)
|
||||
// ^^^^^^^
|
||||
// the align parameter should be equal to the alignment of the element type (assumed to be 4)
|
||||
simd_masked_load::<_, _, _, { SimdAlign::Element }>(mask, pointer, values)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @load_f32x2_aligned
|
||||
#[no_mangle]
|
||||
pub unsafe fn load_f32x2_aligned(
|
||||
mask: Vec2<i32>,
|
||||
pointer: *const f32,
|
||||
values: Vec2<f32>,
|
||||
) -> Vec2<f32> {
|
||||
// CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
|
||||
// CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
|
||||
// LLVM21: call <2 x float> @llvm.masked.load.v2f32.p0(ptr {{.*}}, i32 8, <2 x i1> [[B]], <2 x float> {{.*}})
|
||||
// ^^^^^
|
||||
// LLVM22: call <2 x float> @llvm.masked.load.v2f32.p0(ptr align 8 {{.*}}, <2 x i1> [[B]], <2 x float> {{.*}})
|
||||
// ^^^^^^^
|
||||
// the align parameter should be equal to the size of the vector
|
||||
simd_masked_load::<_, _, _, { SimdAlign::Vector }>(mask, pointer, values)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @load_f32x2_unaligned
|
||||
#[no_mangle]
|
||||
pub unsafe fn load_f32x2_unaligned(
|
||||
mask: Vec2<i32>,
|
||||
pointer: *const f32,
|
||||
values: Vec2<f32>,
|
||||
) -> Vec2<f32> {
|
||||
// CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
|
||||
// CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
|
||||
// LLVM21: call <2 x float> @llvm.masked.load.v2f32.p0(ptr {{.*}}, i32 1, <2 x i1> [[B]], <2 x float> {{.*}})
|
||||
// ^^^^^
|
||||
// LLVM22: call <2 x float> @llvm.masked.load.v2f32.p0(ptr align 1 {{.*}}, <2 x i1> [[B]], <2 x float> {{.*}})
|
||||
// ^^^^^^^
|
||||
// the align parameter should be 1
|
||||
simd_masked_load::<_, _, _, { SimdAlign::Unaligned }>(mask, pointer, values)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @load_f32x2_unsigned
|
||||
|
|
@ -38,7 +75,7 @@ pub unsafe fn load_f32x2_unsigned(
|
|||
// CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
|
||||
// LLVM21: call <2 x float> @llvm.masked.load.v2f32.p0(ptr {{.*}}, i32 4, <2 x i1> [[B]], <2 x float> {{.*}})
|
||||
// LLVM22: call <2 x float> @llvm.masked.load.v2f32.p0(ptr align 4 {{.*}}, <2 x i1> [[B]], <2 x float> {{.*}})
|
||||
simd_masked_load(mask, pointer, values)
|
||||
simd_masked_load::<_, _, _, { SimdAlign::Element }>(mask, pointer, values)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @load_pf32x4
|
||||
|
|
@ -52,5 +89,5 @@ pub unsafe fn load_pf32x4(
|
|||
// CHECK: [[B:%[0-9]+]] = trunc <4 x i32> [[A]] to <4 x i1>
|
||||
// LLVM21: call <4 x ptr> @llvm.masked.load.v4p0.p0(ptr {{.*}}, i32 {{.*}}, <4 x i1> [[B]], <4 x ptr> {{.*}})
|
||||
// LLVM22: call <4 x ptr> @llvm.masked.load.v4p0.p0(ptr align {{.*}} {{.*}}, <4 x i1> [[B]], <4 x ptr> {{.*}})
|
||||
simd_masked_load(mask, pointer, values)
|
||||
simd_masked_load::<_, _, _, { SimdAlign::Element }>(mask, pointer, values)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
mod minisimd;
|
||||
use minisimd::*;
|
||||
|
||||
use std::intrinsics::simd::simd_masked_store;
|
||||
use std::intrinsics::simd::{SimdAlign, simd_masked_store};
|
||||
|
||||
pub type Vec2<T> = Simd<T, 2>;
|
||||
pub type Vec4<T> = Simd<T, 4>;
|
||||
|
|
@ -23,8 +23,37 @@ pub unsafe fn store_f32x2(mask: Vec2<i32>, pointer: *mut f32, values: Vec2<f32>)
|
|||
// CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
|
||||
// CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
|
||||
// LLVM21: call void @llvm.masked.store.v2f32.p0(<2 x float> {{.*}}, ptr {{.*}}, i32 4, <2 x i1> [[B]])
|
||||
// ^^^^^
|
||||
// LLVM22: call void @llvm.masked.store.v2f32.p0(<2 x float> {{.*}}, ptr align 4 {{.*}}, <2 x i1> [[B]])
|
||||
simd_masked_store(mask, pointer, values)
|
||||
// ^^^^^^^
|
||||
// the align parameter should be equal to the alignment of the element type (assumed to be 4)
|
||||
simd_masked_store::<_, _, _, { SimdAlign::Element }>(mask, pointer, values)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @store_f32x2_aligned
|
||||
#[no_mangle]
|
||||
pub unsafe fn store_f32x2_aligned(mask: Vec2<i32>, pointer: *mut f32, values: Vec2<f32>) {
|
||||
// CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
|
||||
// CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
|
||||
// LLVM21: call void @llvm.masked.store.v2f32.p0(<2 x float> {{.*}}, ptr {{.*}}, i32 8, <2 x i1> [[B]])
|
||||
// ^^^^^
|
||||
// LLVM22: call void @llvm.masked.store.v2f32.p0(<2 x float> {{.*}}, ptr align 8 {{.*}}, <2 x i1> [[B]])
|
||||
// ^^^^^^^
|
||||
// the align parameter should be equal to the size of the vector
|
||||
simd_masked_store::<_, _, _, { SimdAlign::Vector }>(mask, pointer, values)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @store_f32x2_unaligned
|
||||
#[no_mangle]
|
||||
pub unsafe fn store_f32x2_unaligned(mask: Vec2<i32>, pointer: *mut f32, values: Vec2<f32>) {
|
||||
// CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
|
||||
// CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
|
||||
// LLVM21: call void @llvm.masked.store.v2f32.p0(<2 x float> {{.*}}, ptr {{.*}}, i32 1, <2 x i1> [[B]])
|
||||
// ^^^^^
|
||||
// LLVM22: call void @llvm.masked.store.v2f32.p0(<2 x float> {{.*}}, ptr align 1 {{.*}}, <2 x i1> [[B]])
|
||||
// ^^^^^^^
|
||||
// the align parameter should be 1
|
||||
simd_masked_store::<_, _, _, { SimdAlign::Unaligned }>(mask, pointer, values)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @store_f32x2_unsigned
|
||||
|
|
@ -34,7 +63,7 @@ pub unsafe fn store_f32x2_unsigned(mask: Vec2<u32>, pointer: *mut f32, values: V
|
|||
// CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
|
||||
// LLVM21: call void @llvm.masked.store.v2f32.p0(<2 x float> {{.*}}, ptr {{.*}}, i32 4, <2 x i1> [[B]])
|
||||
// LLVM22: call void @llvm.masked.store.v2f32.p0(<2 x float> {{.*}}, ptr align 4 {{.*}}, <2 x i1> [[B]])
|
||||
simd_masked_store(mask, pointer, values)
|
||||
simd_masked_store::<_, _, _, { SimdAlign::Element }>(mask, pointer, values)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @store_pf32x4
|
||||
|
|
@ -44,5 +73,5 @@ pub unsafe fn store_pf32x4(mask: Vec4<i32>, pointer: *mut *const f32, values: Ve
|
|||
// CHECK: [[B:%[0-9]+]] = trunc <4 x i32> [[A]] to <4 x i1>
|
||||
// LLVM21: call void @llvm.masked.store.v4p0.p0(<4 x ptr> {{.*}}, ptr {{.*}}, i32 {{.*}}, <4 x i1> [[B]])
|
||||
// LLVM22: call void @llvm.masked.store.v4p0.p0(<4 x ptr> {{.*}}, ptr align {{.*}} {{.*}}, <4 x i1> [[B]])
|
||||
simd_masked_store(mask, pointer, values)
|
||||
simd_masked_store::<_, _, _, { SimdAlign::Element }>(mask, pointer, values)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,17 +61,11 @@
|
|||
StorageDead(_1);
|
||||
return;
|
||||
}
|
||||
+ }
|
||||
+
|
||||
+ ALLOC0 (size: 4, align: 4) {
|
||||
+ 00 00 00 00 │ ....
|
||||
+ }
|
||||
+
|
||||
+ ALLOC1 (size: 4, align: 4) {
|
||||
+ 04 00 00 00 │ ....
|
||||
+ }
|
||||
+
|
||||
+ ALLOC2 (size: 4, align: 4) {
|
||||
+ 01 00 11 00 │ ....
|
||||
}
|
||||
+
|
||||
+ ALLOC0 (size: 4, align: 4) { .. }
|
||||
+
|
||||
+ ALLOC1 (size: 4, align: 4) { .. }
|
||||
+
|
||||
+ ALLOC2 (size: 4, align: 4) { .. }
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// skip-filecheck
|
||||
//@ test-mir-pass: GVN
|
||||
//@ compile-flags: -Zmir-enable-passes=+RemoveZsts
|
||||
//@ compile-flags: -Zmir-enable-passes=+RemoveZsts -Zdump-mir-exclude-alloc-bytes
|
||||
// Verify that we can pretty print invalid constants.
|
||||
|
||||
#![feature(adt_const_params, unsized_const_params)]
|
||||
|
|
|
|||
|
|
@ -34,9 +34,7 @@
|
|||
StorageDead(_1);
|
||||
return;
|
||||
}
|
||||
+ }
|
||||
+
|
||||
+ ALLOC0 (size: 4, align: 4) {
|
||||
+ 01 00 00 00 │ ....
|
||||
}
|
||||
+
|
||||
+ ALLOC0 (size: 4, align: 4) { .. }
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! Tests that we can propagate into places that are projections into unions
|
||||
//@ test-mir-pass: GVN
|
||||
//@ compile-flags: -Zinline-mir
|
||||
//@ compile-flags: -Zinline-mir -Zdump-mir-exclude-alloc-bytes
|
||||
|
||||
fn val() -> u32 {
|
||||
1
|
||||
|
|
|
|||
|
|
@ -107,9 +107,7 @@
|
|||
StorageDead(_11);
|
||||
goto -> bb4;
|
||||
}
|
||||
+ }
|
||||
+
|
||||
+ ALLOC0 (size: 8, align: 4) {
|
||||
+ 01 00 00 00 __ __ __ __ │ ....░░░░
|
||||
}
|
||||
+
|
||||
+ ALLOC0 (size: 8, align: 4) { .. }
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
//@ test-mir-pass: GVN
|
||||
//@ compile-flags: -Zdump-mir-exclude-alloc-bytes
|
||||
|
||||
#![crate_type = "lib"]
|
||||
#![feature(core_intrinsics, rustc_attrs)]
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
//@ ignore-backends: gcc
|
||||
#![feature(repr_simd, core_intrinsics)]
|
||||
|
||||
use std::intrinsics::simd::{simd_masked_load, simd_masked_store};
|
||||
use std::intrinsics::simd::{SimdAlign, simd_masked_load, simd_masked_store};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(simd)]
|
||||
|
|
@ -13,28 +13,60 @@ fn main() {
|
|||
let mut arr = [4u8, 5, 6, 7];
|
||||
let default = Simd::<u8, 4>([9; 4]);
|
||||
|
||||
simd_masked_load(Simd::<i8, 8>([-1, 0, -1, -1, 0, 0, 0, 0]), arr.as_ptr(), default);
|
||||
//~^ ERROR expected third argument with length 8 (same as input type `Simd<i8, 8>`), found `Simd<u8, 4>` with length 4
|
||||
//~v ERROR expected third argument with length 8 (same as input type `Simd<i8, 8>`), found `Simd<u8, 4>` with length 4
|
||||
simd_masked_load::<_, _, _, { SimdAlign::Element }>(
|
||||
Simd::<i8, 8>([-1, 0, -1, -1, 0, 0, 0, 0]),
|
||||
arr.as_ptr(),
|
||||
default,
|
||||
);
|
||||
|
||||
simd_masked_load(Simd::<i8, 4>([-1, 0, -1, -1]), arr.as_ptr() as *const i8, default);
|
||||
//~^ ERROR expected element type `u8` of second argument `*const i8` to be a pointer to the element type `u8` of the first argument `Simd<u8, 4>`, found `u8` != `*_ u8`
|
||||
//~v ERROR expected element type `u8` of second argument `*const i8` to be a pointer to the element type `u8` of the first argument `Simd<u8, 4>`, found `u8` != `*_ u8`
|
||||
simd_masked_load::<_, _, _, { SimdAlign::Element }>(
|
||||
Simd::<i8, 4>([-1, 0, -1, -1]),
|
||||
arr.as_ptr() as *const i8,
|
||||
default,
|
||||
);
|
||||
|
||||
simd_masked_load(Simd::<i8, 4>([-1, 0, -1, -1]), arr.as_ptr(), Simd::<u32, 4>([9; 4]));
|
||||
//~^ ERROR expected element type `u32` of second argument `*const u8` to be a pointer to the element type `u32` of the first argument `Simd<u32, 4>`, found `u32` != `*_ u32`
|
||||
//~v ERROR expected element type `u32` of second argument `*const u8` to be a pointer to the element type `u32` of the first argument `Simd<u32, 4>`, found `u32` != `*_ u32`
|
||||
simd_masked_load::<_, _, _, { SimdAlign::Element }>(
|
||||
Simd::<i8, 4>([-1, 0, -1, -1]),
|
||||
arr.as_ptr(),
|
||||
Simd::<u32, 4>([9; 4]),
|
||||
);
|
||||
|
||||
simd_masked_load(Simd::<f32, 4>([1.0, 0.0, 1.0, 1.0]), arr.as_ptr(), default);
|
||||
//~^ ERROR expected mask element type to be an integer, found `f32`
|
||||
//~v ERROR expected mask element type to be an integer, found `f32`
|
||||
simd_masked_load::<_, _, _, { SimdAlign::Element }>(
|
||||
Simd::<f32, 4>([1.0, 0.0, 1.0, 1.0]),
|
||||
arr.as_ptr(),
|
||||
default,
|
||||
);
|
||||
|
||||
simd_masked_store(Simd([-1i8; 4]), arr.as_ptr(), Simd([5u32; 4]));
|
||||
//~^ ERROR expected element type `u32` of second argument `*const u8` to be a pointer to the element type `u32` of the first argument `Simd<u32, 4>`, found `u32` != `*mut u32`
|
||||
//~v ERROR expected element type `u32` of second argument `*const u8` to be a pointer to the element type `u32` of the first argument `Simd<u32, 4>`, found `u32` != `*mut u32`
|
||||
simd_masked_store::<_, _, _, { SimdAlign::Element }>(
|
||||
Simd([-1i8; 4]),
|
||||
arr.as_ptr(),
|
||||
Simd([5u32; 4]),
|
||||
);
|
||||
|
||||
simd_masked_store(Simd([-1i8; 4]), arr.as_ptr(), Simd([5u8; 4]));
|
||||
//~^ ERROR expected element type `u8` of second argument `*const u8` to be a pointer to the element type `u8` of the first argument `Simd<u8, 4>`, found `u8` != `*mut u8`
|
||||
//~v ERROR expected element type `u8` of second argument `*const u8` to be a pointer to the element type `u8` of the first argument `Simd<u8, 4>`, found `u8` != `*mut u8`
|
||||
simd_masked_store::<_, _, _, { SimdAlign::Element }>(
|
||||
Simd([-1i8; 4]),
|
||||
arr.as_ptr(),
|
||||
Simd([5u8; 4]),
|
||||
);
|
||||
|
||||
simd_masked_store(Simd([-1i8; 4]), arr.as_mut_ptr(), Simd([5u8; 2]));
|
||||
//~^ ERROR expected third argument with length 4 (same as input type `Simd<i8, 4>`), found `Simd<u8, 2>` with length 2
|
||||
//~v ERROR expected third argument with length 4 (same as input type `Simd<i8, 4>`), found `Simd<u8, 2>` with length 2
|
||||
simd_masked_store::<_, _, _, { SimdAlign::Element }>(
|
||||
Simd([-1i8; 4]),
|
||||
arr.as_mut_ptr(),
|
||||
Simd([5u8; 2]),
|
||||
);
|
||||
|
||||
simd_masked_store(Simd([1f32; 4]), arr.as_mut_ptr(), Simd([5u8; 4]));
|
||||
//~^ ERROR expected mask element type to be an integer, found `f32`
|
||||
//~v ERROR expected mask element type to be an integer, found `f32`
|
||||
simd_masked_store::<_, _, _, { SimdAlign::Element }>(
|
||||
Simd([1f32; 4]),
|
||||
arr.as_mut_ptr(),
|
||||
Simd([5u8; 4]),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,50 +1,82 @@
|
|||
error[E0511]: invalid monomorphization of `simd_masked_load` intrinsic: expected third argument with length 8 (same as input type `Simd<i8, 8>`), found `Simd<u8, 4>` with length 4
|
||||
--> $DIR/masked-load-store-build-fail.rs:16:9
|
||||
--> $DIR/masked-load-store-build-fail.rs:17:9
|
||||
|
|
||||
LL | simd_masked_load(Simd::<i8, 8>([-1, 0, -1, -1, 0, 0, 0, 0]), arr.as_ptr(), default);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | / simd_masked_load::<_, _, _, { SimdAlign::Element }>(
|
||||
LL | | Simd::<i8, 8>([-1, 0, -1, -1, 0, 0, 0, 0]),
|
||||
LL | | arr.as_ptr(),
|
||||
LL | | default,
|
||||
LL | | );
|
||||
| |_________^
|
||||
|
||||
error[E0511]: invalid monomorphization of `simd_masked_load` intrinsic: expected element type `u8` of second argument `*const i8` to be a pointer to the element type `u8` of the first argument `Simd<u8, 4>`, found `u8` != `*_ u8`
|
||||
--> $DIR/masked-load-store-build-fail.rs:19:9
|
||||
--> $DIR/masked-load-store-build-fail.rs:24:9
|
||||
|
|
||||
LL | simd_masked_load(Simd::<i8, 4>([-1, 0, -1, -1]), arr.as_ptr() as *const i8, default);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | / simd_masked_load::<_, _, _, { SimdAlign::Element }>(
|
||||
LL | | Simd::<i8, 4>([-1, 0, -1, -1]),
|
||||
LL | | arr.as_ptr() as *const i8,
|
||||
LL | | default,
|
||||
LL | | );
|
||||
| |_________^
|
||||
|
||||
error[E0511]: invalid monomorphization of `simd_masked_load` intrinsic: expected element type `u32` of second argument `*const u8` to be a pointer to the element type `u32` of the first argument `Simd<u32, 4>`, found `u32` != `*_ u32`
|
||||
--> $DIR/masked-load-store-build-fail.rs:22:9
|
||||
|
|
||||
LL | simd_masked_load(Simd::<i8, 4>([-1, 0, -1, -1]), arr.as_ptr(), Simd::<u32, 4>([9; 4]));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0511]: invalid monomorphization of `simd_masked_load` intrinsic: expected mask element type to be an integer, found `f32`
|
||||
--> $DIR/masked-load-store-build-fail.rs:25:9
|
||||
|
|
||||
LL | simd_masked_load(Simd::<f32, 4>([1.0, 0.0, 1.0, 1.0]), arr.as_ptr(), default);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0511]: invalid monomorphization of `simd_masked_store` intrinsic: expected element type `u32` of second argument `*const u8` to be a pointer to the element type `u32` of the first argument `Simd<u32, 4>`, found `u32` != `*mut u32`
|
||||
--> $DIR/masked-load-store-build-fail.rs:28:9
|
||||
|
|
||||
LL | simd_masked_store(Simd([-1i8; 4]), arr.as_ptr(), Simd([5u32; 4]));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0511]: invalid monomorphization of `simd_masked_store` intrinsic: expected element type `u8` of second argument `*const u8` to be a pointer to the element type `u8` of the first argument `Simd<u8, 4>`, found `u8` != `*mut u8`
|
||||
--> $DIR/masked-load-store-build-fail.rs:31:9
|
||||
|
|
||||
LL | simd_masked_store(Simd([-1i8; 4]), arr.as_ptr(), Simd([5u8; 4]));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | / simd_masked_load::<_, _, _, { SimdAlign::Element }>(
|
||||
LL | | Simd::<i8, 4>([-1, 0, -1, -1]),
|
||||
LL | | arr.as_ptr(),
|
||||
LL | | Simd::<u32, 4>([9; 4]),
|
||||
LL | | );
|
||||
| |_________^
|
||||
|
||||
error[E0511]: invalid monomorphization of `simd_masked_load` intrinsic: expected mask element type to be an integer, found `f32`
|
||||
--> $DIR/masked-load-store-build-fail.rs:38:9
|
||||
|
|
||||
LL | / simd_masked_load::<_, _, _, { SimdAlign::Element }>(
|
||||
LL | | Simd::<f32, 4>([1.0, 0.0, 1.0, 1.0]),
|
||||
LL | | arr.as_ptr(),
|
||||
LL | | default,
|
||||
LL | | );
|
||||
| |_________^
|
||||
|
||||
error[E0511]: invalid monomorphization of `simd_masked_store` intrinsic: expected element type `u32` of second argument `*const u8` to be a pointer to the element type `u32` of the first argument `Simd<u32, 4>`, found `u32` != `*mut u32`
|
||||
--> $DIR/masked-load-store-build-fail.rs:45:9
|
||||
|
|
||||
LL | / simd_masked_store::<_, _, _, { SimdAlign::Element }>(
|
||||
LL | | Simd([-1i8; 4]),
|
||||
LL | | arr.as_ptr(),
|
||||
LL | | Simd([5u32; 4]),
|
||||
LL | | );
|
||||
| |_________^
|
||||
|
||||
error[E0511]: invalid monomorphization of `simd_masked_store` intrinsic: expected element type `u8` of second argument `*const u8` to be a pointer to the element type `u8` of the first argument `Simd<u8, 4>`, found `u8` != `*mut u8`
|
||||
--> $DIR/masked-load-store-build-fail.rs:52:9
|
||||
|
|
||||
LL | / simd_masked_store::<_, _, _, { SimdAlign::Element }>(
|
||||
LL | | Simd([-1i8; 4]),
|
||||
LL | | arr.as_ptr(),
|
||||
LL | | Simd([5u8; 4]),
|
||||
LL | | );
|
||||
| |_________^
|
||||
|
||||
error[E0511]: invalid monomorphization of `simd_masked_store` intrinsic: expected third argument with length 4 (same as input type `Simd<i8, 4>`), found `Simd<u8, 2>` with length 2
|
||||
--> $DIR/masked-load-store-build-fail.rs:34:9
|
||||
--> $DIR/masked-load-store-build-fail.rs:59:9
|
||||
|
|
||||
LL | simd_masked_store(Simd([-1i8; 4]), arr.as_mut_ptr(), Simd([5u8; 2]));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | / simd_masked_store::<_, _, _, { SimdAlign::Element }>(
|
||||
LL | | Simd([-1i8; 4]),
|
||||
LL | | arr.as_mut_ptr(),
|
||||
LL | | Simd([5u8; 2]),
|
||||
LL | | );
|
||||
| |_________^
|
||||
|
||||
error[E0511]: invalid monomorphization of `simd_masked_store` intrinsic: expected mask element type to be an integer, found `f32`
|
||||
--> $DIR/masked-load-store-build-fail.rs:37:9
|
||||
--> $DIR/masked-load-store-build-fail.rs:66:9
|
||||
|
|
||||
LL | simd_masked_store(Simd([1f32; 4]), arr.as_mut_ptr(), Simd([5u8; 4]));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | / simd_masked_store::<_, _, _, { SimdAlign::Element }>(
|
||||
LL | | Simd([1f32; 4]),
|
||||
LL | | arr.as_mut_ptr(),
|
||||
LL | | Simd([5u8; 4]),
|
||||
LL | | );
|
||||
| |_________^
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
//@ check-fail
|
||||
#![feature(repr_simd, core_intrinsics)]
|
||||
|
||||
use std::intrinsics::simd::{simd_masked_load, simd_masked_store};
|
||||
use std::intrinsics::simd::{SimdAlign, simd_masked_load, simd_masked_store};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(simd)]
|
||||
|
|
@ -12,11 +12,18 @@ fn main() {
|
|||
let mut arr = [4u8, 5, 6, 7];
|
||||
let default = Simd::<u8, 4>([9; 4]);
|
||||
|
||||
let _x: Simd<u8, 2> =
|
||||
simd_masked_load(Simd::<i8, 4>([-1, 0, -1, -1]), arr.as_ptr(), Simd::<u8, 4>([9; 4]));
|
||||
//~^ ERROR mismatched types
|
||||
let _x: Simd<u8, 2> = simd_masked_load::<_, _, _, { SimdAlign::Element }>(
|
||||
Simd::<i8, 4>([-1, 0, -1, -1]),
|
||||
arr.as_ptr(),
|
||||
Simd::<u8, 4>([9; 4]),
|
||||
);
|
||||
//~^^ ERROR mismatched types
|
||||
|
||||
let _x: Simd<u32, 4> = simd_masked_load(Simd::<u8, 4>([1, 0, 1, 1]), arr.as_ptr(), default);
|
||||
//~^ ERROR mismatched types
|
||||
let _x: Simd<u32, 4> = simd_masked_load::<_, _, _, { SimdAlign::Element }>(
|
||||
Simd::<u8, 4>([1, 0, 1, 1]),
|
||||
arr.as_ptr(),
|
||||
default,
|
||||
);
|
||||
//~^^ ERROR mismatched types
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,36 +1,50 @@
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/masked-load-store-check-fail.rs:16:76
|
||||
--> $DIR/masked-load-store-check-fail.rs:18:13
|
||||
|
|
||||
LL | simd_masked_load(Simd::<i8, 4>([-1, 0, -1, -1]), arr.as_ptr(), Simd::<u8, 4>([9; 4]));
|
||||
| ---------------- arguments to this function are incorrect ^^^^^^^^^^^^^^^^^^^^^ expected `2`, found `4`
|
||||
LL | let _x: Simd<u8, 2> = simd_masked_load::<_, _, _, { SimdAlign::Element }>(
|
||||
| --------------------------------------------------- arguments to this function are incorrect
|
||||
...
|
||||
LL | Simd::<u8, 4>([9; 4]),
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ expected `2`, found `4`
|
||||
|
|
||||
= note: expected struct `Simd<_, 2>`
|
||||
found struct `Simd<_, 4>`
|
||||
help: the return type of this call is `Simd<u8, 4>` due to the type of the argument passed
|
||||
--> $DIR/masked-load-store-check-fail.rs:16:13
|
||||
--> $DIR/masked-load-store-check-fail.rs:15:31
|
||||
|
|
||||
LL | simd_masked_load(Simd::<i8, 4>([-1, 0, -1, -1]), arr.as_ptr(), Simd::<u8, 4>([9; 4]));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------^
|
||||
| |
|
||||
| this argument influences the return type of `simd_masked_load`
|
||||
LL | let _x: Simd<u8, 2> = simd_masked_load::<_, _, _, { SimdAlign::Element }>(
|
||||
| _______________________________^
|
||||
LL | | Simd::<i8, 4>([-1, 0, -1, -1]),
|
||||
LL | | arr.as_ptr(),
|
||||
LL | | Simd::<u8, 4>([9; 4]),
|
||||
| | --------------------- this argument influences the return type of `simd_masked_load`
|
||||
LL | | );
|
||||
| |_________^
|
||||
note: function defined here
|
||||
--> $SRC_DIR/core/src/intrinsics/simd.rs:LL:COL
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/masked-load-store-check-fail.rs:19:92
|
||||
--> $DIR/masked-load-store-check-fail.rs:25:13
|
||||
|
|
||||
LL | let _x: Simd<u32, 4> = simd_masked_load(Simd::<u8, 4>([1, 0, 1, 1]), arr.as_ptr(), default);
|
||||
| ---------------- arguments to this function are incorrect ^^^^^^^ expected `Simd<u32, 4>`, found `Simd<u8, 4>`
|
||||
LL | let _x: Simd<u32, 4> = simd_masked_load::<_, _, _, { SimdAlign::Element }>(
|
||||
| --------------------------------------------------- arguments to this function are incorrect
|
||||
...
|
||||
LL | default,
|
||||
| ^^^^^^^ expected `Simd<u32, 4>`, found `Simd<u8, 4>`
|
||||
|
|
||||
= note: expected struct `Simd<u32, _>`
|
||||
found struct `Simd<u8, _>`
|
||||
help: the return type of this call is `Simd<u8, 4>` due to the type of the argument passed
|
||||
--> $DIR/masked-load-store-check-fail.rs:19:32
|
||||
--> $DIR/masked-load-store-check-fail.rs:22:32
|
||||
|
|
||||
LL | let _x: Simd<u32, 4> = simd_masked_load(Simd::<u8, 4>([1, 0, 1, 1]), arr.as_ptr(), default);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------^
|
||||
| |
|
||||
| this argument influences the return type of `simd_masked_load`
|
||||
LL | let _x: Simd<u32, 4> = simd_masked_load::<_, _, _, { SimdAlign::Element }>(
|
||||
| ________________________________^
|
||||
LL | | Simd::<u8, 4>([1, 0, 1, 1]),
|
||||
LL | | arr.as_ptr(),
|
||||
LL | | default,
|
||||
| | ------- this argument influences the return type of `simd_masked_load`
|
||||
LL | | );
|
||||
| |_________^
|
||||
note: function defined here
|
||||
--> $SRC_DIR/core/src/intrinsics/simd.rs:LL:COL
|
||||
|
||||
|
|
|
|||
|
|
@ -6,23 +6,34 @@
|
|||
mod minisimd;
|
||||
use minisimd::*;
|
||||
|
||||
use std::intrinsics::simd::{simd_masked_load, simd_masked_store};
|
||||
use std::intrinsics::simd::{SimdAlign, simd_masked_load, simd_masked_store};
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let a = Simd::<u8, 4>([0, 1, 2, 3]);
|
||||
let b_src = [4u8, 5, 6, 7];
|
||||
let b_default = Simd::<u8, 4>([9; 4]);
|
||||
let b: Simd<u8, 4> =
|
||||
simd_masked_load(Simd::<i8, 4>([-1, 0, -1, -1]), b_src.as_ptr(), b_default);
|
||||
let b: Simd<u8, 4> = simd_masked_load::<_, _, _, { SimdAlign::Element }>(
|
||||
Simd::<i8, 4>([-1, 0, -1, -1]),
|
||||
b_src.as_ptr(),
|
||||
b_default,
|
||||
);
|
||||
|
||||
assert_eq!(b.as_array(), &[4, 9, 6, 7]);
|
||||
|
||||
let mut output = [u8::MAX; 5];
|
||||
|
||||
simd_masked_store(Simd::<i8, 4>([-1, -1, -1, 0]), output.as_mut_ptr(), a);
|
||||
simd_masked_store::<_, _, _, { SimdAlign::Element }>(
|
||||
Simd::<i8, 4>([-1, -1, -1, 0]),
|
||||
output.as_mut_ptr(),
|
||||
a,
|
||||
);
|
||||
assert_eq!(&output, &[0, 1, 2, u8::MAX, u8::MAX]);
|
||||
simd_masked_store(Simd::<i8, 4>([0, -1, -1, 0]), output[1..].as_mut_ptr(), b);
|
||||
simd_masked_store::<_, _, _, { SimdAlign::Element }>(
|
||||
Simd::<i8, 4>([0, -1, -1, 0]),
|
||||
output[1..].as_mut_ptr(),
|
||||
b,
|
||||
);
|
||||
assert_eq!(&output, &[0, 1, 9, 6, u8::MAX]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue