diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index ca6128b6f1be4..cca1d499088f4 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -10,8 +10,8 @@ use tracing::{debug, trace}; use crate::{ AbiAlign, Align, BackendRepr, FieldsShape, HasDataLayout, IndexSlice, IndexVec, Integer, - LayoutData, Niche, NonZeroUsize, Primitive, ReprOptions, Scalar, Size, StructKind, TagEncoding, - TargetDataLayout, Variants, WrappingRange, + LayoutData, Niche, NonZeroUsize, NumScalableVectors, Primitive, ReprOptions, Scalar, Size, + StructKind, TagEncoding, TargetDataLayout, Variants, WrappingRange, }; mod coroutine; @@ -204,13 +204,19 @@ impl LayoutCalculator { &self, element: F, count: u64, + number_of_vectors: NumScalableVectors, ) -> LayoutCalculatorResult where FieldIdx: Idx, VariantIdx: Idx, F: AsRef> + fmt::Debug, { - vector_type_layout(SimdVectorKind::Scalable, self.cx.data_layout(), element, count) + vector_type_layout( + SimdVectorKind::Scalable(number_of_vectors), + self.cx.data_layout(), + element, + count, + ) } pub fn simd_type( @@ -1526,7 +1532,7 @@ impl LayoutCalculator { enum SimdVectorKind { /// `#[rustc_scalable_vector]` - Scalable, + Scalable(NumScalableVectors), /// `#[repr(simd, packed)]` PackedFixed, /// `#[repr(simd)]` @@ -1559,9 +1565,10 @@ where let size = elt.size.checked_mul(count, dl).ok_or_else(|| LayoutCalculatorError::SizeOverflow)?; let (repr, align) = match kind { - SimdVectorKind::Scalable => { - (BackendRepr::SimdScalableVector { element, count }, dl.llvmlike_vector_align(size)) - } + SimdVectorKind::Scalable(number_of_vectors) => ( + BackendRepr::SimdScalableVector { element, count, number_of_vectors }, + dl.llvmlike_vector_align(size), + ), // Non-power-of-two vectors have padding up to the next power-of-two. // If we're a packed repr, remove the padding while keeping the alignment as close // to a vector as possible. diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 42e272fdafb5d..f148b776852aa 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1696,6 +1696,28 @@ impl AddressSpace { pub const ZERO: Self = AddressSpace(0); } +/// How many scalable vectors are in a `BackendRepr::ScalableVector`? +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +#[cfg_attr(feature = "nightly", derive(HashStable_Generic))] +pub struct NumScalableVectors(pub u8); + +impl NumScalableVectors { + /// Returns a `NumScalableVector` for a non-tuple scalable vector (e.g. a single vector). + pub fn for_non_tuple() -> Self { + NumScalableVectors(1) + } + + // Returns `NumScalableVectors` for values of two through eight, which are a valid number of + // fields for a tuple of scalable vectors to have. `1` is a valid value of `NumScalableVectors` + // but not for a tuple which would have a field count. + pub fn from_field_count(count: usize) -> Option { + match count { + 2..8 => Some(NumScalableVectors(count as u8)), + _ => None, + } + } +} + /// The way we represent values to the backend /// /// Previously this was conflated with the "ABI" a type is given, as in the platform-specific ABI. @@ -1714,6 +1736,7 @@ pub enum BackendRepr { SimdScalableVector { element: Scalar, count: u64, + number_of_vectors: NumScalableVectors, }, SimdVector { element: Scalar, @@ -1820,8 +1843,12 @@ impl BackendRepr { BackendRepr::SimdVector { element: element.to_union(), count } } BackendRepr::Memory { .. } => BackendRepr::Memory { sized: true }, - BackendRepr::SimdScalableVector { element, count } => { - BackendRepr::SimdScalableVector { element: element.to_union(), count } + BackendRepr::SimdScalableVector { element, count, number_of_vectors } => { + BackendRepr::SimdScalableVector { + element: element.to_union(), + count, + number_of_vectors, + } } } } @@ -2161,7 +2188,7 @@ impl LayoutData { } /// Returns `true` if the size of the type is only known at runtime. - pub fn is_runtime_sized(&self) -> bool { + pub fn is_scalable_vector(&self) -> bool { matches!(self.backend_repr, BackendRepr::SimdScalableVector { .. }) } diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs index 8abcaeb5fbf53..e63baf77c0852 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs @@ -3,8 +3,8 @@ use std::ops::Range; use rustc_errors::E0232; use rustc_hir::AttrPath; use rustc_hir::attrs::diagnostic::{ - AppendConstMessage, Directive, FilterFormatString, Flag, FormatArg, FormatString, LitOrArg, - Name, NameValue, OnUnimplementedCondition, Piece, Predicate, + Directive, FilterFormatString, Flag, FormatArg, FormatString, LitOrArg, Name, NameValue, + OnUnimplementedCondition, Piece, Predicate, }; use rustc_hir::lints::{AttributeLintKind, FormatWarning}; use rustc_macros::Diagnostic; @@ -92,7 +92,6 @@ fn parse_directive_items<'p, S: Stage>( let mut notes = ThinVec::new(); let mut parent_label = None; let mut subcommands = ThinVec::new(); - let mut append_const_msg = None; for item in items { let span = item.span(); @@ -131,7 +130,6 @@ fn parse_directive_items<'p, S: Stage>( let Some(ret) = (||{ Some($($code)*) })() else { - malformed!() }; ret @@ -159,8 +157,13 @@ fn parse_directive_items<'p, S: Stage>( let item: &MetaItemParser = or_malformed!(item.meta_item()?); let name = or_malformed!(item.ident()?).name; - // Some things like `message = "message"` must have a value. - // But with things like `append_const_msg` that is optional. + // Currently, as of April 2026, all arguments of all diagnostic attrs + // must have a value, like `message = "message"`. Thus in a well-formed + // diagnostic attribute this is never `None`. + // + // But we don't assert its presence yet because we don't want to mention it + // if someone does something like `#[diagnostic::on_unimplemented(doesnt_exist)]`. + // That happens in the big `match` below. let value: Option = match item.args().name_value() { Some(nv) => Some(or_malformed!(nv.value_as_ident()?)), None => None, @@ -223,14 +226,6 @@ fn parse_directive_items<'p, S: Stage>( let value = or_malformed!(value?); notes.push(parse_format(value)) } - - (Mode::RustcOnUnimplemented, sym::append_const_msg) => { - append_const_msg = if let Some(msg) = value { - Some(AppendConstMessage::Custom(msg.name, item.span())) - } else { - Some(AppendConstMessage::Default) - } - } (Mode::RustcOnUnimplemented, sym::parent_label) => { let value = or_malformed!(value?); if parent_label.is_none() { @@ -290,7 +285,6 @@ fn parse_directive_items<'p, S: Stage>( label, notes, parent_label, - append_const_msg, }) } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 47f14dc3df62e..cf69dda7b2710 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -447,6 +447,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let tcx = self.infcx.tcx; for proj in &user_ty.projs { + // Necessary for non-trivial patterns whose user-type annotation is an opaque type, + // e.g. `let (_a,): Tait = whatever`, see #105897 if !self.infcx.next_trait_solver() && let ty::Alias(ty::Opaque, ..) = curr_projected_ty.ty.kind() { diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 1d6d77604411c..3cffd862b9b98 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -24,7 +24,8 @@ use rustc_data_structures::fx::FxHashSet; use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::ty::layout::{ - FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTyCtxt, HasTypingEnv, LayoutError, LayoutOfHelpers, + FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTyCtxt, HasTypingEnv, LayoutError, + LayoutOfHelpers, TyAndLayout, }; use rustc_middle::ty::{self, AtomicOrdering, Instance, Ty, TyCtxt}; use rustc_span::Span; @@ -943,8 +944,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { .get_address(self.location) } - fn scalable_alloca(&mut self, _elt: u64, _align: Align, _element_ty: Ty<'_>) -> RValue<'gcc> { - todo!() + fn alloca_with_ty(&mut self, ty: TyAndLayout<'tcx>) -> RValue<'gcc> { + self.alloca(ty.layout.size, ty.layout.align.abi) } fn load(&mut self, pointee_ty: Type<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> { diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index 9e548ac0a8b01..dd0064d34bc4a 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -145,6 +145,10 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> { self.const_int(self.type_i32(), i as i64) } + fn const_i64(&self, i: i64) -> RValue<'gcc> { + self.const_int(self.type_i64(), i) + } + fn const_int(&self, typ: Type<'gcc>, int: i64) -> RValue<'gcc> { self.gcc_int(typ, int) } diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 4e79e4fafac52..056a0763087a2 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -7,8 +7,7 @@ pub(crate) mod autodiff; pub(crate) mod gpu_offload; use libc::{c_char, c_uint}; -use rustc_abi as abi; -use rustc_abi::{Align, Size, WrappingRange}; +use rustc_abi::{self as abi, Align, Size, WrappingRange}; use rustc_codegen_ssa::MemFlags; use rustc_codegen_ssa::common::{IntPredicate, RealPredicate, SynchronizationScope, TypeKind}; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; @@ -616,21 +615,14 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } } - fn scalable_alloca(&mut self, elt: u64, align: Align, element_ty: Ty<'_>) -> Self::Value { + fn alloca_with_ty(&mut self, layout: TyAndLayout<'tcx>) -> Self::Value { let mut bx = Builder::with_cx(self.cx); bx.position_at_start(unsafe { llvm::LLVMGetFirstBasicBlock(self.llfn()) }); - let llvm_ty = match element_ty.kind() { - ty::Bool => bx.type_i1(), - ty::Int(int_ty) => self.cx.type_int_from_ty(*int_ty), - ty::Uint(uint_ty) => self.cx.type_uint_from_ty(*uint_ty), - ty::Float(float_ty) => self.cx.type_float_from_ty(*float_ty), - _ => unreachable!("scalable vectors can only contain a bool, int, uint or float"), - }; + let scalable_vector_ty = layout.llvm_type(self.cx); unsafe { - let ty = llvm::LLVMScalableVectorType(llvm_ty, elt.try_into().unwrap()); - let alloca = llvm::LLVMBuildAlloca(&bx.llbuilder, ty, UNNAMED); - llvm::LLVMSetAlignment(alloca, align.bytes() as c_uint); + let alloca = llvm::LLVMBuildAlloca(&bx.llbuilder, scalable_vector_ty, UNNAMED); + llvm::LLVMSetAlignment(alloca, layout.align.abi.bytes() as c_uint); alloca } } diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index a134e97cc8915..dadf8e9e7d5fa 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -159,6 +159,10 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { self.const_int(self.type_i32(), i as i64) } + fn const_i64(&self, i: i64) -> &'ll Value { + self.const_int(self.type_i64(), i as i64) + } + fn const_int(&self, t: &'ll Type, i: i64) -> &'ll Value { debug_assert!( self.type_kind(t) == TypeKind::Integer, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/dwarf_const.rs b/compiler/rustc_codegen_llvm/src/debuginfo/dwarf_const.rs index 52d04625749b9..1172660af4a29 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/dwarf_const.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/dwarf_const.rs @@ -35,6 +35,14 @@ declare_constant!(DW_OP_plus_uconst: u64); /// Double-checked by a static assertion in `RustWrapper.cpp`. #[allow(non_upper_case_globals)] pub(crate) const DW_OP_LLVM_fragment: u64 = 0x1000; +#[allow(non_upper_case_globals)] +pub(crate) const DW_OP_constu: u64 = 0x10; +#[allow(non_upper_case_globals)] +pub(crate) const DW_OP_minus: u64 = 0x1c; +#[allow(non_upper_case_globals)] +pub(crate) const DW_OP_mul: u64 = 0x1e; +#[allow(non_upper_case_globals)] +pub(crate) const DW_OP_bregx: u64 = 0x92; // It describes the actual value of a source variable which might not exist in registers or in memory. #[allow(non_upper_case_globals)] pub(crate) const DW_OP_stack_value: u64 = 0x9f; diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 04c0b6953290c..c91d3ec63a028 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -3,10 +3,10 @@ use std::fmt::{self, Write}; use std::hash::{Hash, Hasher}; use std::path::PathBuf; use std::sync::Arc; -use std::{iter, ptr}; +use std::{assert_matches, iter, ptr}; use libc::{c_longlong, c_uint}; -use rustc_abi::{Align, Size}; +use rustc_abi::{Align, Layout, NumScalableVectors, Size}; use rustc_codegen_ssa::debuginfo::type_names::{VTableNameKind, cpp_like_debuginfo}; use rustc_codegen_ssa::traits::*; use rustc_hir::def::{CtorKind, DefKind}; @@ -16,12 +16,12 @@ use rustc_middle::ty::layout::{ HasTypingEnv, LayoutOf, TyAndLayout, WIDE_PTR_ADDR, WIDE_PTR_EXTRA, }; use rustc_middle::ty::{ - self, AdtKind, CoroutineArgsExt, ExistentialTraitRef, Instance, Ty, TyCtxt, Visibility, + self, AdtDef, AdtKind, CoroutineArgsExt, ExistentialTraitRef, Instance, Ty, TyCtxt, Visibility, }; use rustc_session::config::{self, DebugInfo, Lto}; use rustc_span::{DUMMY_SP, FileName, RemapPathScopeComponents, SourceFile, Span, Symbol, hygiene}; use rustc_symbol_mangling::typeid_for_trait_ref; -use rustc_target::spec::DebuginfoKind; +use rustc_target::spec::{Arch, DebuginfoKind}; use smallvec::smallvec; use tracing::{debug, instrument}; @@ -33,7 +33,7 @@ use super::type_names::{compute_debuginfo_type_name, compute_debuginfo_vtable_na use super::utils::{DIB, debug_context, get_namespace_for_item, is_node_local_to_unit}; use crate::common::{AsCCharPtr, CodegenCx}; use crate::debuginfo::metadata::type_map::build_type_with_children; -use crate::debuginfo::utils::{WidePtrKind, wide_pointer_kind}; +use crate::debuginfo::utils::{WidePtrKind, create_DIArray, wide_pointer_kind}; use crate::debuginfo::{DIBuilderExt, dwarf_const}; use crate::llvm::debuginfo::{ DIBasicType, DIBuilder, DICompositeType, DIDescriptor, DIFile, DIFlags, DILexicalBlock, @@ -1039,6 +1039,7 @@ fn build_struct_type_di_node<'ll, 'tcx>( span: Span, ) -> DINodeCreationResult<'ll> { let struct_type = unique_type_id.expect_ty(); + let ty::Adt(adt_def, _) = struct_type.kind() else { bug!("build_struct_type_di_node() called with non-struct-type: {:?}", struct_type); }; @@ -1051,6 +1052,21 @@ fn build_struct_type_di_node<'ll, 'tcx>( } else { None }; + let name = compute_debuginfo_type_name(cx.tcx, struct_type, false); + + if struct_type.is_scalable_vector() { + let parts = struct_type.scalable_vector_parts(cx.tcx).unwrap(); + return build_scalable_vector_di_node( + cx, + unique_type_id, + name, + *adt_def, + parts, + struct_type_and_layout.layout, + def_location, + containing_scope, + ); + } type_map::build_type_with_children( cx, @@ -1058,7 +1074,7 @@ fn build_struct_type_di_node<'ll, 'tcx>( cx, Stub::Struct, unique_type_id, - &compute_debuginfo_type_name(cx.tcx, struct_type, false), + &name, def_location, size_and_align_of(struct_type_and_layout), Some(containing_scope), @@ -1101,6 +1117,100 @@ fn build_struct_type_di_node<'ll, 'tcx>( ) } +/// Generate debuginfo for a `#[rustc_scalable_vector]` type. +/// +/// Debuginfo for a scalable vector uses a derived type based on a composite type. The composite +/// type has the `DIFlagVector` flag set and is based on the element type of the scalable vector. +/// The composite type has a subrange from 0 to an expression that calculates the number of +/// elements in the vector. +/// +/// ```text,ignore +/// !1 = !DIDerivedType(tag: DW_TAG_typedef, name: "svint16_t", ..., baseType: !2, ...) +/// !2 = !DICompositeType(tag: DW_TAG_array_type, baseType: !3, ..., flags: DIFlagVector, elements: !4) +/// !3 = !DIBasicType(name: "i16", size: 16, encoding: DW_ATE_signed) +/// !4 = !{!5} +/// !5 = !DISubrange(lowerBound: 0, upperBound: !DIExpression(DW_OP_constu, 4, DW_OP_bregx, 46, 0, DW_OP_mul, DW_OP_constu, 1, DW_OP_minus)) +/// ``` +/// +/// See the `CodegenType::CreateType(const BuiltinType *BT)` implementation in Clang for how this +/// is generated for C and C++. +fn build_scalable_vector_di_node<'ll, 'tcx>( + cx: &CodegenCx<'ll, 'tcx>, + unique_type_id: UniqueTypeId<'tcx>, + name: String, + adt_def: AdtDef<'tcx>, + (element_count, element_ty, number_of_vectors): (u16, Ty<'tcx>, NumScalableVectors), + layout: Layout<'tcx>, + def_location: Option>, + containing_scope: &'ll DIScope, +) -> DINodeCreationResult<'ll> { + use dwarf_const::{DW_OP_bregx, DW_OP_constu, DW_OP_minus, DW_OP_mul}; + assert!(adt_def.repr().scalable()); + // This logic is specific to AArch64 for the moment, but can be extended for other architectures + // later. + assert_matches!(cx.tcx.sess.target.arch, Arch::AArch64); + + let (file_metadata, line_number) = if let Some(def_location) = def_location { + (def_location.0, def_location.1) + } else { + (unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER) + }; + + let (bitstride, element_di_node) = if element_ty.is_bool() { + (Some(llvm::LLVMValueAsMetadata(cx.const_i64(1))), type_di_node(cx, cx.tcx.types.u8)) + } else { + (None, type_di_node(cx, element_ty)) + }; + + let number_of_elements: u64 = (element_count as u64) * (number_of_vectors.0 as u64); + let number_of_elements_per_vg = number_of_elements / 2; + let mut expr = smallvec::SmallVec::<[u64; 9]>::new(); + // `($number_of_elements_per_vector_granule * (value_of_register(AArch64::VG) + 0)) - 1` + expr.push(DW_OP_constu); // Push a constant onto the stack + expr.push(number_of_elements_per_vg); + expr.push(DW_OP_bregx); // Push the value of a register + offset on to the stack + expr.push(/* AArch64::VG */ 46u64); + expr.push(0u64); + expr.push(DW_OP_mul); // Multiply top two values on stack + expr.push(DW_OP_constu); // Push a constant onto the stack + expr.push(1u64); + expr.push(DW_OP_minus); // Subtract top two values on stack + + let di_builder = DIB(cx); + let metadata = unsafe { + let upper = llvm::LLVMDIBuilderCreateExpression(di_builder, expr.as_ptr(), expr.len()); + let subrange = llvm::LLVMRustDIGetOrCreateSubrange( + di_builder, + /* CountNode */ None, + llvm::LLVMValueAsMetadata(cx.const_i64(0)), + upper, + /* Stride */ None, + ); + let subscripts = create_DIArray(di_builder, &[Some(subrange)]); + let vector_ty = llvm::LLVMRustDICreateVectorType( + di_builder, + /* Size */ 0, + layout.align.bits() as u32, + element_di_node, + subscripts, + bitstride, + ); + llvm::LLVMDIBuilderCreateTypedef( + di_builder, + vector_ty, + name.as_ptr(), + name.len(), + file_metadata, + line_number, + Some(containing_scope), + layout.align.bits() as u32, + ) + }; + + debug_context(cx).type_map.insert(unique_type_id, metadata); + DINodeCreationResult { di_node: metadata, already_stored_in_typemap: true } +} + //=----------------------------------------------------------------------------- // Tuples //=----------------------------------------------------------------------------- diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 39bf4c10dab18..3e600914d6f42 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -3,7 +3,8 @@ use std::ffi::c_uint; use std::{assert_matches, ptr}; use rustc_abi::{ - Align, BackendRepr, ExternAbi, Float, HasDataLayout, Primitive, Size, WrappingRange, + Align, BackendRepr, ExternAbi, Float, HasDataLayout, NumScalableVectors, Primitive, Size, + WrappingRange, }; use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh, wants_wasm_eh}; use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; @@ -605,6 +606,136 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { self.pointercast(val, self.type_ptr()) } + sym::sve_cast => { + let Some((in_cnt, in_elem, in_num_vecs)) = + args[0].layout.ty.scalable_vector_parts(self.cx.tcx) + else { + bug!("input parameter to `sve_cast` was not scalable vector"); + }; + let out_layout = self.layout_of(fn_args.type_at(1)); + let Some((out_cnt, out_elem, out_num_vecs)) = + out_layout.ty.scalable_vector_parts(self.cx.tcx) + else { + bug!("output parameter to `sve_cast` was not scalable vector"); + }; + assert_eq!(in_cnt, out_cnt); + assert_eq!(in_num_vecs, out_num_vecs); + let out_llty = self.backend_type(out_layout); + match simd_cast(self, sym::simd_cast, args, out_llty, in_elem, out_elem) { + Some(val) => val, + _ => bug!("could not cast scalable vectors"), + } + } + + sym::sve_tuple_create2 => { + assert_matches!( + self.layout_of(fn_args.type_at(0)).backend_repr, + BackendRepr::SimdScalableVector { + number_of_vectors: NumScalableVectors(1), + .. + } + ); + let tuple_ty = self.layout_of(fn_args.type_at(1)); + assert_matches!( + tuple_ty.backend_repr, + BackendRepr::SimdScalableVector { + number_of_vectors: NumScalableVectors(2), + .. + } + ); + let ret = self.const_poison(self.backend_type(tuple_ty)); + let ret = self.insert_value(ret, args[0].immediate(), 0); + self.insert_value(ret, args[1].immediate(), 1) + } + + sym::sve_tuple_create3 => { + assert_matches!( + self.layout_of(fn_args.type_at(0)).backend_repr, + BackendRepr::SimdScalableVector { + number_of_vectors: NumScalableVectors(1), + .. + } + ); + let tuple_ty = self.layout_of(fn_args.type_at(1)); + assert_matches!( + tuple_ty.backend_repr, + BackendRepr::SimdScalableVector { + number_of_vectors: NumScalableVectors(3), + .. + } + ); + let ret = self.const_poison(self.backend_type(tuple_ty)); + let ret = self.insert_value(ret, args[0].immediate(), 0); + let ret = self.insert_value(ret, args[1].immediate(), 1); + self.insert_value(ret, args[2].immediate(), 2) + } + + sym::sve_tuple_create4 => { + assert_matches!( + self.layout_of(fn_args.type_at(0)).backend_repr, + BackendRepr::SimdScalableVector { + number_of_vectors: NumScalableVectors(1), + .. + } + ); + let tuple_ty = self.layout_of(fn_args.type_at(1)); + assert_matches!( + tuple_ty.backend_repr, + BackendRepr::SimdScalableVector { + number_of_vectors: NumScalableVectors(4), + .. + } + ); + let ret = self.const_poison(self.backend_type(tuple_ty)); + let ret = self.insert_value(ret, args[0].immediate(), 0); + let ret = self.insert_value(ret, args[1].immediate(), 1); + let ret = self.insert_value(ret, args[2].immediate(), 2); + self.insert_value(ret, args[3].immediate(), 3) + } + + sym::sve_tuple_get => { + assert_matches!( + self.layout_of(fn_args.type_at(0)).backend_repr, + BackendRepr::SimdScalableVector { + number_of_vectors: NumScalableVectors(2 | 3 | 4 | 5 | 6 | 7 | 8), + .. + } + ); + assert_matches!( + self.layout_of(fn_args.type_at(1)).backend_repr, + BackendRepr::SimdScalableVector { + number_of_vectors: NumScalableVectors(1), + .. + } + ); + self.extract_value( + args[0].immediate(), + fn_args.const_at(2).to_leaf().to_i32() as u64, + ) + } + + sym::sve_tuple_set => { + assert_matches!( + self.layout_of(fn_args.type_at(0)).backend_repr, + BackendRepr::SimdScalableVector { + number_of_vectors: NumScalableVectors(2 | 3 | 4 | 5 | 6 | 7 | 8), + .. + } + ); + assert_matches!( + self.layout_of(fn_args.type_at(1)).backend_repr, + BackendRepr::SimdScalableVector { + number_of_vectors: NumScalableVectors(1), + .. + } + ); + self.insert_value( + args[0].immediate(), + args[1].immediate(), + fn_args.const_at(2).to_leaf().to_i32() as u64, + ) + } + _ if name.as_str().starts_with("simd_") => { // Unpack non-power-of-2 #[repr(packed, simd)] arguments. // This gives them the expected layout of a regular #[repr(simd)] vector. @@ -2662,96 +2793,17 @@ fn generic_simd_intrinsic<'ll, 'tcx>( out_len } ); - // casting cares about nominal type, not just structural type - if in_elem == out_elem { - return Ok(args[0].immediate()); - } - - #[derive(Copy, Clone)] - enum Sign { - Unsigned, - Signed, - } - use Sign::*; - - enum Style { - Float, - Int(Sign), - Unsupported, - } - - let (in_style, in_width) = match in_elem.kind() { - // vectors of pointer-sized integers should've been - // disallowed before here, so this unwrap is safe. - ty::Int(i) => ( - Style::Int(Signed), - i.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(), - ), - ty::Uint(u) => ( - Style::Int(Unsigned), - u.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(), - ), - ty::Float(f) => (Style::Float, f.bit_width()), - _ => (Style::Unsupported, 0), - }; - let (out_style, out_width) = match out_elem.kind() { - ty::Int(i) => ( - Style::Int(Signed), - i.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(), - ), - ty::Uint(u) => ( - Style::Int(Unsigned), - u.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(), - ), - ty::Float(f) => (Style::Float, f.bit_width()), - _ => (Style::Unsupported, 0), - }; - - match (in_style, out_style) { - (Style::Int(sign), Style::Int(_)) => { - return Ok(match in_width.cmp(&out_width) { - Ordering::Greater => bx.trunc(args[0].immediate(), llret_ty), - Ordering::Equal => args[0].immediate(), - Ordering::Less => match sign { - Sign::Signed => bx.sext(args[0].immediate(), llret_ty), - Sign::Unsigned => bx.zext(args[0].immediate(), llret_ty), - }, - }); - } - (Style::Int(Sign::Signed), Style::Float) => { - return Ok(bx.sitofp(args[0].immediate(), llret_ty)); - } - (Style::Int(Sign::Unsigned), Style::Float) => { - return Ok(bx.uitofp(args[0].immediate(), llret_ty)); - } - (Style::Float, Style::Int(sign)) => { - return Ok(match (sign, name == sym::simd_as) { - (Sign::Unsigned, false) => bx.fptoui(args[0].immediate(), llret_ty), - (Sign::Signed, false) => bx.fptosi(args[0].immediate(), llret_ty), - (_, true) => bx.cast_float_to_int( - matches!(sign, Sign::Signed), - args[0].immediate(), - llret_ty, - ), - }); - } - (Style::Float, Style::Float) => { - return Ok(match in_width.cmp(&out_width) { - Ordering::Greater => bx.fptrunc(args[0].immediate(), llret_ty), - Ordering::Equal => args[0].immediate(), - Ordering::Less => bx.fpext(args[0].immediate(), llret_ty), - }); - } - _ => { /* Unsupported. Fallthrough. */ } + match simd_cast(bx, name, args, llret_ty, in_elem, out_elem) { + Some(val) => return Ok(val), + None => return_error!(InvalidMonomorphization::UnsupportedCast { + span, + name, + in_ty, + in_elem, + ret_ty, + out_elem + }), } - return_error!(InvalidMonomorphization::UnsupportedCast { - span, - name, - in_ty, - in_elem, - ret_ty, - out_elem - }); } macro_rules! arith_binary { ($($name: ident: $($($p: ident),* => $call: ident),*;)*) => { @@ -2925,3 +2977,86 @@ fn generic_simd_intrinsic<'ll, 'tcx>( span_bug!(span, "unknown SIMD intrinsic"); } + +/// Implementation of `core::intrinsics::simd_cast`, re-used by `core::scalable::sve_cast`. +fn simd_cast<'ll, 'tcx>( + bx: &mut Builder<'_, 'll, 'tcx>, + name: Symbol, + args: &[OperandRef<'tcx, &'ll Value>], + llret_ty: &'ll Type, + in_elem: Ty<'tcx>, + out_elem: Ty<'tcx>, +) -> Option<&'ll Value> { + // Casting cares about nominal type, not just structural type + if in_elem == out_elem { + return Some(args[0].immediate()); + } + + #[derive(Copy, Clone)] + enum Sign { + Unsigned, + Signed, + } + use Sign::*; + + enum Style { + Float, + Int(Sign), + Unsupported, + } + + let (in_style, in_width) = match in_elem.kind() { + // vectors of pointer-sized integers should've been + // disallowed before here, so this unwrap is safe. + ty::Int(i) => ( + Style::Int(Signed), + i.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(), + ), + ty::Uint(u) => ( + Style::Int(Unsigned), + u.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(), + ), + ty::Float(f) => (Style::Float, f.bit_width()), + _ => (Style::Unsupported, 0), + }; + let (out_style, out_width) = match out_elem.kind() { + ty::Int(i) => ( + Style::Int(Signed), + i.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(), + ), + ty::Uint(u) => ( + Style::Int(Unsigned), + u.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(), + ), + ty::Float(f) => (Style::Float, f.bit_width()), + _ => (Style::Unsupported, 0), + }; + + match (in_style, out_style) { + (Style::Int(sign), Style::Int(_)) => Some(match in_width.cmp(&out_width) { + Ordering::Greater => bx.trunc(args[0].immediate(), llret_ty), + Ordering::Equal => args[0].immediate(), + Ordering::Less => match sign { + Sign::Signed => bx.sext(args[0].immediate(), llret_ty), + Sign::Unsigned => bx.zext(args[0].immediate(), llret_ty), + }, + }), + (Style::Int(Sign::Signed), Style::Float) => Some(bx.sitofp(args[0].immediate(), llret_ty)), + (Style::Int(Sign::Unsigned), Style::Float) => { + Some(bx.uitofp(args[0].immediate(), llret_ty)) + } + (Style::Float, Style::Int(sign)) => Some(match (sign, name == sym::simd_as) { + (Sign::Unsigned, false) => bx.fptoui(args[0].immediate(), llret_ty), + (Sign::Signed, false) => bx.fptosi(args[0].immediate(), llret_ty), + (_, true) => { + bx.cast_float_to_int(matches!(sign, Sign::Signed), args[0].immediate(), llret_ty) + } + }), + (Style::Float, Style::Float) => Some(match in_width.cmp(&out_width) { + Ordering::Greater => bx.fptrunc(args[0].immediate(), llret_ty), + Ordering::Equal => args[0].immediate(), + Ordering::Less => bx.fpext(args[0].immediate(), llret_ty), + }), + _ => None, + } +} diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 7355d11367920..0ad74c9ca43a7 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2302,6 +2302,23 @@ unsafe extern "C" { Params: Option<&'a DIArray>, ); + pub(crate) fn LLVMRustDIGetOrCreateSubrange<'a>( + Builder: &DIBuilder<'a>, + CountNode: Option<&'a Metadata>, + LB: &'a Metadata, + UB: &'a Metadata, + Stride: Option<&'a Metadata>, + ) -> &'a Metadata; + + pub(crate) fn LLVMRustDICreateVectorType<'a>( + Builder: &DIBuilder<'a>, + Size: u64, + AlignInBits: u32, + Type: &'a DIType, + Subscripts: &'a DIArray, + BitStride: Option<&'a Metadata>, + ) -> &'a Metadata; + pub(crate) fn LLVMRustDILocationCloneWithBaseDiscriminator<'a>( Location: &'a DILocation, BD: c_uint, diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index e586ed0dd6b07..6d0490e4a1f79 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -24,14 +24,54 @@ fn uncached_llvm_type<'a, 'tcx>( let element = layout.scalar_llvm_type_at(cx, element); return cx.type_vector(element, count); } - BackendRepr::SimdScalableVector { ref element, count } => { + BackendRepr::SimdScalableVector { ref element, count, number_of_vectors } => { let element = if element.is_bool() { cx.type_i1() } else { layout.scalar_llvm_type_at(cx, *element) }; - return cx.type_scalable_vector(element, count); + let vector_type = cx.type_scalable_vector(element, count); + return match number_of_vectors.0 { + 1 => vector_type, + 2 => cx.type_struct(&[vector_type, vector_type], false), + 3 => cx.type_struct(&[vector_type, vector_type, vector_type], false), + 4 => cx.type_struct(&[vector_type, vector_type, vector_type, vector_type], false), + 5 => cx.type_struct( + &[vector_type, vector_type, vector_type, vector_type, vector_type], + false, + ), + 6 => cx.type_struct( + &[vector_type, vector_type, vector_type, vector_type, vector_type, vector_type], + false, + ), + 7 => cx.type_struct( + &[ + vector_type, + vector_type, + vector_type, + vector_type, + vector_type, + vector_type, + vector_type, + ], + false, + ), + 8 => cx.type_struct( + &[ + vector_type, + vector_type, + vector_type, + vector_type, + vector_type, + vector_type, + vector_type, + vector_type, + ], + false, + ), + _ => bug!("`#[rustc_scalable_vector]` tuple struct with too many fields"), + }; } BackendRepr::Memory { .. } | BackendRepr::ScalarPair(..) => {} } diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 2f93f688c316d..60ab13dbc6f76 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -438,8 +438,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if operand.layout.ty.is_scalable_vector() && bx.sess().target.arch == rustc_target::spec::Arch::AArch64 { - let (count, element_ty) = - operand.layout.ty.scalable_vector_element_count_and_type(bx.tcx()); + let (count, element_ty, _) = + operand.layout.ty.scalable_vector_parts(bx.tcx()).unwrap(); // i.e. `` when `N != 16` if element_ty.is_bool() && count != 16 { return; diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index d62e622b6fed3..53518fd816f31 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -1,3 +1,5 @@ +use std::ops::Deref as _; + use rustc_abi::{ Align, BackendRepr, FieldIdx, FieldsShape, Size, TagEncoding, VariantIdx, Variants, }; @@ -109,8 +111,8 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { bx: &mut Bx, layout: TyAndLayout<'tcx>, ) -> Self { - if layout.is_runtime_sized() { - Self::alloca_runtime_sized(bx, layout) + if layout.deref().is_scalable_vector() { + Self::alloca_scalable(bx, layout) } else { Self::alloca_size(bx, layout.size, layout) } @@ -151,16 +153,11 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { } } - fn alloca_runtime_sized>( + fn alloca_scalable>( bx: &mut Bx, layout: TyAndLayout<'tcx>, ) -> Self { - let (element_count, ty) = layout.ty.scalable_vector_element_count_and_type(bx.tcx()); - PlaceValue::new_sized( - bx.scalable_alloca(element_count as u64, layout.align.abi, ty), - layout.align.abi, - ) - .with_type(layout) + PlaceValue::new_sized(bx.alloca_with_ty(layout), layout.align.abi).with_type(layout) } } diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 2076e2bb26274..c222aef4574bf 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -235,7 +235,7 @@ pub trait BuilderMethods<'a, 'tcx>: fn to_immediate_scalar(&mut self, val: Self::Value, scalar: Scalar) -> Self::Value; fn alloca(&mut self, size: Size, align: Align) -> Self::Value; - fn scalable_alloca(&mut self, elt: u64, align: Align, element_ty: Ty<'_>) -> Self::Value; + fn alloca_with_ty(&mut self, layout: TyAndLayout<'tcx>) -> Self::Value; fn load(&mut self, ty: Self::Type, ptr: Self::Value, align: Align) -> Self::Value; fn volatile_load(&mut self, ty: Self::Type, ptr: Self::Value) -> Self::Value; diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs index 4178a9742e268..22784a8868ab5 100644 --- a/compiler/rustc_codegen_ssa/src/traits/consts.rs +++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs @@ -20,6 +20,7 @@ pub trait ConstCodegenMethods: BackendTypes { fn const_i8(&self, i: i8) -> Self::Value; fn const_i16(&self, i: i16) -> Self::Value; fn const_i32(&self, i: i32) -> Self::Value; + fn const_i64(&self, i: i64) -> Self::Value; fn const_int(&self, t: Self::Type, i: i64) -> Self::Value; fn const_u8(&self, i: u8) -> Self::Value; fn const_u32(&self, i: u32) -> Self::Value; diff --git a/compiler/rustc_errors/src/decorate_diag.rs b/compiler/rustc_errors/src/decorate_diag.rs index 61dd8f0493f91..3215914698896 100644 --- a/compiler/rustc_errors/src/decorate_diag.rs +++ b/compiler/rustc_errors/src/decorate_diag.rs @@ -1,3 +1,5 @@ +use std::any::Any; + /// This module provides types and traits for buffering lints until later in compilation. use rustc_ast::node_id::NodeId; use rustc_data_structures::fx::FxIndexMap; @@ -10,9 +12,11 @@ use crate::{Diag, DiagCtxtHandle, Diagnostic, Level}; /// We can't implement `Diagnostic` for `BuiltinLintDiag`, because decorating some of its /// variants requires types we don't have yet. So, handle that case separately. pub enum DecorateDiagCompat { + /// The third argument of the closure is a `Session`. However, due to the dependency tree, + /// we don't have access to `rustc_session` here, so we downcast it when needed. Dynamic( Box< - dyn for<'a> FnOnce(DiagCtxtHandle<'a>, Level) -> Diag<'a, ()> + dyn for<'a> FnOnce(DiagCtxtHandle<'a>, Level, &dyn Any) -> Diag<'a, ()> + DynSync + DynSend + 'static, @@ -30,7 +34,7 @@ impl std::fmt::Debug for DecorateDiagCompat { impl Diagnostic<'a, ()> + DynSync + DynSend + 'static> From for DecorateDiagCompat { #[inline] fn from(d: D) -> Self { - Self::Dynamic(Box::new(|dcx, level| d.into_diag(dcx, level))) + Self::Dynamic(Box::new(|dcx, level, _| d.into_diag(dcx, level))) } } @@ -97,6 +101,26 @@ impl LintBuffer { node_id: NodeId, span: impl Into, callback: F, + ) { + self.add_early_lint(BufferedEarlyLint { + lint_id: LintId::of(lint), + node_id, + span: Some(span.into()), + diagnostic: DecorateDiagCompat::Dynamic(Box::new(|dcx, level, _| callback(dcx, level))), + }); + } + + pub fn dyn_buffer_lint_any< + F: for<'a> FnOnce(DiagCtxtHandle<'a>, Level, &dyn Any) -> Diag<'a, ()> + + DynSend + + DynSync + + 'static, + >( + &mut self, + lint: &'static Lint, + node_id: NodeId, + span: impl Into, + callback: F, ) { self.add_early_lint(BufferedEarlyLint { lint_id: LintId::of(lint), diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 9525a45d55f1b..7acf95d77d40e 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -7,7 +7,6 @@ use std::panic; use std::path::PathBuf; use std::thread::panicking; -use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_error_messages::{DiagArgMap, DiagArgName, DiagArgValue, IntoDiagArg}; use rustc_lint_defs::{Applicability, LintExpectationId}; use rustc_macros::{Decodable, Encodable}; @@ -119,16 +118,6 @@ where } } -impl<'a> Diagnostic<'a, ()> - for Box< - dyn for<'b> FnOnce(DiagCtxtHandle<'b>, Level) -> Diag<'b, ()> + DynSync + DynSend + 'static, - > -{ - fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { - self(dcx, level) - } -} - /// Type used to emit diagnostic through a closure instead of implementing the `Diagnostic` trait. pub struct DiagDecorator)>(pub F); diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index a9ad07be319c3..859a1ad391cb9 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -581,6 +581,9 @@ declare_features! ( (unstable, marker_trait_attr, "1.30.0", Some(29864)), /// Enable mgca `type const` syntax before expansion. (incomplete, mgca_type_const_syntax, "1.95.0", Some(132980)), + /// Allows additional const parameter types, such as [u8; 10] or user defined types. + /// User defined types must not have fields more private than the type itself. + (unstable, min_adt_const_params, "CURRENT_RUSTC_VERSION", Some(154042)), /// Enables the generic const args MVP (only bare paths, not arbitrary computation). (incomplete, min_generic_const_args, "1.84.0", Some(132980)), /// A minimal, sound subset of specialization intended to be used by the diff --git a/compiler/rustc_hir/src/attrs/diagnostic.rs b/compiler/rustc_hir/src/attrs/diagnostic.rs index 7c66b3f844691..c700ca142759e 100644 --- a/compiler/rustc_hir/src/attrs/diagnostic.rs +++ b/compiler/rustc_hir/src/attrs/diagnostic.rs @@ -19,7 +19,6 @@ pub struct Directive { pub label: Option<(Span, FormatString)>, pub notes: ThinVec, pub parent_label: Option, - pub append_const_msg: Option, } impl Directive { @@ -63,7 +62,6 @@ impl Directive { let mut label = None; let mut notes = Vec::new(); let mut parent_label = None; - let mut append_const_msg = None; info!( "evaluate_directive({:?}, trait_ref={:?}, options={:?}, args ={:?})", self, trait_name, condition_options, args @@ -91,8 +89,6 @@ impl Directive { if let Some(ref parent_label_) = command.parent_label { parent_label = Some(parent_label_.clone()); } - - append_const_msg = command.append_const_msg; } OnUnimplementedNote { @@ -100,7 +96,6 @@ impl Directive { message: message.map(|m| m.1.format(args)), notes: notes.into_iter().map(|n| n.format(args)).collect(), parent_label: parent_label.map(|e_s| e_s.format(args)), - append_const_msg, } } } @@ -111,17 +106,6 @@ pub struct OnUnimplementedNote { pub label: Option, pub notes: Vec, pub parent_label: Option, - // If none, should fall back to a generic message - pub append_const_msg: Option, -} - -/// Append a message for `[const] Trait` errors. -#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)] -#[derive(HashStable_Generic, Encodable, Decodable, PrintAttribute)] -pub enum AppendConstMessage { - #[default] - Default, - Custom(Symbol, Span), } /// Like [std::fmt::Arguments] this is a string that has been parsed into "pieces", diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index b1dc593331c6c..58454cfc489c6 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -783,6 +783,13 @@ pub(crate) fn check_intrinsic_type( sym::simd_shuffle => (3, 0, vec![param(0), param(0), param(1)], param(2)), sym::simd_shuffle_const_generic => (2, 1, vec![param(0), param(0)], param(1)), + sym::sve_cast => (2, 0, vec![param(0)], param(1)), + sym::sve_tuple_create2 => (2, 0, vec![param(0), param(0)], param(1)), + sym::sve_tuple_create3 => (2, 0, vec![param(0), param(0), param(0)], param(1)), + sym::sve_tuple_create4 => (2, 0, vec![param(0), param(0), param(0), param(0)], param(1)), + sym::sve_tuple_get => (2, 1, vec![param(0)], param(1)), + sym::sve_tuple_set => (2, 1, vec![param(0), param(1)], param(0)), + sym::atomic_cxchg | sym::atomic_cxchgweak => ( 1, 2, diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 96d0a56f901ad..52cb061177c1f 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -842,7 +842,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &ty::GenericParamDef) -> Result<(), Er let span = tcx.def_span(param.def_id); let def_id = param.def_id.expect_local(); - if tcx.features().adt_const_params() { + if tcx.features().adt_const_params() || tcx.features().min_adt_const_params() { enter_wf_checking_ctxt(tcx, tcx.local_parent(def_id), |wfcx| { wfcx.register_bound( ObligationCause::new(span, def_id, ObligationCauseCode::ConstParam(ty)), diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index abd5c024ef79c..61453e5328d5f 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -184,6 +184,26 @@ fn visit_implementation_of_const_param_ty(checker: &Checker<'_>) -> Result<(), E return Ok(()); } + if !tcx.features().adt_const_params() { + match *self_type.kind() { + ty::Adt(adt, _) if adt.is_struct() => { + let struct_vis = tcx.visibility(adt.did()); + for variant in adt.variants() { + for field in &variant.fields { + if !field.vis.is_at_least(struct_vis, tcx) { + let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span; + return Err(tcx + .dcx() + .emit_err(errors::ConstParamTyFieldVisMismatch { span })); + } + } + } + } + + _ => {} + } + } + let cause = traits::ObligationCause::misc(DUMMY_SP, impl_did); match type_allowed_to_implement_const_param_ty(tcx, param_env, self_type, cause) { Ok(()) => Ok(()), diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index fcd4cb938bf73..c55b9e384c55b 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -317,6 +317,14 @@ pub(crate) struct ConstParamTyImplOnNonAdt { pub span: Span, } +#[derive(Diagnostic)] +#[diag("the trait `ConstParamTy` may not be implemented for this struct")] +pub(crate) struct ConstParamTyFieldVisMismatch { + #[primary_span] + #[label("struct fields are less visible than the struct")] + pub span: Span, +} + #[derive(Diagnostic)] #[diag("at least one trait is required for an object type", code = E0224)] pub(crate) struct TraitObjectDeclaredWithNoTraits { diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index c5b3d7065fa92..85bcc2745254d 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1214,6 +1214,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { unsatisfied_predicates, ) }; + if let SelfSource::MethodCall(rcvr_expr) = source { + self.err_ctxt().note_field_shadowed_by_private_candidate( + &mut err, + rcvr_expr.hir_id, + self.param_env, + ); + } self.set_label_for_method_error( &mut err, diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index cf61728f7c2a3..f21db0bf85550 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -249,6 +249,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rhs_ty_var, Some(lhs_expr), |err, ty| { + self.err_ctxt().note_field_shadowed_by_private_candidate( + err, + rhs_expr.hir_id, + self.param_env, + ); if let Op::BinOp(binop) = op && binop.node == hir::BinOpKind::Eq { @@ -331,6 +336,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lhs_expr.span, format!("cannot use `{}` on type `{}`", s, lhs_ty_str), ); + let err_ctxt = self.err_ctxt(); + err_ctxt.note_field_shadowed_by_private_candidate( + &mut err, + lhs_expr.hir_id, + self.param_env, + ); + err_ctxt.note_field_shadowed_by_private_candidate( + &mut err, + rhs_expr.hir_id, + self.param_env, + ); self.note_unmet_impls_on_type(&mut err, &errors, false); (err, None) } @@ -391,6 +407,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_label(lhs_expr.span, lhs_ty_str.clone()); err.span_label(rhs_expr.span, rhs_ty_str); } + let err_ctxt = self.err_ctxt(); + err_ctxt.note_field_shadowed_by_private_candidate( + &mut err, + lhs_expr.hir_id, + self.param_env, + ); + err_ctxt.note_field_shadowed_by_private_candidate( + &mut err, + rhs_expr.hir_id, + self.param_env, + ); let suggest_derive = self.can_eq(self.param_env, lhs_ty, rhs_ty); self.note_unmet_impls_on_type(&mut err, &errors, suggest_derive); (err, output_def_id) diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 7d9c2e8327b91..635185be1cb76 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -15,9 +15,9 @@ use rustc_session::lint::LintPass; use rustc_span::{DUMMY_SP, Ident, Span}; use tracing::debug; -use crate::DecorateBuiltinLint; use crate::context::{EarlyContext, LintContext, LintStore}; use crate::passes::{EarlyLintPass, EarlyLintPassObject}; +use crate::{DecorateBuiltinLint, DiagAndSess}; pub(super) mod diagnostics; @@ -49,8 +49,12 @@ impl<'ecx, 'tcx, T: EarlyLintPass> EarlyContextAndPass<'ecx, 'tcx, T> { }, ); } - DecorateDiagCompat::Dynamic(d) => { - self.context.opt_span_lint(lint_id.lint, span, d); + DecorateDiagCompat::Dynamic(callback) => { + self.context.opt_span_lint( + lint_id.lint, + span, + DiagAndSess { callback, sess: self.context.sess() }, + ); } } } diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 75824670d2496..aee16526dfc0b 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -1,5 +1,7 @@ +use std::any::Any; use std::borrow::Cow; +use rustc_data_structures::sync::DynSend; use rustc_errors::{ Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, Level, elided_lifetime_in_path_suggestion, @@ -8,12 +10,24 @@ use rustc_hir::lints::{AttributeLintKind, FormatWarning}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_session::lint::BuiltinLintDiag; -use tracing::debug; use crate::lints; mod check_cfg; +pub struct DiagAndSess<'sess> { + pub callback: Box< + dyn for<'b> FnOnce(DiagCtxtHandle<'b>, Level, &dyn Any) -> Diag<'b, ()> + DynSend + 'static, + >, + pub sess: &'sess Session, +} + +impl<'a> Diagnostic<'a, ()> for DiagAndSess<'_> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + (self.callback)(dcx, level, self.sess) + } +} + /// This is a diagnostic struct that will decorate a `BuiltinLintDiag` /// Directly creating the lint structs is expensive, using this will only decorate the lint structs when needed. pub struct DecorateBuiltinLint<'sess, 'tcx> { @@ -25,28 +39,6 @@ pub struct DecorateBuiltinLint<'sess, 'tcx> { impl<'a> Diagnostic<'a, ()> for DecorateBuiltinLint<'_, '_> { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { match self.diagnostic { - BuiltinLintDiag::AbsPathWithModule(mod_span) => { - let (replacement, applicability) = - match self.sess.source_map().span_to_snippet(mod_span) { - Ok(ref s) => { - // FIXME(Manishearth) ideally the emitting code - // can tell us whether or not this is global - let opt_colon = - if s.trim_start().starts_with("::") { "" } else { "::" }; - - (format!("crate{opt_colon}{s}"), Applicability::MachineApplicable) - } - Err(_) => ("crate::".to_string(), Applicability::HasPlaceholders), - }; - lints::AbsPathWithModule { - sugg: lints::AbsPathWithModuleSugg { - span: mod_span, - applicability, - replacement, - }, - } - .into_diag(dcx, level) - } BuiltinLintDiag::ElidedLifetimesInPaths( n, path_span, @@ -87,36 +79,6 @@ impl<'a> Diagnostic<'a, ()> for DecorateBuiltinLint<'_, '_> { } .into_diag(dcx, level) } - BuiltinLintDiag::SingleUseLifetime { - param_span, - use_span, - elidable, - deletion_span, - ident, - } => { - debug!(?param_span, ?use_span, ?deletion_span); - let suggestion = if let Some(deletion_span) = deletion_span { - let (use_span, replace_lt) = if elidable { - let use_span = - self.sess.source_map().span_extend_while_whitespace(use_span); - (use_span, String::new()) - } else { - (use_span, "'_".to_owned()) - }; - debug!(?deletion_span, ?use_span); - - // issue 107998 for the case such as a wrong function pointer type - // `deletion_span` is empty and there is no need to report lifetime uses here - let deletion_span = - if deletion_span.is_empty() { None } else { Some(deletion_span) }; - Some(lints::SingleUseLifetimeSugg { deletion_span, use_span, replace_lt }) - } else { - None - }; - - lints::SingleUseLifetime { suggestion, param_span, use_span, ident } - .into_diag(dcx, level) - } BuiltinLintDiag::NamedArgumentUsedPositionally { position_sp_to_replace, position_sp_for_msg, diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index e4106cbdfb797..c76fafcde2ee1 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -129,7 +129,7 @@ use unused::*; #[rustfmt::skip] pub use builtin::{MissingDoc, SoftLints}; pub use context::{EarlyContext, LateContext, LintContext, LintStore}; -pub use early::diagnostics::{DecorateAttrLint, DecorateBuiltinLint}; +pub use early::diagnostics::{DecorateAttrLint, DecorateBuiltinLint, DiagAndSess}; pub use early::{EarlyCheckNode, check_ast_node}; pub use late::{check_crate, late_lint_mod, unerased_lint_store}; pub use levels::LintLevelsBuilder; diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index b77225db4f0eb..5819f2bc151f9 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -3011,25 +3011,6 @@ pub(crate) struct IllFormedAttributeInput { pub docs: &'static str, } -#[derive(Diagnostic)] -#[diag( - "absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition" -)] -pub(crate) struct AbsPathWithModule { - #[subdiagnostic] - pub sugg: AbsPathWithModuleSugg, -} - -#[derive(Subdiagnostic)] -#[suggestion("use `crate`", code = "{replacement}")] -pub(crate) struct AbsPathWithModuleSugg { - #[primary_span] - pub span: Span, - #[applicability] - pub applicability: Applicability, - pub replacement: String, -} - #[derive(Diagnostic)] #[diag("hidden lifetime parameters in types are deprecated")] pub(crate) struct ElidedLifetimesInPaths { @@ -3081,30 +3062,6 @@ pub(crate) enum UnusedImportsSugg { }, } -#[derive(Diagnostic)] -#[diag("lifetime parameter `{$ident}` only used once")] -pub(crate) struct SingleUseLifetime { - #[label("this lifetime...")] - pub param_span: Span, - #[label("...is used only here")] - pub use_span: Span, - #[subdiagnostic] - pub suggestion: Option, - - pub ident: Ident, -} - -#[derive(Subdiagnostic)] -#[multipart_suggestion("elide the single-use lifetime", applicability = "machine-applicable")] -pub(crate) struct SingleUseLifetimeSugg { - #[suggestion_part(code = "")] - pub deletion_span: Option, - #[suggestion_part(code = "{replace_lt}")] - pub use_span: Span, - - pub replace_lt: String, -} - #[derive(Diagnostic)] #[diag("named argument `{$named_arg_name}` is not used by name")] pub(crate) struct NamedArgumentUsedPositionally { diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 71b507f67e8f2..7e51029b02bb6 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -656,7 +656,6 @@ pub enum DeprecatedSinceKind { // becomes hacky (and it gets allocated). #[derive(Debug)] pub enum BuiltinLintDiag { - AbsPathWithModule(Span), ElidedLifetimesInPaths(usize, Span, bool, Span), UnusedImports { remove_whole_use: bool, @@ -665,18 +664,6 @@ pub enum BuiltinLintDiag { test_module_span: Option, span_snippets: Vec, }, - SingleUseLifetime { - /// Span of the parameter which declares this lifetime. - param_span: Span, - /// Span of the code that should be removed when eliding this lifetime. - /// This span should include leading or trailing comma. - deletion_span: Option, - /// Span of the single use, or None if the lifetime is never used. - /// If true, the lifetime will be fully elided. - use_span: Span, - elidable: bool, - ident: Ident, - }, NamedArgumentUsedPositionally { /// Span where the named argument is used by position and will be replaced with the named /// argument name diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 63ff0b2a0a0df..f0cda4493c851 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -70,6 +70,10 @@ using namespace llvm::object; // This opcode is an LLVM detail that could hypothetically change (?), so // verify that the hard-coded value in `dwarf_const.rs` still agrees with LLVM. static_assert(dwarf::DW_OP_LLVM_fragment == 0x1000); +static_assert(dwarf::DW_OP_constu == 0x10); +static_assert(dwarf::DW_OP_minus == 0x1c); +static_assert(dwarf::DW_OP_mul == 0x1e); +static_assert(dwarf::DW_OP_bregx == 0x92); static_assert(dwarf::DW_OP_stack_value == 0x9f); static LLVM_THREAD_LOCAL char *LastError; @@ -731,7 +735,7 @@ extern "C" bool LLVMRustInlineAsmVerify(LLVMTypeRef Ty, char *Constraints, } template DIT *unwrapDIPtr(LLVMMetadataRef Ref) { - return (DIT *)(Ref ? unwrap(Ref) : nullptr); + return (DIT *)(Ref ? unwrap(Ref) : nullptr); } #define DIDescriptor DIScope @@ -1207,6 +1211,36 @@ extern "C" void LLVMRustDICompositeTypeReplaceArrays( DINodeArray(unwrap(Params))); } +// LLVM's C FFI bindings don't expose the overload of `GetOrCreateSubrange` +// which takes a metadata node as the upper bound. +extern "C" LLVMMetadataRef +LLVMRustDIGetOrCreateSubrange(LLVMDIBuilderRef Builder, + LLVMMetadataRef CountNode, LLVMMetadataRef LB, + LLVMMetadataRef UB, LLVMMetadataRef Stride) { + return wrap(unwrap(Builder)->getOrCreateSubrange( + unwrapDI(CountNode), unwrapDI(LB), + unwrapDI(UB), unwrapDI(Stride))); +} + +// LLVM's CI FFI bindings don't expose the `BitStride` parameter of +// `createVectorType`. +extern "C" LLVMMetadataRef +LLVMRustDICreateVectorType(LLVMDIBuilderRef Builder, uint64_t Size, + uint32_t AlignInBits, LLVMMetadataRef Type, + LLVMMetadataRef Subscripts, + LLVMMetadataRef BitStride) { +#if LLVM_VERSION_GE(22, 0) + return wrap(unwrap(Builder)->createVectorType( + Size, AlignInBits, unwrapDI(Type), + DINodeArray(unwrapDI(Subscripts)), + unwrapDI(BitStride))); +#else + return wrap(unwrap(Builder)->createVectorType( + Size, AlignInBits, unwrapDI(Type), + DINodeArray(unwrapDI(Subscripts)))); +#endif +} + extern "C" LLVMMetadataRef LLVMRustDILocationCloneWithBaseDiscriminator(LLVMMetadataRef Location, unsigned BD) { diff --git a/compiler/rustc_middle/src/ich/impls_syntax.rs b/compiler/rustc_middle/src/ich/impls_syntax.rs index 1063b37be87e8..d932bfdee6ef6 100644 --- a/compiler/rustc_middle/src/ich/impls_syntax.rs +++ b/compiler/rustc_middle/src/ich/impls_syntax.rs @@ -4,7 +4,7 @@ use rustc_ast as ast; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir as hir; -use rustc_span::{SourceFile, Symbol, sym}; +use rustc_span::{Symbol, sym}; use smallvec::SmallVec; use super::StableHashingContext; @@ -54,56 +54,6 @@ fn is_ignored_attr(name: Symbol) -> bool { IGNORED_ATTRIBUTES.contains(&name) } -impl<'a> HashStable> for SourceFile { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let SourceFile { - name: _, // We hash the smaller stable_id instead of this - stable_id, - cnum, - // Do not hash the source as it is not encoded - src: _, - ref src_hash, - // Already includes src_hash, this is redundant - checksum_hash: _, - external_src: _, - start_pos: _, - normalized_source_len: _, - unnormalized_source_len: _, - lines: _, - ref multibyte_chars, - ref normalized_pos, - } = *self; - - stable_id.hash_stable(hcx, hasher); - - src_hash.hash_stable(hcx, hasher); - - { - // We are always in `Lines` form by the time we reach here. - assert!(self.lines.read().is_lines()); - let lines = self.lines(); - // We only hash the relative position within this source_file - lines.len().hash_stable(hcx, hasher); - for &line in lines.iter() { - line.hash_stable(hcx, hasher); - } - } - - // We only hash the relative position within this source_file - multibyte_chars.len().hash_stable(hcx, hasher); - for &char_pos in multibyte_chars.iter() { - char_pos.hash_stable(hcx, hasher); - } - - normalized_pos.len().hash_stable(hcx, hasher); - for &char_pos in normalized_pos.iter() { - char_pos.hash_stable(hcx, hasher); - } - - cnum.hash_stable(hcx, hasher); - } -} - impl<'tcx> HashStable> for rustc_feature::Features { fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) { // Unfortunately we cannot exhaustively list fields here, since the diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 0d047b348d9e1..621ceeffac658 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -7,7 +7,7 @@ use std::debug_assert_matches; use std::ops::{ControlFlow, Range}; use hir::def::{CtorKind, DefKind}; -use rustc_abi::{FIRST_VARIANT, FieldIdx, ScalableElt, VariantIdx}; +use rustc_abi::{FIRST_VARIANT, FieldIdx, NumScalableVectors, ScalableElt, VariantIdx}; use rustc_errors::{ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; use rustc_hir::LangItem; @@ -1261,17 +1261,27 @@ impl<'tcx> Ty<'tcx> { } } - pub fn scalable_vector_element_count_and_type(self, tcx: TyCtxt<'tcx>) -> (u16, Ty<'tcx>) { + pub fn scalable_vector_parts( + self, + tcx: TyCtxt<'tcx>, + ) -> Option<(u16, Ty<'tcx>, NumScalableVectors)> { let Adt(def, args) = self.kind() else { - bug!("`scalable_vector_size_and_type` called on invalid type") + return None; }; - let Some(ScalableElt::ElementCount(element_count)) = def.repr().scalable else { - bug!("`scalable_vector_size_and_type` called on non-scalable vector type"); + let (num_vectors, vec_def) = match def.repr().scalable? { + ScalableElt::ElementCount(_) => (NumScalableVectors::for_non_tuple(), *def), + ScalableElt::Container => ( + NumScalableVectors::from_field_count(def.non_enum_variant().fields.len())?, + def.non_enum_variant().fields[FieldIdx::ZERO].ty(tcx, args).ty_adt_def()?, + ), }; - let variant = def.non_enum_variant(); + let Some(ScalableElt::ElementCount(element_count)) = vec_def.repr().scalable else { + return None; + }; + let variant = vec_def.non_enum_variant(); assert_eq!(variant.fields.len(), 1); let field_ty = variant.fields[FieldIdx::ZERO].ty(tcx, args); - (element_count, field_ty) + Some((element_count, field_ty, num_vectors)) } pub fn simd_size_and_type(self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) { diff --git a/compiler/rustc_public/src/abi.rs b/compiler/rustc_public/src/abi.rs index 1403e57a7e6a9..4a780d652df81 100644 --- a/compiler/rustc_public/src/abi.rs +++ b/compiler/rustc_public/src/abi.rs @@ -232,6 +232,10 @@ pub enum TagEncoding { }, } +/// How many scalable vectors are in a `ValueAbi::ScalableVector`? +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] +pub struct NumScalableVectors(pub(crate) u8); + /// Describes how values of the type are passed by target ABIs, /// in terms of categories of C types there are ABI rules for. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] @@ -245,6 +249,7 @@ pub enum ValueAbi { ScalableVector { element: Scalar, count: u64, + number_of_vectors: NumScalableVectors, }, Aggregate { /// If true, the size is exact, otherwise it's only a lower bound. diff --git a/compiler/rustc_public/src/unstable/convert/stable/abi.rs b/compiler/rustc_public/src/unstable/convert/stable/abi.rs index b3edc6194c307..d8c4cee7abbe4 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/abi.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/abi.rs @@ -10,8 +10,9 @@ use rustc_target::callconv; use crate::abi::{ AddressSpace, ArgAbi, CallConvention, FieldsShape, FloatLength, FnAbi, IntegerLength, - IntegerType, Layout, LayoutShape, PassMode, Primitive, ReprFlags, ReprOptions, Scalar, - TagEncoding, TyAndLayout, ValueAbi, VariantFields, VariantsShape, WrappingRange, + IntegerType, Layout, LayoutShape, NumScalableVectors, PassMode, Primitive, ReprFlags, + ReprOptions, Scalar, TagEncoding, TyAndLayout, ValueAbi, VariantFields, VariantsShape, + WrappingRange, }; use crate::compiler_interface::BridgeTys; use crate::target::MachineSize as Size; @@ -249,6 +250,18 @@ impl<'tcx> Stable<'tcx> for rustc_abi::TagEncoding { } } +impl<'tcx> Stable<'tcx> for rustc_abi::NumScalableVectors { + type T = NumScalableVectors; + + fn stable<'cx>( + &self, + _tables: &mut Tables<'cx, BridgeTys>, + _cx: &CompilerCtxt<'cx, BridgeTys>, + ) -> Self::T { + NumScalableVectors(self.0) + } +} + impl<'tcx> Stable<'tcx> for rustc_abi::BackendRepr { type T = ValueAbi; @@ -265,8 +278,12 @@ impl<'tcx> Stable<'tcx> for rustc_abi::BackendRepr { rustc_abi::BackendRepr::SimdVector { element, count } => { ValueAbi::Vector { element: element.stable(tables, cx), count } } - rustc_abi::BackendRepr::SimdScalableVector { element, count } => { - ValueAbi::ScalableVector { element: element.stable(tables, cx), count } + rustc_abi::BackendRepr::SimdScalableVector { element, count, number_of_vectors } => { + ValueAbi::ScalableVector { + element: element.stable(tables, cx), + count, + number_of_vectors: number_of_vectors.stable(tables, cx), + } } rustc_abi::BackendRepr::Memory { sized } => ValueAbi::Aggregate { sized }, } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index cab37f5c0faa6..9e0f04e82b472 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -11,7 +11,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, MultiSpan, SuggestionStyle, + Applicability, Diag, DiagCtxtHandle, Diagnostic, ErrorGuaranteed, MultiSpan, SuggestionStyle, struct_span_code_err, }; use rustc_feature::BUILTIN_ATTRIBUTES; @@ -23,7 +23,6 @@ use rustc_hir::{PrimTy, Stability, StabilityLevel, find_attr}; use rustc_middle::bug; use rustc_middle::ty::TyCtxt; use rustc_session::Session; -use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::{ ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, AMBIGUOUS_GLOB_IMPORTS, AMBIGUOUS_IMPORT_VISIBILITIES, AMBIGUOUS_PANIC_IMPORTS, MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS, @@ -510,12 +509,35 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return; } - let diag = BuiltinLintDiag::AbsPathWithModule(root_span); - self.lint_buffer.buffer_lint( + self.lint_buffer.dyn_buffer_lint_any( ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, node_id, root_span, - diag, + move |dcx, level, sess| { + let (replacement, applicability) = match sess + .downcast_ref::() + .expect("expected a `Session`") + .source_map() + .span_to_snippet(root_span) + { + Ok(ref s) => { + // FIXME(Manishearth) ideally the emitting code + // can tell us whether or not this is global + let opt_colon = if s.trim_start().starts_with("::") { "" } else { "::" }; + + (format!("crate{opt_colon}{s}"), Applicability::MachineApplicable) + } + Err(_) => ("crate::".to_string(), Applicability::HasPlaceholders), + }; + errors::AbsPathWithModule { + sugg: errors::AbsPathWithModuleSugg { + span: root_span, + applicability, + replacement, + }, + } + .into_diag(dcx, level) + }, ); } diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 43b006d72e500..305231a3ea0d9 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -1697,3 +1697,46 @@ pub(crate) struct AssociatedConstElidedLifetime { #[note("cannot automatically infer `'static` because of other lifetimes in scope")] pub lifetimes_in_scope: MultiSpan, } + +#[derive(Diagnostic)] +#[diag("lifetime parameter `{$ident}` only used once")] +pub(crate) struct SingleUseLifetime { + #[label("this lifetime...")] + pub param_span: Span, + #[label("...is used only here")] + pub use_span: Span, + #[subdiagnostic] + pub suggestion: Option, + + pub ident: Ident, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion("elide the single-use lifetime", applicability = "machine-applicable")] +pub(crate) struct SingleUseLifetimeSugg { + #[suggestion_part(code = "")] + pub deletion_span: Option, + #[suggestion_part(code = "{replace_lt}")] + pub use_span: Span, + + pub replace_lt: String, +} + +#[derive(Diagnostic)] +#[diag( + "absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition" +)] +pub(crate) struct AbsPathWithModule { + #[subdiagnostic] + pub sugg: AbsPathWithModuleSugg, +} + +#[derive(Subdiagnostic)] +#[suggestion("use `crate`", code = "{replacement}")] +pub(crate) struct AbsPathWithModuleSugg { + #[primary_span] + pub span: Span, + #[applicability] + pub applicability: Applicability, + pub replacement: String, +} diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 7539e3c4f499f..528d55c603ed8 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -14,7 +14,7 @@ use rustc_ast_pretty::pprust::{path_to_string, where_bound_predicate_to_string}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, ErrorGuaranteed, MultiSpan, SuggestionStyle, pluralize, + Applicability, Diag, Diagnostic, ErrorGuaranteed, MultiSpan, SuggestionStyle, pluralize, struct_span_code_err, }; use rustc_hir as hir; @@ -1773,7 +1773,8 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { // const generics. Of course, `Struct` and `Enum` may contain ty params, too, but the // benefits of including them here outweighs the small number of false positives. Some(Res::Def(DefKind::Struct | DefKind::Enum, _)) - if self.r.tcx.features().adt_const_params() => + if self.r.tcx.features().adt_const_params() + || self.r.tcx.features().min_adt_const_params() => { Applicability::MaybeIncorrect } @@ -3641,22 +3642,52 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { match use_set { Some(LifetimeUseSet::Many) => {} Some(LifetimeUseSet::One { use_span, use_ctxt }) => { - debug!(?param.ident, ?param.ident.span, ?use_span); - - let elidable = matches!(use_ctxt, LifetimeCtxt::Ref); + let param_ident = param.ident; let deletion_span = if param.bounds.is_empty() { deletion_span() } else { None }; - - self.r.lint_buffer.buffer_lint( + self.r.lint_buffer.dyn_buffer_lint_any( lint::builtin::SINGLE_USE_LIFETIMES, param.id, - param.ident.span, - lint::BuiltinLintDiag::SingleUseLifetime { - param_span: param.ident.span, - use_span, - elidable, - deletion_span, - ident: param.ident, + param_ident.span, + move |dcx, level, sess| { + debug!(?param_ident, ?param_ident.span, ?use_span); + + let elidable = matches!(use_ctxt, LifetimeCtxt::Ref); + let suggestion = if let Some(deletion_span) = deletion_span { + let (use_span, replace_lt) = if elidable { + let use_span = sess + .downcast_ref::() + .expect("expected a `Session`") + .source_map() + .span_extend_while_whitespace(use_span); + (use_span, String::new()) + } else { + (use_span, "'_".to_owned()) + }; + debug!(?deletion_span, ?use_span); + + // issue 107998 for the case such as a wrong function pointer type + // `deletion_span` is empty and there is no need to report lifetime uses here + let deletion_span = if deletion_span.is_empty() { + None + } else { + Some(deletion_span) + }; + Some(errors::SingleUseLifetimeSugg { + deletion_span, + use_span, + replace_lt, + }) + } else { + None + }; + errors::SingleUseLifetime { + suggestion, + param_span: param_ident.span, + use_span, + ident: param_ident, + } + .into_diag(dcx, level) }, ); } @@ -4064,6 +4095,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { }; let mut spans_suggs: Vec<_> = Vec::new(); + let source_map = self.r.tcx.sess.source_map(); let build_sugg = |lt: MissingLifetime| match lt.kind { MissingLifetimeKind::Underscore => { debug_assert_eq!(lt.count, 1); @@ -4074,9 +4106,12 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { (lt.span.shrink_to_hi(), format!("{existing_name} ")) } MissingLifetimeKind::Comma => { - let sugg: String = std::iter::repeat_n([existing_name.as_str(), ", "], lt.count) - .flatten() + let sugg: String = std::iter::repeat_n(existing_name.as_str(), lt.count) + .intersperse(", ") .collect(); + let is_empty_brackets = + source_map.span_look_ahead(lt.span, ">", Some(50)).is_some(); + let sugg = if is_empty_brackets { sugg } else { format!("{sugg}, ") }; (lt.span.shrink_to_hi(), sugg) } MissingLifetimeKind::Brackets => { diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 65a15dba42873..8251050b6aead 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -344,7 +344,7 @@ impl ParseSess { lint, Some(span.into()), node_id, - DecorateDiagCompat::Dynamic(Box::new(callback)), + DecorateDiagCompat::Dynamic(Box::new(|dcx, level, _| callback(dcx, level))), ) } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 53e2527057bc2..71d67f9608bfa 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -399,7 +399,6 @@ symbols! { anon_assoc, anonymous_lifetime_in_impl_trait, any, - append_const_msg, apx_target_feature, arbitrary_enum_discriminant, arbitrary_self_types, @@ -1245,6 +1244,7 @@ symbols! { meta_sized, metadata_type, mgca_type_const_syntax, + min_adt_const_params, min_const_fn, min_const_generics, min_const_unsafe_fn, @@ -1979,6 +1979,12 @@ symbols! { suggestion, super_let, supertrait_item_shadowing, + sve_cast, + sve_tuple_create2, + sve_tuple_create3, + sve_tuple_create4, + sve_tuple_get, + sve_tuple_set, sym, sync, synthetic, diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index d9ea2e0057895..f7486a23bf731 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -1528,6 +1528,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { label_or_note(span, terr.to_string(self.tcx)); } + if let Some(param_env) = param_env { + self.note_field_shadowed_by_private_candidate_in_cause(diag, cause, param_env); + } + if self.check_and_note_conflicting_crates(diag, terr) { return; } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index d0358b03af197..79007f64a632e 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -14,7 +14,7 @@ use rustc_errors::{ Applicability, Diag, ErrorGuaranteed, Level, MultiSpan, StashKey, StringPart, Suggestions, msg, pluralize, struct_span_code_err, }; -use rustc_hir::attrs::diagnostic::{AppendConstMessage, OnUnimplementedNote}; +use rustc_hir::attrs::diagnostic::OnUnimplementedNote; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_hir::{self as hir, LangItem, Node, find_attr}; @@ -193,10 +193,16 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { label, notes, parent_label, - append_const_msg, } = self.on_unimplemented_note(main_trait_predicate, main_obligation, &mut long_ty_file); let have_alt_message = message.is_some() || label.is_some(); + + let message = message.unwrap_or_else(|| self.get_standard_error_message( + main_trait_predicate, + None, + post_message, + &mut long_ty_file, + )); let is_try_conversion = self.is_try_conversion(span, main_trait_predicate.def_id()); let is_question_mark = matches!( root_obligation.cause.code().peel_derives(), @@ -210,16 +216,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let question_mark_message = "the question mark operation (`?`) implicitly \ performs a conversion on the error value \ using the `From` trait"; - let (message, notes, append_const_msg) = if is_try_conversion { + let (message, notes) = if is_try_conversion { let ty = self.tcx.short_string( main_trait_predicate.skip_binder().self_ty(), &mut long_ty_file, ); // We have a `-> Result<_, E1>` and `gives_E2()?`. ( - Some(format!("`?` couldn't convert the error to `{ty}`")), + format!("`?` couldn't convert the error to `{ty}`"), vec![question_mark_message.to_owned()], - Some(AppendConstMessage::Default), ) } else if is_question_mark { let main_trait_predicate = @@ -228,26 +233,16 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // trait object: `-> Result<_, Box` and `gives_E()?` when // `E: Error` isn't met. ( - Some(format!( + format!( "`?` couldn't convert the error: `{main_trait_predicate}` is \ not satisfied", - )), + ), vec![question_mark_message.to_owned()], - Some(AppendConstMessage::Default), ) } else { - (message, notes, append_const_msg) + (message, notes) }; - let default_err_msg = || self.get_standard_error_message( - main_trait_predicate, - message, - None, - append_const_msg, - post_message, - &mut long_ty_file, - ); - let (err_msg, safe_transmute_explanation) = if self.tcx.is_lang_item( main_trait_predicate.def_id(), LangItem::TransmuteTrait, @@ -271,7 +266,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); } GetSafeTransmuteErrorAndReason::Default => { - (default_err_msg(), None) + (message, None) } GetSafeTransmuteErrorAndReason::Error { err_msg, @@ -279,7 +274,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } => (err_msg, safe_transmute_explanation), } } else { - (default_err_msg(), None) + (message, None) }; let mut err = struct_span_code_err!(self.dcx(), span, E0277, "{}", err_msg); @@ -393,7 +388,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if let Some(s) = label { // If it has a custom `#[rustc_on_unimplemented]` // error message, let's display it as the label! - err.span_label(span, s.as_str().to_owned()); + err.span_label(span, s); if !matches!(leaf_trait_predicate.skip_binder().self_ty().kind(), ty::Param(_)) // When the self type is a type param We don't need to "the trait // `std::marker::Sized` is not implemented for `T`" as we will point @@ -559,6 +554,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); } + self.note_field_shadowed_by_private_candidate_in_cause( + &mut err, + &obligation.cause, + obligation.param_env, + ); self.try_to_add_help_message( &root_obligation, &obligation, @@ -857,9 +857,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let err_msg = self.get_standard_error_message( trait_ref, - None, Some(predicate.constness()), - None, String::new(), &mut file, ); @@ -919,7 +917,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { label, notes, parent_label, - append_const_msg: _, } = note; if let Some(message) = message { @@ -2836,40 +2833,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { fn get_standard_error_message( &self, trait_predicate: ty::PolyTraitPredicate<'tcx>, - message: Option, predicate_constness: Option, - append_const_msg: Option, post_message: String, long_ty_path: &mut Option, ) -> String { - message - .and_then(|cannot_do_this| { - match (predicate_constness, append_const_msg) { - // do nothing if predicate is not const - (None, _) => Some(cannot_do_this), - // suggested using default post message - ( - Some(ty::BoundConstness::Const | ty::BoundConstness::Maybe), - Some(AppendConstMessage::Default), - ) => Some(format!("{cannot_do_this} in const contexts")), - // overridden post message - ( - Some(ty::BoundConstness::Const | ty::BoundConstness::Maybe), - Some(AppendConstMessage::Custom(custom_msg, _)), - ) => Some(format!("{cannot_do_this}{custom_msg}")), - // fallback to generic message - (Some(ty::BoundConstness::Const | ty::BoundConstness::Maybe), None) => None, - } - }) - .unwrap_or_else(|| { - format!( - "the trait bound `{}` is not satisfied{post_message}", - self.tcx.short_string( - trait_predicate.print_with_bound_constness(predicate_constness), - long_ty_path, - ), - ) - }) + format!( + "the trait bound `{}` is not satisfied{post_message}", + self.tcx.short_string( + trait_predicate.print_with_bound_constness(predicate_constness), + long_ty_path, + ), + ) } fn select_transmute_obligation_for_reporting( diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 2d9574ea8c546..4912d5f4582e7 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -22,8 +22,10 @@ use rustc_hir::{ expr_needs_parens, }; use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk}; +use rustc_infer::traits::ImplSource; use rustc_middle::middle::privacy::Level; use rustc_middle::traits::IsConstable; +use rustc_middle::ty::adjustment::{Adjust, DerefAdjustKind}; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::print::{ PrintPolyTraitPredicateExt as _, PrintPolyTraitRefExt, PrintTraitPredicateExt as _, @@ -49,7 +51,7 @@ use crate::error_reporting::TypeErrCtxt; use crate::errors; use crate::infer::InferCtxtExt as _; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; -use crate::traits::{ImplDerivedCause, NormalizeExt, ObligationCtxt}; +use crate::traits::{ImplDerivedCause, NormalizeExt, ObligationCtxt, SelectionContext}; #[derive(Debug)] pub enum CoroutineInteriorOrUpvar { @@ -242,6 +244,213 @@ pub fn suggest_restriction<'tcx, G: EmissionGuarantee>( } impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { + pub fn note_field_shadowed_by_private_candidate_in_cause( + &self, + err: &mut Diag<'_>, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) { + let mut hir_ids = FxHashSet::default(); + // Walk the parent chain so we can recover + // the source expression from whichever layer carries them. + let mut next_code = Some(cause.code()); + while let Some(cause_code) = next_code { + match cause_code { + ObligationCauseCode::BinOp { lhs_hir_id, rhs_hir_id, .. } => { + hir_ids.insert(*lhs_hir_id); + hir_ids.insert(*rhs_hir_id); + } + ObligationCauseCode::FunctionArg { arg_hir_id, .. } + | ObligationCauseCode::ReturnValue(arg_hir_id) + | ObligationCauseCode::AwaitableExpr(arg_hir_id) + | ObligationCauseCode::BlockTailExpression(arg_hir_id, _) + | ObligationCauseCode::UnOp { hir_id: arg_hir_id } => { + hir_ids.insert(*arg_hir_id); + } + ObligationCauseCode::OpaqueReturnType(Some((_, hir_id))) => { + hir_ids.insert(*hir_id); + } + _ => {} + } + next_code = cause_code.parent(); + } + + if !cause.span.is_dummy() + && let Some(body) = self.tcx.hir_maybe_body_owned_by(cause.body_id) + { + let mut expr_finder = FindExprBySpan::new(cause.span, self.tcx); + expr_finder.visit_body(body); + if let Some(expr) = expr_finder.result { + hir_ids.insert(expr.hir_id); + } + } + + // we will sort immediately by source order before emitting any diagnostics + #[allow(rustc::potential_query_instability)] + let mut hir_ids: Vec<_> = hir_ids.into_iter().collect(); + let source_map = self.tcx.sess.source_map(); + hir_ids.sort_by_cached_key(|hir_id| { + let span = self.tcx.hir_span(*hir_id); + let lo = source_map.lookup_byte_offset(span.lo()); + let hi = source_map.lookup_byte_offset(span.hi()); + (lo.sf.name.prefer_remapped_unconditionally().to_string(), lo.pos.0, hi.pos.0) + }); + + for hir_id in hir_ids { + self.note_field_shadowed_by_private_candidate(err, hir_id, param_env); + } + } + + pub fn note_field_shadowed_by_private_candidate( + &self, + err: &mut Diag<'_>, + hir_id: hir::HirId, + param_env: ty::ParamEnv<'tcx>, + ) { + let Some(typeck_results) = &self.typeck_results else { + return; + }; + let Node::Expr(expr) = self.tcx.hir_node(hir_id) else { + return; + }; + let hir::ExprKind::Field(base_expr, field_ident) = expr.kind else { + return; + }; + + let Some(base_ty) = typeck_results.expr_ty_opt(base_expr) else { + return; + }; + let base_ty = self.resolve_vars_if_possible(base_ty); + if base_ty.references_error() { + return; + } + + let fn_body_hir_id = self.tcx.local_def_id_to_hir_id(typeck_results.hir_owner.def_id); + let mut private_candidate: Option<(Ty<'tcx>, Ty<'tcx>, Span)> = None; + + for (deref_base_ty, _) in (self.autoderef_steps)(base_ty) { + let ty::Adt(base_def, args) = deref_base_ty.kind() else { + continue; + }; + + if base_def.is_enum() { + continue; + } + + let (adjusted_ident, def_scope) = + self.tcx.adjust_ident_and_get_scope(field_ident, base_def.did(), fn_body_hir_id); + + let Some((_, field_def)) = + base_def.non_enum_variant().fields.iter_enumerated().find(|(_, field)| { + field.ident(self.tcx).normalize_to_macros_2_0() == adjusted_ident + }) + else { + continue; + }; + let field_span = self + .tcx + .def_ident_span(field_def.did) + .unwrap_or_else(|| self.tcx.def_span(field_def.did)); + + if field_def.vis.is_accessible_from(def_scope, self.tcx) { + let accessible_field_ty = field_def.ty(self.tcx, args); + if let Some((private_base_ty, private_field_ty, private_field_span)) = + private_candidate + && !self.can_eq(param_env, private_field_ty, accessible_field_ty) + { + let private_struct_span = match private_base_ty.kind() { + ty::Adt(private_base_def, _) => self + .tcx + .def_ident_span(private_base_def.did()) + .unwrap_or_else(|| self.tcx.def_span(private_base_def.did())), + _ => DUMMY_SP, + }; + let accessible_struct_span = self + .tcx + .def_ident_span(base_def.did()) + .unwrap_or_else(|| self.tcx.def_span(base_def.did())); + let deref_impl_span = (typeck_results + .expr_adjustments(base_expr) + .iter() + .filter(|adj| { + matches!(adj.kind, Adjust::Deref(DerefAdjustKind::Overloaded(_))) + }) + .count() + == 1) + .then(|| { + self.probe(|_| { + let deref_trait_did = + self.tcx.require_lang_item(LangItem::Deref, DUMMY_SP); + let trait_ref = + ty::TraitRef::new(self.tcx, deref_trait_did, [private_base_ty]); + let obligation: Obligation<'tcx, ty::Predicate<'tcx>> = + Obligation::new( + self.tcx, + ObligationCause::dummy(), + param_env, + trait_ref, + ); + let Ok(Some(ImplSource::UserDefined(impl_data))) = + SelectionContext::new(self) + .select(&obligation.with(self.tcx, trait_ref)) + else { + return None; + }; + Some(self.tcx.def_span(impl_data.impl_def_id)) + }) + }) + .flatten(); + + let mut note_spans: MultiSpan = private_struct_span.into(); + if private_struct_span != DUMMY_SP { + note_spans.push_span_label(private_struct_span, "in this struct"); + } + if private_field_span != DUMMY_SP { + note_spans.push_span_label( + private_field_span, + "if this field wasn't private, it would be accessible", + ); + } + if accessible_struct_span != DUMMY_SP { + note_spans.push_span_label( + accessible_struct_span, + "this struct is accessible through auto-deref", + ); + } + if field_span != DUMMY_SP { + note_spans + .push_span_label(field_span, "this is the field that was accessed"); + } + if let Some(deref_impl_span) = deref_impl_span + && deref_impl_span != DUMMY_SP + { + note_spans.push_span_label( + deref_impl_span, + "the field was accessed through this `Deref`", + ); + } + + err.span_note( + note_spans, + format!( + "there is a field `{field_ident}` on `{private_base_ty}` with type `{private_field_ty}` but it is private; `{field_ident}` from `{deref_base_ty}` was accessed through auto-deref instead" + ), + ); + } + + // we finally get to the accessible field, + // so we can return early without checking the rest of the autoderef candidates + return; + } + + private_candidate.get_or_insert(( + deref_base_ty, + field_def.ty(self.tcx, args), + field_span, + )); + } + } + pub fn suggest_restricting_param_bound( &self, err: &mut Diag<'_>, diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 391f50edf23fa..136df923ee47a 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -4,8 +4,8 @@ use rustc_abi::Integer::{I8, I32}; use rustc_abi::Primitive::{self, Float, Int, Pointer}; use rustc_abi::{ AddressSpace, BackendRepr, FIRST_VARIANT, FieldIdx, FieldsShape, HasDataLayout, Layout, - LayoutCalculatorError, LayoutData, Niche, ReprOptions, ScalableElt, Scalar, Size, StructKind, - TagEncoding, VariantIdx, Variants, WrappingRange, + LayoutCalculatorError, LayoutData, Niche, ReprOptions, Scalar, Size, StructKind, TagEncoding, + VariantIdx, Variants, WrappingRange, }; use rustc_hashes::Hash64; use rustc_hir as hir; @@ -572,30 +572,26 @@ fn layout_of_uncached<'tcx>( // ```rust (ignore, example) // #[rustc_scalable_vector(3)] // struct svuint32_t(u32); + // + // #[rustc_scalable_vector] + // struct svuint32x2_t(svuint32_t, svuint32_t); // ``` - ty::Adt(def, args) - if matches!(def.repr().scalable, Some(ScalableElt::ElementCount(..))) => - { - let Some(element_ty) = def - .is_struct() - .then(|| &def.variant(FIRST_VARIANT).fields) - .filter(|fields| fields.len() == 1) - .map(|fields| fields[FieldIdx::ZERO].ty(tcx, args)) + ty::Adt(def, _args) if def.repr().scalable() => { + let Some((element_count, element_ty, number_of_vectors)) = + ty.scalable_vector_parts(tcx) else { let guar = tcx .dcx() - .delayed_bug("#[rustc_scalable_vector] was applied to an invalid type"); - return Err(error(cx, LayoutError::ReferencesError(guar))); - }; - let Some(ScalableElt::ElementCount(element_count)) = def.repr().scalable else { - let guar = tcx - .dcx() - .delayed_bug("#[rustc_scalable_vector] was applied to an invalid type"); + .delayed_bug("`#[rustc_scalable_vector]` was applied to an invalid type"); return Err(error(cx, LayoutError::ReferencesError(guar))); }; let element_layout = cx.layout_of(element_ty)?; - map_layout(cx.calc.scalable_vector_type(element_layout, element_count as u64))? + map_layout(cx.calc.scalable_vector_type( + element_layout, + element_count as u64, + number_of_vectors, + ))? } // SIMD vector types. diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 49d7487c2803b..2051a806af642 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -241,10 +241,9 @@ use crate::ops::ControlFlow; #[stable(feature = "rust1", since = "1.0.0")] #[doc(alias = "==")] #[doc(alias = "!=")] -#[rustc_on_unimplemented( +#[diagnostic::on_unimplemented( message = "can't compare `{Self}` with `{Rhs}`", - label = "no implementation for `{Self} == {Rhs}`", - append_const_msg + label = "no implementation for `{Self} == {Rhs}`" )] #[rustc_diagnostic_item = "PartialEq"] #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] @@ -1356,10 +1355,9 @@ pub macro Ord($item:item) { #[doc(alias = "<")] #[doc(alias = "<=")] #[doc(alias = ">=")] -#[rustc_on_unimplemented( +#[diagnostic::on_unimplemented( message = "can't compare `{Self}` with `{Rhs}`", - label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`", - append_const_msg + label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`" )] #[rustc_diagnostic_item = "PartialOrd"] #[allow(multiple_supertrait_upcastable)] // FIXME(sized_hierarchy): remove this diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd/mod.rs similarity index 99% rename from library/core/src/intrinsics/simd.rs rename to library/core/src/intrinsics/simd/mod.rs index ae86690dc418d..084d8a3f1f247 100644 --- a/library/core/src/intrinsics/simd.rs +++ b/library/core/src/intrinsics/simd/mod.rs @@ -2,6 +2,8 @@ //! //! In this module, a "vector" is any `repr(simd)` type. +pub mod scalable; + use crate::marker::ConstParamTy; /// Inserts an element into a vector, returning the updated vector. diff --git a/library/core/src/intrinsics/simd/scalable.rs b/library/core/src/intrinsics/simd/scalable.rs new file mode 100644 index 0000000000000..f33831a30c070 --- /dev/null +++ b/library/core/src/intrinsics/simd/scalable.rs @@ -0,0 +1,93 @@ +//! Scalable vector compiler intrinsics. +//! +//! In this module, a "vector" is any `#[rustc_scalable_vector]`-annotated type. + +/// Numerically casts a vector, elementwise. +/// +/// `T` and `U` must be vectors of integers or floats, and must have the same length. +/// +/// When casting floats to integers, the result is truncated. Out-of-bounds result lead to UB. +/// When casting integers to floats, the result is rounded. +/// Otherwise, truncates or extends the value, maintaining the sign for signed integers. +/// +/// # Safety +/// Casting from integer types is always safe. +/// Casting between two float types is also always safe. +/// +/// Casting floats to integers truncates, following the same rules as `to_int_unchecked`. +/// Specifically, each element must: +/// * Not be `NaN` +/// * Not be infinite +/// * Be representable in the return type, after truncating off its fractional part +#[cfg(target_arch = "aarch64")] +#[rustc_intrinsic] +#[rustc_nounwind] +pub unsafe fn sve_cast(x: T) -> U; + +/// Create a tuple of two vectors. +/// +/// `SVecTup` must be a scalable vector tuple (`#[rustc_scalable_vector]`) and `SVec` must be a +/// scalable vector (`#[rustc_scalable_vector(N)]`). `SVecTup` must be a tuple of vectors of +/// type `SVec`. +/// +/// Corresponds to Clang's `__builtin_sve_svcreate2*` builtins. +#[cfg(target_arch = "aarch64")] +#[rustc_nounwind] +#[rustc_intrinsic] +pub unsafe fn sve_tuple_create2(x0: SVec, x1: SVec) -> SVecTup; + +/// Create a tuple of three vectors. +/// +/// `SVecTup` must be a scalable vector tuple (`#[rustc_scalable_vector]`) and `SVec` must be a +/// scalable vector (`#[rustc_scalable_vector(N)]`). `SVecTup` must be a tuple of vectors of +/// type `SVec`. +/// +/// Corresponds to Clang's `__builtin_sve_svcreate3*` builtins. +#[cfg(target_arch = "aarch64")] +#[rustc_intrinsic] +#[rustc_nounwind] +pub unsafe fn sve_tuple_create3(x0: SVec, x1: SVec, x2: SVec) -> SVecTup; + +/// Create a tuple of four vectors. +/// +/// `SVecTup` must be a scalable vector tuple (`#[rustc_scalable_vector]`) and `SVec` must be a +/// scalable vector (`#[rustc_scalable_vector(N)]`). `SVecTup` must be a tuple of vectors of +/// type `SVec`. +/// +/// Corresponds to Clang's `__builtin_sve_svcreate4*` builtins. +#[cfg(target_arch = "aarch64")] +#[rustc_intrinsic] +#[rustc_nounwind] +pub unsafe fn sve_tuple_create4(x0: SVec, x1: SVec, x2: SVec, x3: SVec) -> SVecTup; + +/// Get one vector from a tuple of vectors. +/// +/// `SVecTup` must be a scalable vector tuple (`#[rustc_scalable_vector]`) and `SVec` must be a +/// scalable vector (`#[rustc_scalable_vector(N)]`). `SVecTup` must be a tuple of vectors of +/// type `SVec`. +/// +/// Corresponds to Clang's `__builtin_sve_svget*` builtins. +/// +/// # Safety +/// +/// `IDX` must be in-bounds of the tuple. +#[cfg(target_arch = "aarch64")] +#[rustc_intrinsic] +#[rustc_nounwind] +pub unsafe fn sve_tuple_get(tuple: SVecTup) -> SVec; + +/// Change one vector in a tuple of vectors. +/// +/// `SVecTup` must be a scalable vector tuple (`#[rustc_scalable_vector]`) and `SVec` must be a +/// scalable vector (`#[rustc_scalable_vector(N)]`). `SVecTup` must be a tuple of vectors of +/// type `SVec`. +/// +/// Corresponds to Clang's `__builtin_sve_svset*` builtins. +/// +/// # Safety +/// +/// `IDX` must be in-bounds of the tuple. +#[cfg(target_arch = "aarch64")] +#[rustc_intrinsic] +#[rustc_nounwind] +pub unsafe fn sve_tuple_set(tuple: SVecTup, x: SVec) -> SVecTup; diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index 951bb5d0029f6..c57f41ffbf06d 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -15,13 +15,14 @@ macro_rules! unsafe_impl_trusted_step { )*}; } unsafe_impl_trusted_step![AsciiChar char i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize Ipv4Addr Ipv6Addr]; +unsafe_impl_trusted_step![NonZero NonZero NonZero NonZero NonZero NonZero]; /// Objects that have a notion of *successor* and *predecessor* operations. /// /// The *successor* operation moves towards values that compare greater. /// The *predecessor* operation moves towards values that compare lesser. #[rustc_diagnostic_item = "range_step"] -#[rustc_on_unimplemented( +#[diagnostic::on_unimplemented( message = "`std::ops::Range<{Self}>` is not an iterator", label = "`Range<{Self}>` is not an iterator", note = "`Range` only implements `Iterator` for select types in the standard library, \ @@ -255,10 +256,8 @@ macro_rules! step_identical_methods { macro_rules! step_integer_impls { { - narrower than or same width as usize: - $( [ $u_narrower:ident $i_narrower:ident ] ),+; - wider than usize: - $( [ $u_wider:ident $i_wider:ident ] ),+; + [ $( [ $u_narrower:ident $i_narrower:ident ] ),+ ] <= usize < + [ $( [ $u_wider:ident $i_wider:ident ] ),+ ] } => { $( #[allow(unreachable_patterns)] @@ -437,20 +436,138 @@ macro_rules! step_integer_impls { #[cfg(target_pointer_width = "64")] step_integer_impls! { - narrower than or same width as usize: [u8 i8], [u16 i16], [u32 i32], [u64 i64], [usize isize]; - wider than usize: [u128 i128]; + [ [u8 i8], [u16 i16], [u32 i32], [u64 i64], [usize isize] ] <= usize < [ [u128 i128] ] } #[cfg(target_pointer_width = "32")] step_integer_impls! { - narrower than or same width as usize: [u8 i8], [u16 i16], [u32 i32], [usize isize]; - wider than usize: [u64 i64], [u128 i128]; + [ [u8 i8], [u16 i16], [u32 i32], [usize isize] ] <= usize < [ [u64 i64], [u128 i128] ] } #[cfg(target_pointer_width = "16")] step_integer_impls! { - narrower than or same width as usize: [u8 i8], [u16 i16], [usize isize]; - wider than usize: [u32 i32], [u64 i64], [u128 i128]; + [ [u8 i8], [u16 i16], [usize isize] ] <= usize < [ [u32 i32], [u64 i64], [u128 i128] ] +} + +// These are still macro-generated because the integer literals resolve to different types. +macro_rules! step_nonzero_identical_methods { + ($int:ident) => { + #[inline] + unsafe fn forward_unchecked(start: Self, n: usize) -> Self { + // SAFETY: the caller has to guarantee that `start + n` doesn't overflow. + unsafe { Self::new_unchecked(start.get().unchecked_add(n as $int)) } + } + + #[inline] + unsafe fn backward_unchecked(start: Self, n: usize) -> Self { + // SAFETY: the caller has to guarantee that `start - n` doesn't overflow or hit zero. + unsafe { Self::new_unchecked(start.get().unchecked_sub(n as $int)) } + } + + #[inline] + #[allow(arithmetic_overflow)] + #[rustc_inherit_overflow_checks] + fn forward(start: Self, n: usize) -> Self { + // In debug builds, trigger a panic on overflow. + // This should optimize completely out in release builds. + if Self::forward_checked(start, n).is_none() { + let _ = $int::MAX + 1; + } + // Do saturating math (wrapping math causes UB if it wraps to Zero) + start.saturating_add(n as $int) + } + + #[inline] + #[allow(arithmetic_overflow)] + #[rustc_inherit_overflow_checks] + fn backward(start: Self, n: usize) -> Self { + // In debug builds, trigger a panic on overflow. + // This should optimize completely out in release builds. + if Self::backward_checked(start, n).is_none() { + let _ = $int::MIN - 1; + } + // Do saturating math (wrapping math causes UB if it wraps to Zero) + Self::new(start.get().saturating_sub(n as $int)).unwrap_or(Self::MIN) + } + + #[inline] + fn steps_between(start: &Self, end: &Self) -> (usize, Option) { + if *start <= *end { + #[allow(irrefutable_let_patterns, reason = "happens on usize or narrower")] + if let Ok(steps) = usize::try_from(end.get() - start.get()) { + (steps, Some(steps)) + } else { + (usize::MAX, None) + } + } else { + (0, None) + } + } + }; +} + +macro_rules! step_nonzero_impls { + { + [$( $narrower:ident ),+] <= usize < [$( $wider:ident ),+] + } => { + $( + #[allow(unreachable_patterns)] + #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] + impl Step for NonZero<$narrower> { + step_nonzero_identical_methods!($narrower); + + #[inline] + fn forward_checked(start: Self, n: usize) -> Option { + match $narrower::try_from(n) { + Ok(n) => start.checked_add(n), + Err(_) => None, // if n is out of range, `unsigned_start + n` is too + } + } + + #[inline] + fn backward_checked(start: Self, n: usize) -> Option { + match $narrower::try_from(n) { + // *_sub() is not implemented on NonZero + Ok(n) => start.get().checked_sub(n).and_then(Self::new), + Err(_) => None, // if n is out of range, `unsigned_start - n` is too + } + } + } + )+ + + $( + #[allow(unreachable_patterns)] + #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] + impl Step for NonZero<$wider> { + step_nonzero_identical_methods!($wider); + + #[inline] + fn forward_checked(start: Self, n: usize) -> Option { + start.checked_add(n as $wider) + } + + #[inline] + fn backward_checked(start: Self, n: usize) -> Option { + start.get().checked_sub(n as $wider).and_then(Self::new) + } + } + )+ + }; +} + +#[cfg(target_pointer_width = "64")] +step_nonzero_impls! { + [u8, u16, u32, u64, usize] <= usize < [u128] +} + +#[cfg(target_pointer_width = "32")] +step_nonzero_impls! { + [u8, u16, u32, usize] <= usize < [u64, u128] +} + +#[cfg(target_pointer_width = "16")] +step_nonzero_impls! { + [u8, u16, usize] <= usize < [u32, u64, u128] } #[unstable(feature = "step_trait", issue = "42168")] @@ -944,6 +1061,7 @@ impl Iterator for ops::Range { range_exact_iter_impl! { usize u8 u16 isize i8 i16 + NonZero NonZero NonZero // These are incorrect per the reasoning above, // but removing them would be a breaking change as they were stabilized in Rust 1.0.0. @@ -956,22 +1074,30 @@ range_exact_iter_impl! { unsafe_range_trusted_random_access_impl! { usize u8 u16 isize i8 i16 + NonZero NonZero NonZero } #[cfg(target_pointer_width = "32")] unsafe_range_trusted_random_access_impl! { u32 i32 + NonZero } #[cfg(target_pointer_width = "64")] unsafe_range_trusted_random_access_impl! { u32 i32 u64 i64 + NonZero + NonZero } range_incl_exact_iter_impl! { u8 i8 + NonZero + // Since RangeInclusive> can only be 1..=uN::MAX the length of this range is always + // <= uN::MAX, so they are always valid ExactSizeIterator unlike the ranges that include zero. + NonZero NonZero // These are incorrect per the reasoning above, // but removing them would be a breaking change as they were stabilized in Rust 1.26.0. diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index c79e8fc4060c1..e0f8e10484732 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -1054,7 +1054,7 @@ marker_impls! { #[unstable(feature = "const_destruct", issue = "133214")] #[rustc_const_unstable(feature = "const_destruct", issue = "133214")] #[lang = "destruct"] -#[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)] +#[diagnostic::on_unimplemented(message = "can't drop `{Self}`")] #[rustc_deny_explicit_impl] #[rustc_dyn_incompatible_trait] pub const trait Destruct: PointeeSized {} @@ -1088,7 +1088,7 @@ pub trait ConstParamTy_: StructuralPartialEq + Eq {} /// Derive macro generating an impl of the trait `ConstParamTy`. #[rustc_builtin_macro] #[allow_internal_unstable(const_param_ty_trait)] -#[unstable(feature = "adt_const_params", issue = "95174")] +#[unstable(feature = "min_adt_const_params", issue = "154042", implied_by = "adt_const_params")] pub macro ConstParamTy($item:item) { /* compiler built-in */ } diff --git a/library/core/src/ops/arith.rs b/library/core/src/ops/arith.rs index aec52424af3c4..afb814dbc6b33 100644 --- a/library/core/src/ops/arith.rs +++ b/library/core/src/ops/arith.rs @@ -70,8 +70,7 @@ on(all(Self = "{integer}", Rhs = "{float}"), message = "cannot add a float to an integer",), on(all(Self = "{float}", Rhs = "{integer}"), message = "cannot add an integer to a float",), message = "cannot add `{Rhs}` to `{Self}`", - label = "no implementation for `{Self} + {Rhs}`", - append_const_msg + label = "no implementation for `{Self} + {Rhs}`" )] #[doc(alias = "+")] pub const trait Add { @@ -181,10 +180,9 @@ add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 #[lang = "sub"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_ops", issue = "143802")] -#[rustc_on_unimplemented( +#[diagnostic::on_unimplemented( message = "cannot subtract `{Rhs}` from `{Self}`", - label = "no implementation for `{Self} - {Rhs}`", - append_const_msg + label = "no implementation for `{Self} - {Rhs}`" )] #[doc(alias = "-")] pub const trait Sub { diff --git a/library/coretests/tests/iter/range.rs b/library/coretests/tests/iter/range.rs index d5d2b8bf2b047..4a00e6f96bda8 100644 --- a/library/coretests/tests/iter/range.rs +++ b/library/coretests/tests/iter/range.rs @@ -502,3 +502,142 @@ fn test_double_ended_range() { panic!("unreachable"); } } + +macro_rules! nz { + (NonZero<$type:ident>($val:literal)) => { + ::core::num::NonZero::<$type>::new($val).unwrap() + }; + (NonZero<$type:ident>::MAX) => { + ::core::num::NonZero::<$type>::new($type::MAX).unwrap() + }; +} + +macro_rules! nonzero_array { + (NonZero<$type:ident>[$($val:literal),*]) => { + [$(nz!(NonZero<$type>($val))),*] + } +} + +macro_rules! nonzero_range { + (NonZero<$type:ident>($($left:literal)?..$($right:literal)?)) => { + nz!(NonZero<$type>($($left)?))..nz!(NonZero<$type>($($right)?)) + }; + (NonZero<$type:ident>($($left:literal)?..MAX)) => { + nz!(NonZero<$type>($($left)?))..nz!(NonZero<$type>::MAX) + }; + (NonZero<$type:ident>($($left:literal)?..=$right:literal)) => { + nz!(NonZero<$type>($($left)?))..=nz!(NonZero<$type>($right)) + }; + (NonZero<$type:ident>($($left:literal)?..=MAX)) => { + nz!(NonZero<$type>($($left)?))..=nz!(NonZero<$type>::MAX) + }; +} + +#[test] +fn test_nonzero_range() { + assert_eq!( + nonzero_range!(NonZero(1..=21)).step_by(5).collect::>(), + nonzero_array!(NonZero[1, 6, 11, 16, 21]) + ); + assert_eq!( + nonzero_range!(NonZero(1..=20)).step_by(5).collect::>(), + nonzero_array!(NonZero[1, 6, 11, 16]) + ); + assert_eq!( + nonzero_range!(NonZero(1..20)).step_by(5).collect::>(), + nonzero_array!(NonZero[1, 6, 11, 16]) + ); + assert_eq!( + nonzero_range!(NonZero(1..21)).rev().step_by(5).collect::>(), + nonzero_array!(NonZero[20, 15, 10, 5]) + ); + assert_eq!( + nonzero_range!(NonZero(1..21)).rev().step_by(6).collect::>(), + nonzero_array!(NonZero[20, 14, 8, 2]) + ); + assert_eq!( + nonzero_range!(NonZero(200..255)).step_by(50).collect::>(), + nonzero_array!(NonZero[200, 250]) + ); + assert_eq!( + nonzero_range!(NonZero(200..5)).step_by(1).collect::>(), + nonzero_array!(NonZero[]) + ); + assert_eq!( + nonzero_range!(NonZero(200..200)).step_by(1).collect::>(), + nonzero_array!(NonZero[]) + ); + + assert_eq!(nonzero_range!(NonZero(10..20)).step_by(1).size_hint(), (10, Some(10))); + assert_eq!(nonzero_range!(NonZero(10..20)).step_by(5).size_hint(), (2, Some(2))); + assert_eq!(nonzero_range!(NonZero(1..21)).rev().step_by(5).size_hint(), (4, Some(4))); + assert_eq!(nonzero_range!(NonZero(1..21)).rev().step_by(6).size_hint(), (4, Some(4))); + assert_eq!(nonzero_range!(NonZero(20..1)).step_by(1).size_hint(), (0, Some(0))); + assert_eq!(nonzero_range!(NonZero(20..20)).step_by(1).size_hint(), (0, Some(0))); + + // ExactSizeIterator + assert_eq!(nonzero_range!(NonZero(1..=MAX)).step_by(1).len(), usize::from(u8::MAX)); + assert_eq!(nonzero_range!(NonZero(1..=MAX)).step_by(1).len(), usize::from(u16::MAX)); + assert_eq!(nonzero_range!(NonZero(1..=MAX)).step_by(1).len(), usize::MAX); + + // Limits (next) + let mut range = nonzero_range!(NonZero(254..=MAX)); + assert_eq!(range.next(), Some(nz!(NonZero(254)))); + assert_eq!(range.next(), Some(nz!(NonZero(255)))); + assert_eq!(range.next(), None); + + let mut range = nonzero_range!(NonZero(65534..=MAX)); + assert_eq!(range.next(), Some(nz!(NonZero(65534)))); + assert_eq!(range.next(), Some(nz!(NonZero(65535)))); + assert_eq!(range.next(), None); + + // Limits (size_hint, exclusive range) + assert_eq!( + nonzero_range!(NonZero(1..MAX)).step_by(1).size_hint(), + (u8::MAX as usize - 1, Some(u8::MAX as usize - 1)) + ); + assert_eq!( + nonzero_range!(NonZero(1..MAX)).step_by(1).size_hint(), + (u16::MAX as usize - 1, Some(u16::MAX as usize - 1)) + ); + #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] + assert_eq!( + nonzero_range!(NonZero(1..MAX)).step_by(1).size_hint(), + (u32::MAX as usize - 1, Some(u32::MAX as usize - 1)) + ); + #[cfg(target_pointer_width = "64")] + assert_eq!( + nonzero_range!(NonZero(1..MAX)).step_by(1).size_hint(), + (u64::MAX as usize - 1, Some(u64::MAX as usize - 1)) + ); + assert_eq!(nonzero_range!(NonZero(1..MAX)).step_by(1).size_hint(), (usize::MAX, None)); + assert_eq!( + nonzero_range!(NonZero(1..MAX)).step_by(1).size_hint(), + (usize::MAX - 1, Some(usize::MAX - 1)) + ); + + // Limits (size_hint, inclusive range) + assert_eq!( + nonzero_range!(NonZero(1..=MAX)).step_by(1).size_hint(), + (u8::MAX as usize, Some(u8::MAX as usize)) + ); + assert_eq!( + nonzero_range!(NonZero(1..=MAX)).step_by(1).size_hint(), + (u16::MAX as usize, Some(u16::MAX as usize)) + ); + #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] + assert_eq!( + nonzero_range!(NonZero(1..=MAX)).step_by(1).size_hint(), + (u32::MAX as usize, Some(u32::MAX as usize)) + ); + #[cfg(target_pointer_width = "64")] + assert_eq!( + nonzero_range!(NonZero(1..=MAX)).step_by(1).size_hint(), + (u64::MAX as usize, Some(u64::MAX as usize)) + ); + assert_eq!(nonzero_range!(NonZero(1..=MAX)).step_by(1).size_hint(), (usize::MAX, None)); + assert_eq!( + nonzero_range!(NonZero(1..=MAX)).step_by(1).size_hint(), + (usize::MAX, Some(usize::MAX)) + ); +} diff --git a/tests/auxiliary/minicore.rs b/tests/auxiliary/minicore.rs index d84357edd0423..5c6eb54832437 100644 --- a/tests/auxiliary/minicore.rs +++ b/tests/auxiliary/minicore.rs @@ -63,7 +63,7 @@ pub trait MetaSized: PointeeSized {} pub trait Sized: MetaSized {} #[lang = "destruct"] -#[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)] +#[diagnostic::on_unimplemented(message = "can't drop `{Self}`")] pub trait Destruct: PointeeSized {} #[lang = "legacy_receiver"] diff --git a/tests/codegen-llvm/scalable-vectors/debuginfo-tuples-x2.rs b/tests/codegen-llvm/scalable-vectors/debuginfo-tuples-x2.rs new file mode 100644 index 0000000000000..1aa6562c471e4 --- /dev/null +++ b/tests/codegen-llvm/scalable-vectors/debuginfo-tuples-x2.rs @@ -0,0 +1,150 @@ +//@ only-aarch64 +//@ only-linux +//@ compile-flags: -Cdebuginfo=2 -Copt-level=0 + +#![crate_type = "lib"] +#![allow(incomplete_features, internal_features)] +#![feature(rustc_attrs)] + +// Test that we generate the correct debuginfo for scalable vector types. + +#[rustc_scalable_vector(16)] +#[allow(non_camel_case_types)] +struct svint8_t(i8); + +#[rustc_scalable_vector] +#[allow(non_camel_case_types)] +struct svint8x2_t(svint8_t, svint8_t); + +#[rustc_scalable_vector(16)] +#[allow(non_camel_case_types)] +struct svuint8_t(u8); + +#[rustc_scalable_vector] +#[allow(non_camel_case_types)] +struct svuint8x2_t(svuint8_t, svuint8_t); + +#[rustc_scalable_vector(8)] +#[allow(non_camel_case_types)] +struct svint16_t(i16); + +#[rustc_scalable_vector] +#[allow(non_camel_case_types)] +struct svint16x2_t(svint16_t, svint16_t); + +#[rustc_scalable_vector(8)] +#[allow(non_camel_case_types)] +struct svuint16_t(u16); + +#[rustc_scalable_vector] +#[allow(non_camel_case_types)] +struct svuint16x2_t(svuint16_t, svuint16_t); + +#[rustc_scalable_vector(4)] +#[allow(non_camel_case_types)] +struct svint32_t(i32); + +#[rustc_scalable_vector] +#[allow(non_camel_case_types)] +struct svint32x2_t(svint32_t, svint32_t); + +#[rustc_scalable_vector(4)] +#[allow(non_camel_case_types)] +struct svuint32_t(u32); + +#[rustc_scalable_vector] +#[allow(non_camel_case_types)] +struct svuint32x2_t(svuint32_t, svuint32_t); + +#[rustc_scalable_vector(2)] +#[allow(non_camel_case_types)] +struct svint64_t(i64); + +#[rustc_scalable_vector] +#[allow(non_camel_case_types)] +struct svint64x2_t(svint64_t, svint64_t); + +#[rustc_scalable_vector(2)] +#[allow(non_camel_case_types)] +struct svuint64_t(u64); + +#[rustc_scalable_vector] +#[allow(non_camel_case_types)] +struct svuint64x2_t(svuint64_t, svuint64_t); + +#[rustc_scalable_vector(4)] +#[allow(non_camel_case_types)] +struct svfloat32_t(f32); + +#[rustc_scalable_vector] +#[allow(non_camel_case_types)] +struct svfloat32x2_t(svfloat32_t, svfloat32_t); + +#[rustc_scalable_vector(2)] +#[allow(non_camel_case_types)] +struct svfloat64_t(f64); + +#[rustc_scalable_vector] +#[allow(non_camel_case_types)] +struct svfloat64x2_t(svfloat64_t, svfloat64_t); + +#[target_feature(enable = "sve")] +pub fn locals() { + // CHECK-DAG: name: "svint8x2_t",{{.*}}, baseType: ![[CT8:[0-9]+]] + // CHECK-DAG: ![[CT8]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY8:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS8x2:[0-9]+]]) + // CHECK-DAG: ![[ELTTY8]] = !DIBasicType(name: "i8", size: 8, encoding: DW_ATE_signed) + // CHECK-DAG: ![[ELTS8x2]] = !{![[REALELTS8x2:[0-9]+]]} + // CHECK-DAG: ![[REALELTS8x2]] = !DISubrange(lowerBound: 0, upperBound: !DIExpression(DW_OP_constu, 16, DW_OP_bregx, 46, 0, DW_OP_mul, DW_OP_constu, 1, DW_OP_minus)) + let s8: svint8x2_t; + + // CHECK-DAG: name: "svuint8x2_t",{{.*}}, baseType: ![[CT8:[0-9]+]] + // CHECK-DAG: ![[CT8]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY8:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS8x2]]) + // CHECK-DAG: ![[ELTTY8]] = !DIBasicType(name: "u8", size: 8, encoding: DW_ATE_unsigned) + let u8: svuint8x2_t; + + // CHECK-DAG: name: "svint16x2_t",{{.*}}, baseType: ![[CT16:[0-9]+]] + // CHECK-DAG: ![[CT16]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY16:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS16x2:[0-9]+]]) + // CHECK-DAG: ![[ELTTY16]] = !DIBasicType(name: "i16", size: 16, encoding: DW_ATE_signed) + // CHECK-DAG: ![[ELTS16x2]] = !{![[REALELTS16x2:[0-9]+]]} + // CHECK-DAG: ![[REALELTS16x2]] = !DISubrange(lowerBound: 0, upperBound: !DIExpression(DW_OP_constu, 8, DW_OP_bregx, 46, 0, DW_OP_mul, DW_OP_constu, 1, DW_OP_minus)) + let s16: svint16x2_t; + + // CHECK-DAG: name: "svuint16x2_t",{{.*}}, baseType: ![[CT16:[0-9]+]] + // CHECK-DAG: ![[CT16]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY16:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS16x2]]) + // CHECK-DAG: ![[ELTTY16]] = !DIBasicType(name: "u16", size: 16, encoding: DW_ATE_unsigned) + let u16: svuint16x2_t; + + // CHECK-DAG: name: "svint32x2_t",{{.*}}, baseType: ![[CT32:[0-9]+]] + // CHECK-DAG: ![[CT32]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY32:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS32x2:[0-9]+]]) + // CHECK-DAG: ![[ELTTY32]] = !DIBasicType(name: "i32", size: 32, encoding: DW_ATE_signed) + // CHECK-DAG: ![[ELTS32x2]] = !{![[REALELTS32x2:[0-9]+]]} + // CHECK-DAG: ![[REALELTS32x2]] = !DISubrange(lowerBound: 0, upperBound: !DIExpression(DW_OP_constu, 4, DW_OP_bregx, 46, 0, DW_OP_mul, DW_OP_constu, 1, DW_OP_minus)) + let s32: svint32x2_t; + + // CHECK-DAG: name: "svuint32x2_t",{{.*}}, baseType: ![[CT32:[0-9]+]] + // CHECK-DAG: ![[CT32]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY32:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS32x2]]) + // CHECK-DAG: ![[ELTTY32]] = !DIBasicType(name: "u32", size: 32, encoding: DW_ATE_unsigned) + let u32: svuint32x2_t; + + // CHECK-DAG: name: "svint64x2_t",{{.*}}, baseType: ![[CT64:[0-9]+]] + // CHECK-DAG: ![[CT64]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY64:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS1x2_64:[0-9]+]]) + // CHECK-DAG: ![[ELTTY64]] = !DIBasicType(name: "i64", size: 64, encoding: DW_ATE_signed) + // CHECK-DAG: ![[ELTS1x2_64]] = !{![[REALELTS1x2_64:[0-9]+]]} + // CHECK-DAG: ![[REALELTS1x2_64]] = !DISubrange(lowerBound: 0, upperBound: !DIExpression(DW_OP_constu, 2, DW_OP_bregx, 46, 0, DW_OP_mul, DW_OP_constu, 1, DW_OP_minus)) + let s64: svint64x2_t; + + // CHECK-DAG: name: "svuint64x2_t",{{.*}}, baseType: ![[CT64:[0-9]+]] + // CHECK-DAG: ![[CT64]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY64:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS1x2_64]]) + // CHECK-DAG: ![[ELTTY64]] = !DIBasicType(name: "u64", size: 64, encoding: DW_ATE_unsigned) + let u64: svuint64x2_t; + + // CHECK: name: "svfloat32x2_t",{{.*}}, baseType: ![[CT32:[0-9]+]] + // CHECK-DAG: ![[CT32]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY32:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS32x2]]) + // CHECK-DAG: ![[ELTTY32]] = !DIBasicType(name: "f32", size: 32, encoding: DW_ATE_float) + let f32: svfloat32x2_t; + + // CHECK: name: "svfloat64x2_t",{{.*}}, baseType: ![[CT64:[0-9]+]] + // CHECK-DAG: ![[CT64]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY64:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS1x2_64]]) + // CHECK-DAG: ![[ELTTY64]] = !DIBasicType(name: "f64", size: 64, encoding: DW_ATE_float) + let f64: svfloat64x2_t; +} diff --git a/tests/codegen-llvm/scalable-vectors/debuginfo-tuples-x3.rs b/tests/codegen-llvm/scalable-vectors/debuginfo-tuples-x3.rs new file mode 100644 index 0000000000000..89f76087bb4a7 --- /dev/null +++ b/tests/codegen-llvm/scalable-vectors/debuginfo-tuples-x3.rs @@ -0,0 +1,150 @@ +//@ only-aarch64 +//@ only-linux +//@ compile-flags: -Cdebuginfo=2 -Copt-level=0 + +#![crate_type = "lib"] +#![allow(incomplete_features, internal_features)] +#![feature(rustc_attrs)] + +// Test that we generate the correct debuginfo for scalable vector types. + +#[rustc_scalable_vector(16)] +#[allow(non_camel_case_types)] +struct svint8_t(i8); + +#[rustc_scalable_vector] +#[allow(non_camel_case_types)] +struct svint8x3_t(svint8_t, svint8_t, svint8_t); + +#[rustc_scalable_vector(16)] +#[allow(non_camel_case_types)] +struct svuint8_t(u8); + +#[rustc_scalable_vector] +#[allow(non_camel_case_types)] +struct svuint8x3_t(svuint8_t, svuint8_t, svuint8_t); + +#[rustc_scalable_vector(8)] +#[allow(non_camel_case_types)] +struct svint16_t(i16); + +#[rustc_scalable_vector] +#[allow(non_camel_case_types)] +struct svint16x3_t(svint16_t, svint16_t, svint16_t); + +#[rustc_scalable_vector(8)] +#[allow(non_camel_case_types)] +struct svuint16_t(u16); + +#[rustc_scalable_vector] +#[allow(non_camel_case_types)] +struct svuint16x3_t(svuint16_t, svuint16_t, svuint16_t); + +#[rustc_scalable_vector(4)] +#[allow(non_camel_case_types)] +struct svint32_t(i32); + +#[rustc_scalable_vector] +#[allow(non_camel_case_types)] +struct svint32x3_t(svint32_t, svint32_t, svint32_t); + +#[rustc_scalable_vector(4)] +#[allow(non_camel_case_types)] +struct svuint32_t(u32); + +#[rustc_scalable_vector] +#[allow(non_camel_case_types)] +struct svuint32x3_t(svuint32_t, svuint32_t, svuint32_t); + +#[rustc_scalable_vector(2)] +#[allow(non_camel_case_types)] +struct svint64_t(i64); + +#[rustc_scalable_vector] +#[allow(non_camel_case_types)] +struct svint64x3_t(svint64_t, svint64_t, svint64_t); + +#[rustc_scalable_vector(2)] +#[allow(non_camel_case_types)] +struct svuint64_t(u64); + +#[rustc_scalable_vector] +#[allow(non_camel_case_types)] +struct svuint64x3_t(svuint64_t, svuint64_t, svuint64_t); + +#[rustc_scalable_vector(4)] +#[allow(non_camel_case_types)] +struct svfloat32_t(f32); + +#[rustc_scalable_vector] +#[allow(non_camel_case_types)] +struct svfloat32x3_t(svfloat32_t, svfloat32_t, svfloat32_t); + +#[rustc_scalable_vector(2)] +#[allow(non_camel_case_types)] +struct svfloat64_t(f64); + +#[rustc_scalable_vector] +#[allow(non_camel_case_types)] +struct svfloat64x3_t(svfloat64_t, svfloat64_t, svfloat64_t); + +#[target_feature(enable = "sve")] +pub fn locals() { + // CHECK-DAG: name: "svint8x3_t",{{.*}}, baseType: ![[CT8:[0-9]+]] + // CHECK-DAG: ![[CT8]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY8:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS8x3:[0-9]+]]) + // CHECK-DAG: ![[ELTTY8]] = !DIBasicType(name: "i8", size: 8, encoding: DW_ATE_signed) + // CHECK-DAG: ![[ELTS8x3]] = !{![[REALELTS8x3:[0-9]+]]} + // CHECK-DAG: ![[REALELTS8x3]] = !DISubrange(lowerBound: 0, upperBound: !DIExpression(DW_OP_constu, 24, DW_OP_bregx, 46, 0, DW_OP_mul, DW_OP_constu, 1, DW_OP_minus)) + let s8: svint8x3_t; + + // CHECK-DAG: name: "svuint8x3_t",{{.*}}, baseType: ![[CT8:[0-9]+]] + // CHECK-DAG: ![[CT8]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY8:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS8x3]]) + // CHECK-DAG: ![[ELTTY8]] = !DIBasicType(name: "u8", size: 8, encoding: DW_ATE_unsigned) + let u8: svuint8x3_t; + + // CHECK-DAG: name: "svint16x3_t",{{.*}}, baseType: ![[CT16:[0-9]+]] + // CHECK-DAG: ![[CT16]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY16:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS16x3:[0-9]+]]) + // CHECK-DAG: ![[ELTTY16]] = !DIBasicType(name: "i16", size: 16, encoding: DW_ATE_signed) + // CHECK-DAG: ![[ELTS16x3]] = !{![[REALELTS16x3:[0-9]+]]} + // CHECK-DAG: ![[REALELTS16x3]] = !DISubrange(lowerBound: 0, upperBound: !DIExpression(DW_OP_constu, 12, DW_OP_bregx, 46, 0, DW_OP_mul, DW_OP_constu, 1, DW_OP_minus)) + let s16: svint16x3_t; + + // CHECK-DAG: name: "svuint16x3_t",{{.*}}, baseType: ![[CT16:[0-9]+]] + // CHECK-DAG: ![[CT16]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY16:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS16x3]]) + // CHECK-DAG: ![[ELTTY16]] = !DIBasicType(name: "u16", size: 16, encoding: DW_ATE_unsigned) + let u16: svuint16x3_t; + + // CHECK-DAG: name: "svint32x3_t",{{.*}}, baseType: ![[CT32:[0-9]+]] + // CHECK-DAG: ![[CT32]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY32:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS32x3:[0-9]+]]) + // CHECK-DAG: ![[ELTTY32]] = !DIBasicType(name: "i32", size: 32, encoding: DW_ATE_signed) + // CHECK-DAG: ![[ELTS32x3]] = !{![[REALELTS32x3:[0-9]+]]} + // CHECK-DAG: ![[REALELTS32x3]] = !DISubrange(lowerBound: 0, upperBound: !DIExpression(DW_OP_constu, 6, DW_OP_bregx, 46, 0, DW_OP_mul, DW_OP_constu, 1, DW_OP_minus)) + let s32: svint32x3_t; + + // CHECK-DAG: name: "svuint32x3_t",{{.*}}, baseType: ![[CT32:[0-9]+]] + // CHECK-DAG: ![[CT32]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY32:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS32x3]]) + // CHECK-DAG: ![[ELTTY32]] = !DIBasicType(name: "u32", size: 32, encoding: DW_ATE_unsigned) + let u32: svuint32x3_t; + + // CHECK-DAG: name: "svint64x3_t",{{.*}}, baseType: ![[CT64:[0-9]+]] + // CHECK-DAG: ![[CT64]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY64:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS1x3_64:[0-9]+]]) + // CHECK-DAG: ![[ELTTY64]] = !DIBasicType(name: "i64", size: 64, encoding: DW_ATE_signed) + // CHECK-DAG: ![[ELTS1x3_64]] = !{![[REALELTS1x3_64:[0-9]+]]} + // CHECK-DAG: ![[REALELTS1x3_64]] = !DISubrange(lowerBound: 0, upperBound: !DIExpression(DW_OP_constu, 3, DW_OP_bregx, 46, 0, DW_OP_mul, DW_OP_constu, 1, DW_OP_minus)) + let s64: svint64x3_t; + + // CHECK-DAG: name: "svuint64x3_t",{{.*}}, baseType: ![[CT64:[0-9]+]] + // CHECK-DAG: ![[CT64]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY64:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS1x3_64]]) + // CHECK-DAG: ![[ELTTY64]] = !DIBasicType(name: "u64", size: 64, encoding: DW_ATE_unsigned) + let u64: svuint64x3_t; + + // CHECK: name: "svfloat32x3_t",{{.*}}, baseType: ![[CT32:[0-9]+]] + // CHECK-DAG: ![[CT32]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY32:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS32x3]]) + // CHECK-DAG: ![[ELTTY32]] = !DIBasicType(name: "f32", size: 32, encoding: DW_ATE_float) + let f32: svfloat32x3_t; + + // CHECK: name: "svfloat64x3_t",{{.*}}, baseType: ![[CT64:[0-9]+]] + // CHECK-DAG: ![[CT64]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY64:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS1x3_64]]) + // CHECK-DAG: ![[ELTTY64]] = !DIBasicType(name: "f64", size: 64, encoding: DW_ATE_float) + let f64: svfloat64x3_t; +} diff --git a/tests/codegen-llvm/scalable-vectors/debuginfo-tuples-x4.rs b/tests/codegen-llvm/scalable-vectors/debuginfo-tuples-x4.rs new file mode 100644 index 0000000000000..0daa3f8747d54 --- /dev/null +++ b/tests/codegen-llvm/scalable-vectors/debuginfo-tuples-x4.rs @@ -0,0 +1,150 @@ +//@ only-aarch64 +//@ only-linux +//@ compile-flags: -Cdebuginfo=2 -Copt-level=0 + +#![crate_type = "lib"] +#![allow(incomplete_features, internal_features)] +#![feature(rustc_attrs)] + +// Test that we generate the correct debuginfo for scalable vector types. + +#[rustc_scalable_vector(16)] +#[allow(non_camel_case_types)] +struct svint8_t(i8); + +#[rustc_scalable_vector] +#[allow(non_camel_case_types)] +struct svint8x4_t(svint8_t, svint8_t, svint8_t, svint8_t); + +#[rustc_scalable_vector(16)] +#[allow(non_camel_case_types)] +struct svuint8_t(u8); + +#[rustc_scalable_vector] +#[allow(non_camel_case_types)] +struct svuint8x4_t(svuint8_t, svuint8_t, svuint8_t, svuint8_t); + +#[rustc_scalable_vector(8)] +#[allow(non_camel_case_types)] +struct svint16_t(i16); + +#[rustc_scalable_vector] +#[allow(non_camel_case_types)] +struct svint16x4_t(svint16_t, svint16_t, svint16_t, svint16_t); + +#[rustc_scalable_vector(8)] +#[allow(non_camel_case_types)] +struct svuint16_t(u16); + +#[rustc_scalable_vector] +#[allow(non_camel_case_types)] +struct svuint16x4_t(svuint16_t, svuint16_t, svuint16_t, svuint16_t); + +#[rustc_scalable_vector(4)] +#[allow(non_camel_case_types)] +struct svint32_t(i32); + +#[rustc_scalable_vector] +#[allow(non_camel_case_types)] +struct svint32x4_t(svint32_t, svint32_t, svint32_t, svint32_t); + +#[rustc_scalable_vector(4)] +#[allow(non_camel_case_types)] +struct svuint32_t(u32); + +#[rustc_scalable_vector] +#[allow(non_camel_case_types)] +struct svuint32x4_t(svuint32_t, svuint32_t, svuint32_t, svuint32_t); + +#[rustc_scalable_vector(2)] +#[allow(non_camel_case_types)] +struct svint64_t(i64); + +#[rustc_scalable_vector] +#[allow(non_camel_case_types)] +struct svint64x4_t(svint64_t, svint64_t, svint64_t, svint64_t); + +#[rustc_scalable_vector(2)] +#[allow(non_camel_case_types)] +struct svuint64_t(u64); + +#[rustc_scalable_vector] +#[allow(non_camel_case_types)] +struct svuint64x4_t(svuint64_t, svuint64_t, svuint64_t, svuint64_t); + +#[rustc_scalable_vector(4)] +#[allow(non_camel_case_types)] +struct svfloat32_t(f32); + +#[rustc_scalable_vector] +#[allow(non_camel_case_types)] +struct svfloat32x4_t(svfloat32_t, svfloat32_t, svfloat32_t, svfloat32_t); + +#[rustc_scalable_vector(2)] +#[allow(non_camel_case_types)] +struct svfloat64_t(f64); + +#[rustc_scalable_vector] +#[allow(non_camel_case_types)] +struct svfloat64x4_t(svfloat64_t, svfloat64_t, svfloat64_t, svfloat64_t); + +#[target_feature(enable = "sve")] +pub fn locals() { + // CHECK-DAG: name: "svint8x4_t",{{.*}}, baseType: ![[CT8:[0-9]+]] + // CHECK-DAG: ![[CT8]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY8:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS8x4:[0-9]+]]) + // CHECK-DAG: ![[ELTTY8]] = !DIBasicType(name: "i8", size: 8, encoding: DW_ATE_signed) + // CHECK-DAG: ![[ELTS8x4]] = !{![[REALELTS8x4:[0-9]+]]} + // CHECK-DAG: ![[REALELTS8x4]] = !DISubrange(lowerBound: 0, upperBound: !DIExpression(DW_OP_constu, 32, DW_OP_bregx, 46, 0, DW_OP_mul, DW_OP_constu, 1, DW_OP_minus)) + let s8: svint8x4_t; + + // CHECK-DAG: name: "svuint8x4_t",{{.*}}, baseType: ![[CT8:[0-9]+]] + // CHECK-DAG: ![[CT8]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY8:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS8x4]]) + // CHECK-DAG: ![[ELTTY8]] = !DIBasicType(name: "u8", size: 8, encoding: DW_ATE_unsigned) + let u8: svuint8x4_t; + + // CHECK-DAG: name: "svint16x4_t",{{.*}}, baseType: ![[CT16:[0-9]+]] + // CHECK-DAG: ![[CT16]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY16:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS16x4:[0-9]+]]) + // CHECK-DAG: ![[ELTTY16]] = !DIBasicType(name: "i16", size: 16, encoding: DW_ATE_signed) + // CHECK-DAG: ![[ELTS16x4]] = !{![[REALELTS16x4:[0-9]+]]} + // CHECK-DAG: ![[REALELTS16x4]] = !DISubrange(lowerBound: 0, upperBound: !DIExpression(DW_OP_constu, 16, DW_OP_bregx, 46, 0, DW_OP_mul, DW_OP_constu, 1, DW_OP_minus)) + let s16: svint16x4_t; + + // CHECK-DAG: name: "svuint16x4_t",{{.*}}, baseType: ![[CT16:[0-9]+]] + // CHECK-DAG: ![[CT16]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY16:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS16x4]]) + // CHECK-DAG: ![[ELTTY16]] = !DIBasicType(name: "u16", size: 16, encoding: DW_ATE_unsigned) + let u16: svuint16x4_t; + + // CHECK-DAG: name: "svint32x4_t",{{.*}}, baseType: ![[CT32:[0-9]+]] + // CHECK-DAG: ![[CT32]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY32:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS32x4:[0-9]+]]) + // CHECK-DAG: ![[ELTTY32]] = !DIBasicType(name: "i32", size: 32, encoding: DW_ATE_signed) + // CHECK-DAG: ![[ELTS32x4]] = !{![[REALELTS32x4:[0-9]+]]} + // CHECK-DAG: ![[REALELTS32x4]] = !DISubrange(lowerBound: 0, upperBound: !DIExpression(DW_OP_constu, 8, DW_OP_bregx, 46, 0, DW_OP_mul, DW_OP_constu, 1, DW_OP_minus)) + let s32: svint32x4_t; + + // CHECK-DAG: name: "svuint32x4_t",{{.*}}, baseType: ![[CT32:[0-9]+]] + // CHECK-DAG: ![[CT32]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY32:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS32x4]]) + // CHECK-DAG: ![[ELTTY32]] = !DIBasicType(name: "u32", size: 32, encoding: DW_ATE_unsigned) + let u32: svuint32x4_t; + + // CHECK-DAG: name: "svint64x4_t",{{.*}}, baseType: ![[CT64:[0-9]+]] + // CHECK-DAG: ![[CT64]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY64:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS1x4_64:[0-9]+]]) + // CHECK-DAG: ![[ELTTY64]] = !DIBasicType(name: "i64", size: 64, encoding: DW_ATE_signed) + // CHECK-DAG: ![[ELTS1x4_64]] = !{![[REALELTS1x4_64:[0-9]+]]} + // CHECK-DAG: ![[REALELTS1x4_64]] = !DISubrange(lowerBound: 0, upperBound: !DIExpression(DW_OP_constu, 4, DW_OP_bregx, 46, 0, DW_OP_mul, DW_OP_constu, 1, DW_OP_minus)) + let s64: svint64x4_t; + + // CHECK-DAG: name: "svuint64x4_t",{{.*}}, baseType: ![[CT64:[0-9]+]] + // CHECK-DAG: ![[CT64]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY64:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS1x4_64]]) + // CHECK-DAG: ![[ELTTY64]] = !DIBasicType(name: "u64", size: 64, encoding: DW_ATE_unsigned) + let u64: svuint64x4_t; + + // CHECK: name: "svfloat32x4_t",{{.*}}, baseType: ![[CT32:[0-9]+]] + // CHECK-DAG: ![[CT32]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY32:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS32x4]]) + // CHECK-DAG: ![[ELTTY32]] = !DIBasicType(name: "f32", size: 32, encoding: DW_ATE_float) + let f32: svfloat32x4_t; + + // CHECK: name: "svfloat64x4_t",{{.*}}, baseType: ![[CT64:[0-9]+]] + // CHECK-DAG: ![[CT64]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY64:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS1x4_64]]) + // CHECK-DAG: ![[ELTTY64]] = !DIBasicType(name: "f64", size: 64, encoding: DW_ATE_float) + let f64: svfloat64x4_t; +} diff --git a/tests/codegen-llvm/scalable-vectors/debuginfo.rs b/tests/codegen-llvm/scalable-vectors/debuginfo.rs new file mode 100644 index 0000000000000..8b2724f06f3e0 --- /dev/null +++ b/tests/codegen-llvm/scalable-vectors/debuginfo.rs @@ -0,0 +1,124 @@ +// ignore-tidy-linelength +//@ only-aarch64 +//@ only-linux +//@ compile-flags: -Cdebuginfo=2 -Copt-level=0 +//@ revisions: POST-LLVM-22 PRE-LLVM-22 +//@ [PRE-LLVM-22] max-llvm-major-version: 21 +//@ [POST-LLVM-22] min-llvm-version: 22 + +#![crate_type = "lib"] +#![allow(incomplete_features, internal_features)] +#![feature(rustc_attrs)] + +// Test that we generate the correct debuginfo for scalable vector types. + +#[rustc_scalable_vector(16)] +#[allow(non_camel_case_types)] +struct svbool_t(bool); + +#[rustc_scalable_vector(16)] +#[allow(non_camel_case_types)] +struct svint8_t(i8); + +#[rustc_scalable_vector(16)] +#[allow(non_camel_case_types)] +struct svuint8_t(u8); + +#[rustc_scalable_vector(8)] +#[allow(non_camel_case_types)] +struct svint16_t(i16); + +#[rustc_scalable_vector(8)] +#[allow(non_camel_case_types)] +struct svuint16_t(u16); + +#[rustc_scalable_vector(4)] +#[allow(non_camel_case_types)] +struct svint32_t(i32); + +#[rustc_scalable_vector(4)] +#[allow(non_camel_case_types)] +struct svuint32_t(u32); + +#[rustc_scalable_vector(2)] +#[allow(non_camel_case_types)] +struct svint64_t(i64); + +#[rustc_scalable_vector(2)] +#[allow(non_camel_case_types)] +struct svuint64_t(u64); + +#[rustc_scalable_vector(4)] +#[allow(non_camel_case_types)] +struct svfloat32_t(f32); + +#[rustc_scalable_vector(2)] +#[allow(non_camel_case_types)] +struct svfloat64_t(f64); + +#[target_feature(enable = "sve")] +pub fn locals() { + // CHECK-DAG: name: "svbool_t",{{.*}}, baseType: ![[CT1:[0-9]+]] + // PRE-LLVM-22-DAG: ![[CT1]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTYU8:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS8:[0-9]+]]) + // POST-LLVM-22-DAG: ![[CT1]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTYU8:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS8:[0-9]+]], bitStride: i64 1) + // CHECK-DAG: ![[ELTTYU8]] = !DIBasicType(name: "u8", size: 8, encoding: DW_ATE_unsigned) + // CHECK-DAG: ![[ELTS8]] = !{![[REALELTS8:[0-9]+]]} + // CHECK-DAG: ![[REALELTS8]] = !DISubrange(lowerBound: 0, upperBound: !DIExpression(DW_OP_constu, 8, DW_OP_bregx, 46, 0, DW_OP_mul, DW_OP_constu, 1, DW_OP_minus)) + let b8: svbool_t; + + // CHECK-DAG: name: "svint8_t",{{.*}}, baseType: ![[CT8:[0-9]+]] + // CHECK-DAG: ![[CT8]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTYS8:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS8:[0-9]+]]) + // CHECK-DAG: ![[ELTTYS8]] = !DIBasicType(name: "i8", size: 8, encoding: DW_ATE_signed) + let s8: svint8_t; + + // PRE-LLVM-22-DAG: name: "svuint8_t",{{.*}}, baseType: ![[CT1:[0-9]+]] + // POST-LLVM-22-DAG: name: "svuint8_t",{{.*}}, baseType: ![[CT8:[0-9]+]] + // POST-LLVM-22-DAG: ![[CT8]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTYU8]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS8]]) + let u8: svuint8_t; + + // CHECK-DAG: name: "svint16_t",{{.*}}, baseType: ![[CT16:[0-9]+]] + // CHECK-DAG: ![[CT16]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY16:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS16:[0-9]+]]) + // CHECK-DAG: ![[ELTTY16]] = !DIBasicType(name: "i16", size: 16, encoding: DW_ATE_signed) + // CHECK-DAG: ![[ELTS16]] = !{![[REALELTS16:[0-9]+]]} + // CHECK-DAG: ![[REALELTS16]] = !DISubrange(lowerBound: 0, upperBound: !DIExpression(DW_OP_constu, 4, DW_OP_bregx, 46, 0, DW_OP_mul, DW_OP_constu, 1, DW_OP_minus)) + let s16: svint16_t; + + // CHECK-DAG: name: "svuint16_t",{{.*}}, baseType: ![[CT16:[0-9]+]] + // CHECK-DAG: ![[CT16]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY16:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS16]]) + // CHECK-DAG: ![[ELTTY16]] = !DIBasicType(name: "u16", size: 16, encoding: DW_ATE_unsigned) + let u16: svuint16_t; + + // CHECK-DAG: name: "svint32_t",{{.*}}, baseType: ![[CT32:[0-9]+]] + // CHECK-DAG: ![[CT32]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY32:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS32:[0-9]+]]) + // CHECK-DAG: ![[ELTTY32]] = !DIBasicType(name: "i32", size: 32, encoding: DW_ATE_signed) + // CHECK-DAG: ![[ELTS32]] = !{![[REALELTS32:[0-9]+]]} + // CHECK-DAG: ![[REALELTS32]] = !DISubrange(lowerBound: 0, upperBound: !DIExpression(DW_OP_constu, 2, DW_OP_bregx, 46, 0, DW_OP_mul, DW_OP_constu, 1, DW_OP_minus)) + let s32: svint32_t; + + // CHECK-DAG: name: "svuint32_t",{{.*}}, baseType: ![[CT32:[0-9]+]] + // CHECK-DAG: ![[CT32]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY32:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS32]]) + // CHECK-DAG: ![[ELTTY32]] = !DIBasicType(name: "u32", size: 32, encoding: DW_ATE_unsigned) + let u32: svuint32_t; + + // CHECK-DAG: name: "svint64_t",{{.*}}, baseType: ![[CT64:[0-9]+]] + // CHECK-DAG: ![[CT64]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY64:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS64:[0-9]+]]) + // CHECK-DAG: ![[ELTTY64]] = !DIBasicType(name: "i64", size: 64, encoding: DW_ATE_signed) + // CHECK-DAG: ![[ELTS64]] = !{![[REALELTS64:[0-9]+]]} + // CHECK-DAG: ![[REALELTS64]] = !DISubrange(lowerBound: 0, upperBound: !DIExpression(DW_OP_constu, 1, DW_OP_bregx, 46, 0, DW_OP_mul, DW_OP_constu, 1, DW_OP_minus)) + let s64: svint64_t; + + // CHECK-DAG: name: "svuint64_t",{{.*}}, baseType: ![[CT64:[0-9]+]] + // CHECK-DAG: ![[CT64]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY64:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS64]]) + // CHECK-DAG: ![[ELTTY64]] = !DIBasicType(name: "u64", size: 64, encoding: DW_ATE_unsigned) + let u64: svuint64_t; + + // CHECK: name: "svfloat32_t",{{.*}}, baseType: ![[CT32:[0-9]+]] + // CHECK-DAG: ![[CT32]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY32:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS32]]) + // CHECK-DAG: ![[ELTTY32]] = !DIBasicType(name: "f32", size: 32, encoding: DW_ATE_float) + let f32: svfloat32_t; + + // CHECK: name: "svfloat64_t",{{.*}}, baseType: ![[CT64:[0-9]+]] + // CHECK-DAG: ![[CT64]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY64:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS64]]) + // CHECK-DAG: ![[ELTTY64]] = !DIBasicType(name: "f64", size: 64, encoding: DW_ATE_float) + let f64: svfloat64_t; +} diff --git a/tests/codegen-llvm/scalable-vectors/tuple-intrinsics.rs b/tests/codegen-llvm/scalable-vectors/tuple-intrinsics.rs new file mode 100644 index 0000000000000..e19fc40cb9d67 --- /dev/null +++ b/tests/codegen-llvm/scalable-vectors/tuple-intrinsics.rs @@ -0,0 +1,100 @@ +//@ build-pass +//@ only-aarch64 +#![crate_type = "lib"] +#![allow(incomplete_features, internal_features)] +#![feature(abi_unadjusted, core_intrinsics, link_llvm_intrinsics, rustc_attrs)] + +// Tests that tuples of scalable vectors are passed as immediates and that the intrinsics for +// creating/getting/setting tuples of scalable vectors generate the correct assembly + +#[derive(Copy, Clone)] +#[rustc_scalable_vector(4)] +#[allow(non_camel_case_types)] +pub struct svfloat32_t(f32); + +#[derive(Copy, Clone)] +#[rustc_scalable_vector] +#[allow(non_camel_case_types)] +pub struct svfloat32x2_t(svfloat32_t, svfloat32_t); + +#[derive(Copy, Clone)] +#[rustc_scalable_vector] +#[allow(non_camel_case_types)] +pub struct svfloat32x3_t(svfloat32_t, svfloat32_t, svfloat32_t); + +#[derive(Copy, Clone)] +#[rustc_scalable_vector] +#[allow(non_camel_case_types)] +pub struct svfloat32x4_t(svfloat32_t, svfloat32_t, svfloat32_t, svfloat32_t); + +#[inline(never)] +#[target_feature(enable = "sve")] +pub fn svdup_n_f32(op: f32) -> svfloat32_t { + extern "C" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.dup.x.nxv4f32")] + fn _svdup_n_f32(op: f32) -> svfloat32_t; + } + unsafe { _svdup_n_f32(op) } +} + +// CHECK: define { , } @svcreate2_f32( %x0, %x1) +#[no_mangle] +#[target_feature(enable = "sve")] +pub fn svcreate2_f32(x0: svfloat32_t, x1: svfloat32_t) -> svfloat32x2_t { + // CHECK: %1 = insertvalue { , } poison, %x0, 0 + // CHECK-NEXT: %2 = insertvalue { , } %1, %x1, 1 + unsafe { std::intrinsics::simd::scalable::sve_tuple_create2(x0, x1) } +} + +// CHECK: define { , , } @svcreate3_f32( %x0, %x1, %x2) +#[no_mangle] +#[target_feature(enable = "sve")] +pub fn svcreate3_f32(x0: svfloat32_t, x1: svfloat32_t, x2: svfloat32_t) -> svfloat32x3_t { + // CHECK-LABEL: @_RNvCsk3YxfLN8zWY_6tuples13svcreate3_f32 + // CHECK: %1 = insertvalue { , , } poison, %x0, 0 + // CHECK-NEXT: %2 = insertvalue { , , } %1, %x1, 1 + // CHECK-NEXT: %3 = insertvalue { , , } %2, %x2, 2 + unsafe { std::intrinsics::simd::scalable::sve_tuple_create3(x0, x1, x2) } +} + +// CHECK: define { , , , } @svcreate4_f32( %x0, %x1, %x2, %x3) +#[no_mangle] +#[target_feature(enable = "sve")] +pub fn svcreate4_f32( + x0: svfloat32_t, + x1: svfloat32_t, + x2: svfloat32_t, + x3: svfloat32_t, +) -> svfloat32x4_t { + // CHECK-LABEL: @_RNvCsk3YxfLN8zWY_6tuples13svcreate4_f32 + // CHECK: %1 = insertvalue { , , , } poison, %x0, 0 + // CHECK-NEXT: %2 = insertvalue { , , , } %1, %x1, 1 + // CHECK-NEXT: %3 = insertvalue { , , , } %2, %x2, 2 + // CHECK-NEXT: %4 = insertvalue { , , , } %3, %x3, 3 + unsafe { std::intrinsics::simd::scalable::sve_tuple_create4(x0, x1, x2, x3) } +} + +// CHECK: define @svget2_f32({ , } %tup) +#[no_mangle] +#[target_feature(enable = "sve")] +pub fn svget2_f32(tup: svfloat32x2_t) -> svfloat32_t { + // CHECK: %1 = extractvalue { , } %tup, 0 + unsafe { std::intrinsics::simd::scalable::sve_tuple_get::<_, _, { IDX }>(tup) } +} + +// CHECK: define { , } @svset2_f32({ , } %tup, %x) +#[no_mangle] +#[target_feature(enable = "sve")] +pub fn svset2_f32(tup: svfloat32x2_t, x: svfloat32_t) -> svfloat32x2_t { + // CHECK: %1 = insertvalue { , } %tup, %x, 0 + unsafe { std::intrinsics::simd::scalable::sve_tuple_set::<_, _, { IDX }>(tup, x) } +} + +// This function exists only so there are calls to the generic functions +#[target_feature(enable = "sve")] +pub fn test() { + let x = svdup_n_f32(2f32); + let tup = svcreate2_f32(x, x); + let x = svget2_f32::<0>(tup); + let tup = svset2_f32::<0>(tup, x); +} diff --git a/tests/ui/const-generics/generic_const_exprs/escaping-late-bound-region-in-canonical-ice-113870.rs b/tests/ui/const-generics/generic_const_exprs/escaping-late-bound-region-in-canonical-ice-113870.rs new file mode 100644 index 0000000000000..6a75bf6ca4b73 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/escaping-late-bound-region-in-canonical-ice-113870.rs @@ -0,0 +1,24 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/113870 + +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] + +const fn allow<'b, 'b>() -> usize +//~^ ERROR the name `'b` is already used for a generic parameter in this item's generic parameters +where + for<'b> [u8; foo::<'a, 'b>()]: Sized, + //~^ ERROR lifetime name `'b` shadows a lifetime name that is already in scope + //~| ERROR use of undeclared lifetime name `'a` + //~| ERROR cannot capture late-bound lifetime in constant +{ + 4 +} + +const fn foo<'a, 'b>() -> usize +where + &'a (): Sized, + &'b (): Sized, +{ + 4 +} +//~^ ERROR `main` function not found in crate diff --git a/tests/ui/const-generics/generic_const_exprs/escaping-late-bound-region-in-canonical-ice-113870.stderr b/tests/ui/const-generics/generic_const_exprs/escaping-late-bound-region-in-canonical-ice-113870.stderr new file mode 100644 index 0000000000000..f036a2a341e3c --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/escaping-late-bound-region-in-canonical-ice-113870.stderr @@ -0,0 +1,52 @@ +error[E0403]: the name `'b` is already used for a generic parameter in this item's generic parameters + --> $DIR/escaping-late-bound-region-in-canonical-ice-113870.rs:6:20 + | +LL | const fn allow<'b, 'b>() -> usize + | -- ^^ already used + | | + | first use of `'b` + +error[E0496]: lifetime name `'b` shadows a lifetime name that is already in scope + --> $DIR/escaping-late-bound-region-in-canonical-ice-113870.rs:9:9 + | +LL | const fn allow<'b, 'b>() -> usize + | -- first declared here +... +LL | for<'b> [u8; foo::<'a, 'b>()]: Sized, + | ^^ lifetime `'b` already in scope + +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/escaping-late-bound-region-in-canonical-ice-113870.rs:9:24 + | +LL | for<'b> [u8; foo::<'a, 'b>()]: Sized, + | ^^ undeclared lifetime + | + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the bound lifetime-generic with a new `'a` lifetime + | +LL | for<'a, 'b> [u8; foo::<'a, 'b>()]: Sized, + | +++ +help: consider introducing lifetime `'a` here + | +LL | const fn allow<'a, 'b, 'b>() -> usize + | +++ + +error[E0601]: `main` function not found in crate `escaping_late_bound_region_in_canonical_ice_113870` + --> $DIR/escaping-late-bound-region-in-canonical-ice-113870.rs:23:2 + | +LL | } + | ^ consider adding a `main` function to `$DIR/escaping-late-bound-region-in-canonical-ice-113870.rs` + +error: cannot capture late-bound lifetime in constant + --> $DIR/escaping-late-bound-region-in-canonical-ice-113870.rs:9:28 + | +LL | const fn allow<'b, 'b>() -> usize + | -- lifetime defined here +... +LL | for<'b> [u8; foo::<'a, 'b>()]: Sized, + | ^^ + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0261, E0403, E0496, E0601. +For more information about an error, try `rustc --explain E0261`. diff --git a/tests/ui/const-generics/generic_const_exprs/ice-wrapper-impl-trait-with-const-bound-118278.rs b/tests/ui/const-generics/generic_const_exprs/ice-wrapper-impl-trait-with-const-bound-118278.rs new file mode 100644 index 0000000000000..02dff02430989 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/ice-wrapper-impl-trait-with-const-bound-118278.rs @@ -0,0 +1,28 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/118278 + +//@ check-pass + +#![allow(incomplete_features)] +#![feature(generic_const_exprs)] + +pub trait Foo { + const SIZE: usize; +} + +impl Foo for u64 { + const SIZE: usize = 8; +} + +pub struct Wrapper +where + T: Foo, + [(); T::SIZE]:, +{ + pub t: T, +} + +pub fn bar() -> Wrapper { + Wrapper { t: 10 } +} + +fn main() {} diff --git a/tests/ui/const-generics/min_adt_const_params/const_param_ty-on-adt-without-adt-gate.rs b/tests/ui/const-generics/min_adt_const_params/const_param_ty-on-adt-without-adt-gate.rs new file mode 100644 index 0000000000000..9b5c62c412995 --- /dev/null +++ b/tests/ui/const-generics/min_adt_const_params/const_param_ty-on-adt-without-adt-gate.rs @@ -0,0 +1,17 @@ +//! Ensure we enforce `min_adt_const_params` rules on any adt `ConstParamTy_` +//! implementation unless `adt_const_params` feature is used. +#![allow(incomplete_features)] +#![feature(const_param_ty_trait)] + +use std::marker::ConstParamTy_; + +#[derive(PartialEq, Eq)] +pub struct Fumo { + cirno: i32, + pub(crate) reimu: i32 +} + +impl ConstParamTy_ for Fumo {} + //~^ ERROR: the trait `ConstParamTy` may not be implemented for this struct + +fn main() {} diff --git a/tests/ui/const-generics/min_adt_const_params/const_param_ty-on-adt-without-adt-gate.stderr b/tests/ui/const-generics/min_adt_const_params/const_param_ty-on-adt-without-adt-gate.stderr new file mode 100644 index 0000000000000..784c6f0937d8a --- /dev/null +++ b/tests/ui/const-generics/min_adt_const_params/const_param_ty-on-adt-without-adt-gate.stderr @@ -0,0 +1,8 @@ +error: the trait `ConstParamTy` may not be implemented for this struct + --> $DIR/const_param_ty-on-adt-without-adt-gate.rs:14:24 + | +LL | impl ConstParamTy_ for Fumo {} + | ^^^^ struct fields are less visible than the struct + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/min_adt_const_params/min_adt_const_params-gate-fail.rs b/tests/ui/const-generics/min_adt_const_params/min_adt_const_params-gate-fail.rs new file mode 100644 index 0000000000000..bb18a3314f4c6 --- /dev/null +++ b/tests/ui/const-generics/min_adt_const_params/min_adt_const_params-gate-fail.rs @@ -0,0 +1,35 @@ +//! Ensure min_adt_const_params enforce +//! struct's visibility on its fields +#![allow(incomplete_features)] +#![feature(min_adt_const_params)] +#![feature(const_param_ty_trait)] + +use std::marker::ConstParamTy_; + +#[derive(PartialEq, Eq)] +pub struct Meowl { + pub public: i32, + private: i32 +} + +#[derive(PartialEq, Eq)] +pub struct Meowl2 { + pub a: i32, + pub b: i32 +} + +#[derive(PartialEq, Eq)] +pub(crate) struct Meowl3 { + pub(crate) a: i32, + pub b: i32 +} + +impl ConstParamTy_ for Meowl {} + //~^ ERROR the trait `ConstParamTy` may not be implemented for this struct +impl ConstParamTy_ for Meowl2 {} +impl ConstParamTy_ for Meowl3 {} + +fn something() {} +fn something2() {} + +fn main() {} diff --git a/tests/ui/const-generics/min_adt_const_params/min_adt_const_params-gate-fail.stderr b/tests/ui/const-generics/min_adt_const_params/min_adt_const_params-gate-fail.stderr new file mode 100644 index 0000000000000..fec610f061c20 --- /dev/null +++ b/tests/ui/const-generics/min_adt_const_params/min_adt_const_params-gate-fail.stderr @@ -0,0 +1,8 @@ +error: the trait `ConstParamTy` may not be implemented for this struct + --> $DIR/min_adt_const_params-gate-fail.rs:27:24 + | +LL | impl ConstParamTy_ for Meowl {} + | ^^^^^ struct fields are less visible than the struct + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/min_adt_const_params/min_adt_const_params-gate.rs b/tests/ui/const-generics/min_adt_const_params/min_adt_const_params-gate.rs new file mode 100644 index 0000000000000..e33f5b0fac99b --- /dev/null +++ b/tests/ui/const-generics/min_adt_const_params/min_adt_const_params-gate.rs @@ -0,0 +1,18 @@ +// gate-test-min_adt_const_params +//@run-pass +#![feature(min_adt_const_params, const_param_ty_trait)] +#![allow(incomplete_features, dead_code)] + +use std::marker::ConstParamTy_; + +#[derive(PartialEq, Eq)] +pub struct Meowl { + pub public: i32, + pub also_public: i32 +} + +impl ConstParamTy_ for Meowl {} + +fn meoow() {} + +fn main() {} diff --git a/tests/ui/const-generics/min_adt_const_params/type-field-more-visible-than-type.rs b/tests/ui/const-generics/min_adt_const_params/type-field-more-visible-than-type.rs new file mode 100644 index 0000000000000..cedec86675f3e --- /dev/null +++ b/tests/ui/const-generics/min_adt_const_params/type-field-more-visible-than-type.rs @@ -0,0 +1,12 @@ +//@run-pass +#![feature(min_adt_const_params)] + +use std::marker::ConstParamTy; + +#[derive(ConstParamTy, Eq, PartialEq)] +#[allow(dead_code)] +struct Foo { + pub field: u32, +} + +fn main() {} diff --git a/tests/ui/generics/wrong-number-of-args.stderr b/tests/ui/generics/wrong-number-of-args.stderr index 554d017d67e33..953cd273eb764 100644 --- a/tests/ui/generics/wrong-number-of-args.stderr +++ b/tests/ui/generics/wrong-number-of-args.stderr @@ -28,8 +28,8 @@ LL | type E = Ty<>; | help: consider introducing a named lifetime parameter | -LL | type E<'a> = Ty<'a, >; - | ++++ +++ +LL | type E<'a> = Ty<'a>; + | ++++ ++ error[E0106]: missing lifetime specifier --> $DIR/wrong-number-of-args.rs:120:22 @@ -55,12 +55,12 @@ LL | type F = Box>; | help: consider making the bound lifetime-generic with a new `'a` lifetime | -LL | type F = Box GenericLifetime<'a, >>; - | +++++++ +++ +LL | type F = Box GenericLifetime<'a>>; + | +++++++ ++ help: consider introducing a named lifetime parameter | -LL | type F<'a> = Box>; - | ++++ +++ +LL | type F<'a> = Box>; + | ++++ ++ error[E0106]: missing lifetime specifier --> $DIR/wrong-number-of-args.rs:163:43 diff --git a/tests/ui/lifetimes/E0106-trailing-comma-in-lifetime-suggestion.rs b/tests/ui/lifetimes/E0106-trailing-comma-in-lifetime-suggestion.rs new file mode 100644 index 0000000000000..acf93ae51cc4d --- /dev/null +++ b/tests/ui/lifetimes/E0106-trailing-comma-in-lifetime-suggestion.rs @@ -0,0 +1,18 @@ +// Regression test for . +// +// When suggesting lifetime parameters for empty angle brackets like `Foo<>`, +// the suggestion should not include a trailing comma (e.g., `Foo<'a>` not `Foo<'a, >`). +// When there are other generic arguments like `Foo`, the trailing comma is needed +// (e.g., `Foo<'a, T>`). + +#![crate_type = "lib"] + +struct Foo<'a>(&'a ()); + +type A = Foo<>; +//~^ ERROR missing lifetime specifier [E0106] + +struct Bar<'a, T>(&'a T); + +type B = Bar; +//~^ ERROR missing lifetime specifier [E0106] diff --git a/tests/ui/lifetimes/E0106-trailing-comma-in-lifetime-suggestion.stderr b/tests/ui/lifetimes/E0106-trailing-comma-in-lifetime-suggestion.stderr new file mode 100644 index 0000000000000..f189c259d65f9 --- /dev/null +++ b/tests/ui/lifetimes/E0106-trailing-comma-in-lifetime-suggestion.stderr @@ -0,0 +1,25 @@ +error[E0106]: missing lifetime specifier + --> $DIR/E0106-trailing-comma-in-lifetime-suggestion.rs:12:13 + | +LL | type A = Foo<>; + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | type A<'a> = Foo<'a>; + | ++++ ++ + +error[E0106]: missing lifetime specifier + --> $DIR/E0106-trailing-comma-in-lifetime-suggestion.rs:17:13 + | +LL | type B = Bar; + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | type B<'a> = Bar<'a, u8>; + | ++++ +++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0106`. diff --git a/tests/ui/privacy/private-field-deref-confusion-issue-149546.rs b/tests/ui/privacy/private-field-deref-confusion-issue-149546.rs new file mode 100644 index 0000000000000..ec26c879d4eb3 --- /dev/null +++ b/tests/ui/privacy/private-field-deref-confusion-issue-149546.rs @@ -0,0 +1,88 @@ +// Field lookup still resolves to the public field on the Deref target, but +// follow-up diagnostics should explain that the original type has a same-named +// private field with a different type. +//@ dont-require-annotations: ERROR + +mod structs { + pub struct A { + field: usize, + b: B, + } + + pub struct B { + pub field: bool, + } + + impl std::ops::Deref for A { + type Target = B; + + fn deref(&self) -> &Self::Target { + &self.b + } + } +} + +use structs::A; + +fn takes_usize(_: usize) {} + +trait Marker {} + +impl Marker for usize {} + +struct Wrapper(i32); + +impl std::ops::Add for Wrapper { + type Output = (); + + fn add(self, _: T) {} +} + +fn by_value(a: A) { + a.field + 5; +} + +fn by_ref(a: &A) { + a.field + 5; +} + +fn rhs_by_value(a: A) { + 5 + a.field; +} + +fn rhs_by_ref(a: &A) { + 5 + a.field; +} + +fn rhs_assign_op_by_value(a: A) { + let mut n = 5; + n += a.field; +} + +fn rhs_assign_op_by_ref(a: &A) { + let mut n = 5; + n += a.field; +} + +fn rhs_nested_obligation(a: A) { + Wrapper(5) + a.field; +} + +fn method_call(a: A) { + a.field.count_ones(); +} + +fn type_mismatch(a: A) { + let value: usize = a.field; + eprintln!("value: {value}"); +} + +fn function_arg(a: A) { + takes_usize(a.field); +} + +fn return_value(a: &A) -> usize { + a.field +} + +fn main() {} diff --git a/tests/ui/privacy/private-field-deref-confusion-issue-149546.stderr b/tests/ui/privacy/private-field-deref-confusion-issue-149546.stderr new file mode 100644 index 0000000000000..9f2bb523913c8 --- /dev/null +++ b/tests/ui/privacy/private-field-deref-confusion-issue-149546.stderr @@ -0,0 +1,317 @@ +error[E0369]: cannot add `{integer}` to `bool` + --> $DIR/private-field-deref-confusion-issue-149546.rs:42:13 + | +LL | a.field + 5; + | ------- ^ - {integer} + | | + | bool + | +note: there is a field `field` on `A` with type `usize` but it is private; `field` from `B` was accessed through auto-deref instead + --> $DIR/private-field-deref-confusion-issue-149546.rs:7:16 + | +LL | pub struct A { + | ^ in this struct +LL | field: usize, + | ----- if this field wasn't private, it would be accessible +... +LL | pub struct B { + | - this struct is accessible through auto-deref +LL | pub field: bool, + | ----- this is the field that was accessed +... +LL | impl std::ops::Deref for A { + | -------------------------- the field was accessed through this `Deref` + +error[E0369]: cannot add `{integer}` to `bool` + --> $DIR/private-field-deref-confusion-issue-149546.rs:46:13 + | +LL | a.field + 5; + | ------- ^ - {integer} + | | + | bool + | +note: there is a field `field` on `A` with type `usize` but it is private; `field` from `B` was accessed through auto-deref instead + --> $DIR/private-field-deref-confusion-issue-149546.rs:7:16 + | +LL | pub struct A { + | ^ in this struct +LL | field: usize, + | ----- if this field wasn't private, it would be accessible +... +LL | pub struct B { + | - this struct is accessible through auto-deref +LL | pub field: bool, + | ----- this is the field that was accessed +... +LL | impl std::ops::Deref for A { + | -------------------------- the field was accessed through this `Deref` + +error[E0277]: cannot add `bool` to `{integer}` + --> $DIR/private-field-deref-confusion-issue-149546.rs:50:7 + | +LL | 5 + a.field; + | ^ no implementation for `{integer} + bool` + | + = help: the trait `Add` is not implemented for `{integer}` +note: there is a field `field` on `A` with type `usize` but it is private; `field` from `B` was accessed through auto-deref instead + --> $DIR/private-field-deref-confusion-issue-149546.rs:7:16 + | +LL | pub struct A { + | ^ in this struct +LL | field: usize, + | ----- if this field wasn't private, it would be accessible +... +LL | pub struct B { + | - this struct is accessible through auto-deref +LL | pub field: bool, + | ----- this is the field that was accessed +... +LL | impl std::ops::Deref for A { + | -------------------------- the field was accessed through this `Deref` + = help: the following other types implement trait `Add`: + `&f128` implements `Add` + `&f128` implements `Add` + `&f16` implements `Add` + `&f16` implements `Add` + `&f32` implements `Add` + `&f32` implements `Add` + `&f64` implements `Add` + `&f64` implements `Add` + and 56 others + +error[E0277]: cannot add `bool` to `{integer}` + --> $DIR/private-field-deref-confusion-issue-149546.rs:54:7 + | +LL | 5 + a.field; + | ^ no implementation for `{integer} + bool` + | + = help: the trait `Add` is not implemented for `{integer}` +note: there is a field `field` on `A` with type `usize` but it is private; `field` from `B` was accessed through auto-deref instead + --> $DIR/private-field-deref-confusion-issue-149546.rs:7:16 + | +LL | pub struct A { + | ^ in this struct +LL | field: usize, + | ----- if this field wasn't private, it would be accessible +... +LL | pub struct B { + | - this struct is accessible through auto-deref +LL | pub field: bool, + | ----- this is the field that was accessed +... +LL | impl std::ops::Deref for A { + | -------------------------- the field was accessed through this `Deref` + = help: the following other types implement trait `Add`: + `&f128` implements `Add` + `&f128` implements `Add` + `&f16` implements `Add` + `&f16` implements `Add` + `&f32` implements `Add` + `&f32` implements `Add` + `&f64` implements `Add` + `&f64` implements `Add` + and 56 others + +error[E0277]: cannot add-assign `bool` to `{integer}` + --> $DIR/private-field-deref-confusion-issue-149546.rs:59:7 + | +LL | n += a.field; + | ^^ no implementation for `{integer} += bool` + | + = help: the trait `AddAssign` is not implemented for `{integer}` +note: there is a field `field` on `A` with type `usize` but it is private; `field` from `B` was accessed through auto-deref instead + --> $DIR/private-field-deref-confusion-issue-149546.rs:7:16 + | +LL | pub struct A { + | ^ in this struct +LL | field: usize, + | ----- if this field wasn't private, it would be accessible +... +LL | pub struct B { + | - this struct is accessible through auto-deref +LL | pub field: bool, + | ----- this is the field that was accessed +... +LL | impl std::ops::Deref for A { + | -------------------------- the field was accessed through this `Deref` + = help: the following other types implement trait `AddAssign`: + `f128` implements `AddAssign<&f128>` + `f128` implements `AddAssign` + `f16` implements `AddAssign<&f16>` + `f16` implements `AddAssign` + `f32` implements `AddAssign<&f32>` + `f32` implements `AddAssign` + `f64` implements `AddAssign<&f64>` + `f64` implements `AddAssign` + and 24 others + +error[E0277]: cannot add-assign `bool` to `{integer}` + --> $DIR/private-field-deref-confusion-issue-149546.rs:64:7 + | +LL | n += a.field; + | ^^ no implementation for `{integer} += bool` + | + = help: the trait `AddAssign` is not implemented for `{integer}` +note: there is a field `field` on `A` with type `usize` but it is private; `field` from `B` was accessed through auto-deref instead + --> $DIR/private-field-deref-confusion-issue-149546.rs:7:16 + | +LL | pub struct A { + | ^ in this struct +LL | field: usize, + | ----- if this field wasn't private, it would be accessible +... +LL | pub struct B { + | - this struct is accessible through auto-deref +LL | pub field: bool, + | ----- this is the field that was accessed +... +LL | impl std::ops::Deref for A { + | -------------------------- the field was accessed through this `Deref` + = help: the following other types implement trait `AddAssign`: + `f128` implements `AddAssign<&f128>` + `f128` implements `AddAssign` + `f16` implements `AddAssign<&f16>` + `f16` implements `AddAssign` + `f32` implements `AddAssign<&f32>` + `f32` implements `AddAssign` + `f64` implements `AddAssign<&f64>` + `f64` implements `AddAssign` + and 24 others + +error[E0277]: the trait bound `bool: Marker` is not satisfied + --> $DIR/private-field-deref-confusion-issue-149546.rs:68:16 + | +LL | Wrapper(5) + a.field; + | ^ the trait `Marker` is not implemented for `bool` + | +note: there is a field `field` on `A` with type `usize` but it is private; `field` from `B` was accessed through auto-deref instead + --> $DIR/private-field-deref-confusion-issue-149546.rs:7:16 + | +LL | pub struct A { + | ^ in this struct +LL | field: usize, + | ----- if this field wasn't private, it would be accessible +... +LL | pub struct B { + | - this struct is accessible through auto-deref +LL | pub field: bool, + | ----- this is the field that was accessed +... +LL | impl std::ops::Deref for A { + | -------------------------- the field was accessed through this `Deref` +help: the trait `Marker` is implemented for `usize` + --> $DIR/private-field-deref-confusion-issue-149546.rs:31:1 + | +LL | impl Marker for usize {} + | ^^^^^^^^^^^^^^^^^^^^^ +note: required for `Wrapper` to implement `Add` + --> $DIR/private-field-deref-confusion-issue-149546.rs:35:17 + | +LL | impl std::ops::Add for Wrapper { + | ------ ^^^^^^^^^^^^^^^^ ^^^^^^^ + | | + | unsatisfied trait bound introduced here + +error[E0599]: no method named `count_ones` found for type `bool` in the current scope + --> $DIR/private-field-deref-confusion-issue-149546.rs:72:13 + | +LL | a.field.count_ones(); + | ^^^^^^^^^^ method not found in `bool` + | +note: there is a field `field` on `A` with type `usize` but it is private; `field` from `B` was accessed through auto-deref instead + --> $DIR/private-field-deref-confusion-issue-149546.rs:7:16 + | +LL | pub struct A { + | ^ in this struct +LL | field: usize, + | ----- if this field wasn't private, it would be accessible +... +LL | pub struct B { + | - this struct is accessible through auto-deref +LL | pub field: bool, + | ----- this is the field that was accessed +... +LL | impl std::ops::Deref for A { + | -------------------------- the field was accessed through this `Deref` + +error[E0308]: mismatched types + --> $DIR/private-field-deref-confusion-issue-149546.rs:76:24 + | +LL | let value: usize = a.field; + | ----- ^^^^^^^ expected `usize`, found `bool` + | | + | expected due to this + | +note: there is a field `field` on `A` with type `usize` but it is private; `field` from `B` was accessed through auto-deref instead + --> $DIR/private-field-deref-confusion-issue-149546.rs:7:16 + | +LL | pub struct A { + | ^ in this struct +LL | field: usize, + | ----- if this field wasn't private, it would be accessible +... +LL | pub struct B { + | - this struct is accessible through auto-deref +LL | pub field: bool, + | ----- this is the field that was accessed +... +LL | impl std::ops::Deref for A { + | -------------------------- the field was accessed through this `Deref` + +error[E0308]: mismatched types + --> $DIR/private-field-deref-confusion-issue-149546.rs:81:17 + | +LL | takes_usize(a.field); + | ----------- ^^^^^^^ expected `usize`, found `bool` + | | + | arguments to this function are incorrect + | +note: there is a field `field` on `A` with type `usize` but it is private; `field` from `B` was accessed through auto-deref instead + --> $DIR/private-field-deref-confusion-issue-149546.rs:7:16 + | +LL | pub struct A { + | ^ in this struct +LL | field: usize, + | ----- if this field wasn't private, it would be accessible +... +LL | pub struct B { + | - this struct is accessible through auto-deref +LL | pub field: bool, + | ----- this is the field that was accessed +... +LL | impl std::ops::Deref for A { + | -------------------------- the field was accessed through this `Deref` +note: function defined here + --> $DIR/private-field-deref-confusion-issue-149546.rs:27:4 + | +LL | fn takes_usize(_: usize) {} + | ^^^^^^^^^^^ -------- + +error[E0308]: mismatched types + --> $DIR/private-field-deref-confusion-issue-149546.rs:85:5 + | +LL | fn return_value(a: &A) -> usize { + | ----- expected `usize` because of return type +LL | a.field + | ^^^^^^^ expected `usize`, found `bool` + | +note: there is a field `field` on `A` with type `usize` but it is private; `field` from `B` was accessed through auto-deref instead + --> $DIR/private-field-deref-confusion-issue-149546.rs:7:16 + | +LL | pub struct A { + | ^ in this struct +LL | field: usize, + | ----- if this field wasn't private, it would be accessible +... +LL | pub struct B { + | - this struct is accessible through auto-deref +LL | pub field: bool, + | ----- this is the field that was accessed +... +LL | impl std::ops::Deref for A { + | -------------------------- the field was accessed through this `Deref` + +error: aborting due to 11 previous errors + +Some errors have detailed explanations: E0277, E0308, E0369, E0599. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/scalable-vectors/cast-intrinsic.rs b/tests/ui/scalable-vectors/cast-intrinsic.rs new file mode 100644 index 0000000000000..f2157d8bcc14b --- /dev/null +++ b/tests/ui/scalable-vectors/cast-intrinsic.rs @@ -0,0 +1,65 @@ +//@ check-pass +//@ only-aarch64 +#![crate_type = "lib"] +#![allow(incomplete_features, internal_features, improper_ctypes)] +#![feature(abi_unadjusted, core_intrinsics, link_llvm_intrinsics, rustc_attrs)] + +use std::intrinsics::simd::scalable::sve_cast; + +#[derive(Copy, Clone)] +#[rustc_scalable_vector(16)] +#[allow(non_camel_case_types)] +pub struct svbool_t(bool); + +#[derive(Copy, Clone)] +#[rustc_scalable_vector(2)] +#[allow(non_camel_case_types)] +pub struct svbool2_t(bool); + +#[derive(Copy, Clone)] +#[rustc_scalable_vector(2)] +#[allow(non_camel_case_types)] +pub struct svint64_t(i64); + +#[derive(Copy, Clone)] +#[rustc_scalable_vector(2)] +#[allow(non_camel_case_types)] +pub struct nxv2i16(i16); + +pub trait SveInto: Sized { + unsafe fn sve_into(self) -> T; +} + +impl SveInto for svbool_t { + #[target_feature(enable = "sve")] + unsafe fn sve_into(self) -> svbool2_t { + unsafe extern "C" { + #[cfg_attr( + target_arch = "aarch64", + link_name = concat!("llvm.aarch64.sve.convert.from.svbool.nxv2i1") + )] + fn convert_from_svbool(b: svbool_t) -> svbool2_t; + } + unsafe { convert_from_svbool(self) } + } +} + +#[target_feature(enable = "sve")] +pub unsafe fn svld1sh_gather_s64offset_s64( + pg: svbool_t, + base: *const i16, + offsets: svint64_t, +) -> svint64_t { + unsafe extern "unadjusted" { + #[cfg_attr( + target_arch = "aarch64", + link_name = "llvm.aarch64.sve.ld1.gather.nxv2i16" + )] + fn _svld1sh_gather_s64offset_s64( + pg: svbool2_t, + base: *const i16, + offsets: svint64_t, + ) -> nxv2i16; + } + sve_cast(_svld1sh_gather_s64offset_s64(pg.sve_into(), base, offsets)) +} diff --git a/tests/ui/simd/masked-load-store-check-fail.stderr b/tests/ui/simd/masked-load-store-check-fail.stderr index 4e63d04a3b158..037855c8ec9ca 100644 --- a/tests/ui/simd/masked-load-store-check-fail.stderr +++ b/tests/ui/simd/masked-load-store-check-fail.stderr @@ -21,7 +21,7 @@ LL | | Simd::([9; 4]), LL | | ); | |_________^ note: function defined here - --> $SRC_DIR/core/src/intrinsics/simd.rs:LL:COL + --> $SRC_DIR/core/src/intrinsics/simd/mod.rs:LL:COL error[E0308]: mismatched types --> $DIR/masked-load-store-check-fail.rs:25:13 @@ -46,7 +46,7 @@ LL | | default, LL | | ); | |_________^ note: function defined here - --> $SRC_DIR/core/src/intrinsics/simd.rs:LL:COL + --> $SRC_DIR/core/src/intrinsics/simd/mod.rs:LL:COL error: aborting due to 2 previous errors diff --git a/tests/ui/typeck/index-out-of-bounds-on-partial-cmp-ice-114056.rs b/tests/ui/typeck/index-out-of-bounds-on-partial-cmp-ice-114056.rs new file mode 100644 index 0000000000000..73230055908d1 --- /dev/null +++ b/tests/ui/typeck/index-out-of-bounds-on-partial-cmp-ice-114056.rs @@ -0,0 +1,12 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/114056 + +struct P(Q); + +impl P { + fn foo(&self) { + self.partial_cmp(()) + //~^ ERROR the method `partial_cmp` exists for reference `&P`, but its trait bounds were not satisfied + } +} + +fn main() {} diff --git a/tests/ui/typeck/index-out-of-bounds-on-partial-cmp-ice-114056.stderr b/tests/ui/typeck/index-out-of-bounds-on-partial-cmp-ice-114056.stderr new file mode 100644 index 0000000000000..47e0d2d90357a --- /dev/null +++ b/tests/ui/typeck/index-out-of-bounds-on-partial-cmp-ice-114056.stderr @@ -0,0 +1,27 @@ +error[E0599]: the method `partial_cmp` exists for reference `&P`, but its trait bounds were not satisfied + --> $DIR/index-out-of-bounds-on-partial-cmp-ice-114056.rs:7:14 + | +LL | struct P(Q); + | ----------- doesn't satisfy `P: Iterator` or `P: PartialOrd<_>` +... +LL | self.partial_cmp(()) + | ^^^^^^^^^^^ method cannot be called on `&P` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `P: PartialOrd<_>` + which is required by `&P: PartialOrd<&_>` + `&P: Iterator` + which is required by `&mut &P: Iterator` + `P: Iterator` + which is required by `&mut P: Iterator` +note: the trait `Iterator` must be implemented + --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL +help: consider annotating `P` with `#[derive(PartialEq, PartialOrd)]` + | +LL + #[derive(PartialEq, PartialOrd)] +LL | struct P(Q); + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/triagebot.toml b/triagebot.toml index f99d700310dfe..719fe2a75c82b 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1077,7 +1077,7 @@ cc = ["@Amanieu", "@folkertdev", "@sayantn"] message = "Some changes occurred in `std_detect`" cc = ["@Amanieu", "@folkertdev", "@sayantn"] -[mentions."library/core/src/intrinsics/simd.rs"] +[mentions."library/core/src/intrinsics/simd/mod.rs"] message = """ Some changes occurred to the platform-builtins intrinsics. Make sure the LLVM backend as well as portable-simd gets adapted for the changes.