diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs
index 4611de4445997..00edafecd9a88 100644
--- a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs
@@ -1,40 +1,4 @@
-use std::num::IntErrorKind;
-
-use rustc_hir::limit::Limit;
-
use super::prelude::*;
-use crate::session_diagnostics::LimitInvalid;
-
-impl AcceptContext<'_, '_, S> {
- fn parse_limit_int(&self, nv: &NameValueParser) -> Option {
- let Some(limit) = nv.value_as_str() else {
- self.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
- return None;
- };
-
- let error_str = match limit.as_str().parse() {
- Ok(i) => return Some(Limit::new(i)),
- Err(e) => match e.kind() {
- IntErrorKind::PosOverflow => "`limit` is too large",
- IntErrorKind::Empty => "`limit` must be a non-negative integer",
- IntErrorKind::InvalidDigit => "not a valid integer",
- IntErrorKind::NegOverflow => {
- panic!(
- "`limit` should never negatively overflow since we're parsing into a usize and we'd get Empty instead"
- )
- }
- IntErrorKind::Zero => {
- panic!("zero is a valid `limit` so should have returned Ok() when parsing")
- }
- kind => panic!("unimplemented IntErrorKind variant: {:?}", kind),
- },
- };
-
- self.emit_err(LimitInvalid { span: self.attr_span, value_span: nv.value_span, error_str });
-
- None
- }
-}
pub(crate) struct CrateNameParser;
diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
index a995549fc7c83..cf2f5c6c79024 100644
--- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
@@ -49,3 +49,21 @@ impl SingleAttributeParser for RustcObjectLifetimeDefaultParser {
Some(AttributeKind::RustcObjectLifetimeDefault)
}
}
+
+pub(crate) struct RustcSimdMonomorphizeLaneLimitParser;
+
+impl SingleAttributeParser for RustcSimdMonomorphizeLaneLimitParser {
+ const PATH: &[Symbol] = &[sym::rustc_simd_monomorphize_lane_limit];
+ const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
+ const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
+ const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
+ const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
+
+ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option {
+ let ArgParser::NameValue(nv) = args else {
+ cx.expected_name_value(cx.attr_span, None);
+ return None;
+ };
+ Some(AttributeKind::RustcSimdMonomorphizeLaneLimit(cx.parse_limit_int(nv)?))
+ }
+}
diff --git a/compiler/rustc_attr_parsing/src/attributes/util.rs b/compiler/rustc_attr_parsing/src/attributes/util.rs
index 77e8c32e59d73..62b72798e9699 100644
--- a/compiler/rustc_attr_parsing/src/attributes/util.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/util.rs
@@ -1,11 +1,15 @@
+use std::num::IntErrorKind;
+
use rustc_ast::LitKind;
use rustc_ast::attr::AttributeExt;
use rustc_feature::is_builtin_attr_name;
use rustc_hir::RustcVersion;
+use rustc_hir::limit::Limit;
use rustc_span::{Symbol, sym};
use crate::context::{AcceptContext, Stage};
-use crate::parser::ArgParser;
+use crate::parser::{ArgParser, NameValueParser};
+use crate::session_diagnostics::LimitInvalid;
/// Parse a rustc version number written inside string literal in an attribute,
/// like appears in `since = "1.0.0"`. Suffixes like "-dev" and "-nightly" are
@@ -85,3 +89,34 @@ pub(crate) fn parse_single_integer(
};
Some(num.0)
}
+
+impl AcceptContext<'_, '_, S> {
+ pub(crate) fn parse_limit_int(&self, nv: &NameValueParser) -> Option {
+ let Some(limit) = nv.value_as_str() else {
+ self.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
+ return None;
+ };
+
+ let error_str = match limit.as_str().parse() {
+ Ok(i) => return Some(Limit::new(i)),
+ Err(e) => match e.kind() {
+ IntErrorKind::PosOverflow => "`limit` is too large",
+ IntErrorKind::Empty => "`limit` must be a non-negative integer",
+ IntErrorKind::InvalidDigit => "not a valid integer",
+ IntErrorKind::NegOverflow => {
+ panic!(
+ "`limit` should never negatively overflow since we're parsing into a usize and we'd get Empty instead"
+ )
+ }
+ IntErrorKind::Zero => {
+ panic!("zero is a valid `limit` so should have returned Ok() when parsing")
+ }
+ kind => panic!("unimplemented IntErrorKind variant: {:?}", kind),
+ },
+ };
+
+ self.emit_err(LimitInvalid { span: self.attr_span, value_span: nv.value_span, error_str });
+
+ None
+ }
+}
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index d7998048be5af..72fe269b135a7 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -53,7 +53,7 @@ use crate::attributes::prototype::CustomMirParser;
use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser};
use crate::attributes::rustc_internal::{
RustcLayoutScalarValidRangeEnd, RustcLayoutScalarValidRangeStart,
- RustcObjectLifetimeDefaultParser,
+ RustcObjectLifetimeDefaultParser, RustcSimdMonomorphizeLaneLimitParser,
};
use crate::attributes::semantics::MayDangleParser;
use crate::attributes::stability::{
@@ -195,6 +195,7 @@ attribute_parsers!(
Single,
Single,
Single,
+ Single,
Single,
Single,
Single,
diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs
index 2fbe5c02802ab..81b1814605a12 100644
--- a/compiler/rustc_codegen_cranelift/src/common.rs
+++ b/compiler/rustc_codegen_cranelift/src/common.rs
@@ -439,7 +439,10 @@ pub(crate) struct FullyMonomorphizedLayoutCx<'tcx>(pub(crate) TyCtxt<'tcx>);
impl<'tcx> LayoutOfHelpers<'tcx> for FullyMonomorphizedLayoutCx<'tcx> {
#[inline]
fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
- if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err {
+ if let LayoutError::SizeOverflow(_)
+ | LayoutError::InvalidSimd { .. }
+ | LayoutError::ReferencesError(_) = err
+ {
self.0.sess.dcx().span_fatal(span, err.to_string())
} else {
self.0
@@ -458,7 +461,9 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for FullyMonomorphizedLayoutCx<'tcx> {
span: Span,
fn_abi_request: FnAbiRequest<'tcx>,
) -> ! {
- if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err {
+ if let FnAbiError::Layout(LayoutError::SizeOverflow(_) | LayoutError::InvalidSimd { .. }) =
+ err
+ {
self.0.sess.dcx().emit_fatal(Spanned { span, node: err })
} else {
match fn_abi_request {
diff --git a/compiler/rustc_codegen_cranelift/src/global_asm.rs b/compiler/rustc_codegen_cranelift/src/global_asm.rs
index 203b443269fa7..1306c6aa5179c 100644
--- a/compiler/rustc_codegen_cranelift/src/global_asm.rs
+++ b/compiler/rustc_codegen_cranelift/src/global_asm.rs
@@ -42,7 +42,10 @@ impl<'tcx> AsmCodegenMethods<'tcx> for GlobalAsmContext<'_, 'tcx> {
impl<'tcx> LayoutOfHelpers<'tcx> for GlobalAsmContext<'_, 'tcx> {
#[inline]
fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
- if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err {
+ if let LayoutError::SizeOverflow(_)
+ | LayoutError::InvalidSimd { .. }
+ | LayoutError::ReferencesError(_) = err
+ {
self.tcx.sess.dcx().span_fatal(span, err.to_string())
} else {
self.tcx
diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs
index 665cf22ddbaee..9815fb07eaae9 100644
--- a/compiler/rustc_codegen_gcc/src/context.rs
+++ b/compiler/rustc_codegen_gcc/src/context.rs
@@ -529,7 +529,10 @@ impl<'gcc, 'tcx> HasX86AbiOpt for CodegenCx<'gcc, 'tcx> {
impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
#[inline]
fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
- if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err {
+ if let LayoutError::SizeOverflow(_)
+ | LayoutError::InvalidSimd { .. }
+ | LayoutError::ReferencesError(_) = err
+ {
self.tcx.dcx().emit_fatal(respan(span, err.into_diagnostic()))
} else {
self.tcx.dcx().emit_fatal(ssa_errors::FailedToGetLayout { span, ty, err })
@@ -545,7 +548,9 @@ impl<'gcc, 'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
span: Span,
fn_abi_request: FnAbiRequest<'tcx>,
) -> ! {
- if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err {
+ if let FnAbiError::Layout(LayoutError::SizeOverflow(_) | LayoutError::InvalidSimd { .. }) =
+ err
+ {
self.tcx.dcx().emit_fatal(respan(span, err))
} else {
match fn_abi_request {
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index a69fa54a54a4d..e4528efaa37b1 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -991,7 +991,10 @@ impl<'tcx, 'll> HasTypingEnv<'tcx> for CodegenCx<'ll, 'tcx> {
impl<'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'_, 'tcx> {
#[inline]
fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
- if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err {
+ if let LayoutError::SizeOverflow(_)
+ | LayoutError::ReferencesError(_)
+ | LayoutError::InvalidSimd { .. } = err
+ {
self.tcx.dcx().emit_fatal(Spanned { span, node: err.into_diagnostic() })
} else {
self.tcx.dcx().emit_fatal(ssa_errors::FailedToGetLayout { span, ty, err })
@@ -1008,7 +1011,11 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'_, 'tcx> {
fn_abi_request: FnAbiRequest<'tcx>,
) -> ! {
match err {
- FnAbiError::Layout(LayoutError::SizeOverflow(_) | LayoutError::Cycle(_)) => {
+ FnAbiError::Layout(
+ LayoutError::SizeOverflow(_)
+ | LayoutError::Cycle(_)
+ | LayoutError::InvalidSimd { .. },
+ ) => {
self.tcx.dcx().emit_fatal(Spanned { span, node: err });
}
_ => match fn_abi_request {
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index dc3a84b6a151a..7ecba13d7274c 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -469,8 +469,8 @@ pub(crate) fn spanned_type_di_node<'ll, 'tcx>(
ty::CoroutineClosure(..) => build_closure_env_di_node(cx, unique_type_id),
ty::Coroutine(..) => enums::build_coroutine_di_node(cx, unique_type_id),
ty::Adt(def, ..) => match def.adt_kind() {
- AdtKind::Struct => build_struct_type_di_node(cx, unique_type_id),
- AdtKind::Union => build_union_type_di_node(cx, unique_type_id),
+ AdtKind::Struct => build_struct_type_di_node(cx, unique_type_id, span),
+ AdtKind::Union => build_union_type_di_node(cx, unique_type_id, span),
AdtKind::Enum => enums::build_enum_type_di_node(cx, unique_type_id, span),
},
ty::Tuple(_) => build_tuple_type_di_node(cx, unique_type_id),
@@ -1066,6 +1066,7 @@ fn visibility_di_flags<'ll, 'tcx>(
fn build_struct_type_di_node<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
unique_type_id: UniqueTypeId<'tcx>,
+ span: Span,
) -> DINodeCreationResult<'ll> {
let struct_type = unique_type_id.expect_ty();
let ty::Adt(adt_def, _) = struct_type.kind() else {
@@ -1073,7 +1074,7 @@ fn build_struct_type_di_node<'ll, 'tcx>(
};
assert!(adt_def.is_struct());
let containing_scope = get_namespace_for_item(cx, adt_def.did());
- let struct_type_and_layout = cx.layout_of(struct_type);
+ let struct_type_and_layout = cx.spanned_layout_of(struct_type, span);
let variant_def = adt_def.non_enum_variant();
let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
Some(file_metadata_from_def_id(cx, Some(adt_def.did())))
@@ -1266,6 +1267,7 @@ fn build_closure_env_di_node<'ll, 'tcx>(
fn build_union_type_di_node<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
unique_type_id: UniqueTypeId<'tcx>,
+ span: Span,
) -> DINodeCreationResult<'ll> {
let union_type = unique_type_id.expect_ty();
let (union_def_id, variant_def) = match union_type.kind() {
@@ -1273,7 +1275,7 @@ fn build_union_type_di_node<'ll, 'tcx>(
_ => bug!("build_union_type_di_node on a non-ADT"),
};
let containing_scope = get_namespace_for_item(cx, union_def_id);
- let union_ty_and_layout = cx.layout_of(union_type);
+ let union_ty_and_layout = cx.spanned_layout_of(union_type, span);
let type_name = compute_debuginfo_type_name(cx.tcx, union_type, false);
let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
Some(file_metadata_from_def_id(cx, Some(union_def_id)))
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 129ab7eccb577..0d890b57de0d6 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -1203,6 +1203,12 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
"the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable \
niche optimizations in the standard library",
),
+ rustc_attr!(
+ rustc_simd_monomorphize_lane_limit, Normal, template!(NameValueStr: "N"), ErrorFollowing,
+ EncodeCrossCrate::Yes,
+ "the `#[rustc_simd_monomorphize_lane_limit]` attribute is just used by std::simd \
+ for better error messages",
+ ),
rustc_attr!(
rustc_nonnull_optimization_guaranteed, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::Yes,
diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs
index ea11a99efbc35..80cb641768471 100644
--- a/compiler/rustc_hir/src/attrs/data_structures.rs
+++ b/compiler/rustc_hir/src/attrs/data_structures.rs
@@ -642,6 +642,9 @@ pub enum AttributeKind {
/// Represents `#[rustc_object_lifetime_default]`.
RustcObjectLifetimeDefault,
+ /// Represents `#[rustc_simd_monomorphize_lane_limit = "N"]`.
+ RustcSimdMonomorphizeLaneLimit(Limit),
+
/// Represents `#[sanitize]`
///
/// the on set and off set are distjoint since there's a third option: unset.
diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
index 55521c1585402..968ea668efea1 100644
--- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
+++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
@@ -85,6 +85,7 @@ impl AttributeKind {
RustcLayoutScalarValidRangeEnd(..) => Yes,
RustcLayoutScalarValidRangeStart(..) => Yes,
RustcObjectLifetimeDefault => No,
+ RustcSimdMonomorphizeLaneLimit(..) => Yes, // Affects layout computation, which needs to work cross-crate
Sanitize { .. } => No,
ShouldPanic { .. } => No,
SkipDuringMethodDispatch { .. } => No,
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
index 5088c63702e60..76b0ce985f0ca 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
@@ -213,6 +213,7 @@ fn should_emit_generic_error<'tcx>(abi: ExternAbi, layout_err: &'tcx LayoutError
}
Unknown(..)
| SizeOverflow(..)
+ | InvalidSimd { .. }
| NormalizationFailure(..)
| ReferencesError(..)
| Cycle(..) => {
diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl
index 279ab9a9d8fbe..82f3df8da3b12 100644
--- a/compiler/rustc_middle/messages.ftl
+++ b/compiler/rustc_middle/messages.ftl
@@ -98,6 +98,12 @@ middle_layout_references_error =
middle_layout_size_overflow =
values of the type `{$ty}` are too big for the target architecture
+middle_layout_simd_too_many =
+ the SIMD type `{$ty}` has more elements than the limit {$max_lanes}
+
+middle_layout_simd_zero_length =
+ the SIMD type `{$ty}` has zero elements
+
middle_layout_too_generic = the type `{$ty}` does not have a fixed layout
middle_layout_unknown =
diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs
index dad402ec69616..e15da827bda9b 100644
--- a/compiler/rustc_middle/src/error.rs
+++ b/compiler/rustc_middle/src/error.rs
@@ -141,6 +141,12 @@ pub enum LayoutError<'tcx> {
#[diag(middle_layout_size_overflow)]
Overflow { ty: Ty<'tcx> },
+ #[diag(middle_layout_simd_too_many)]
+ SimdTooManyLanes { ty: Ty<'tcx>, max_lanes: u64 },
+
+ #[diag(middle_layout_simd_zero_length)]
+ SimdZeroLength { ty: Ty<'tcx> },
+
#[diag(middle_layout_normalization_failure)]
NormalizationFailure { ty: Ty<'tcx>, failure_ty: String },
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 2114d080dfa43..47e561d9d3ce8 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -217,6 +217,15 @@ impl fmt::Display for ValidityRequirement {
}
}
+#[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)]
+pub enum SimdLayoutError {
+ /// The vector has 0 lanes.
+ ZeroLength,
+ /// The vector has more lanes than supported or permitted by
+ /// #\[rustc_simd_monomorphize_lane_limit\].
+ TooManyLanes(u64),
+}
+
#[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)]
pub enum LayoutError<'tcx> {
/// A type doesn't have a sensible layout.
@@ -229,6 +238,8 @@ pub enum LayoutError<'tcx> {
Unknown(Ty<'tcx>),
/// The size of a type exceeds [`TargetDataLayout::obj_size_bound`].
SizeOverflow(Ty<'tcx>),
+ /// A SIMD vector has invalid layout, such as zero-length or too many lanes.
+ InvalidSimd { ty: Ty<'tcx>, kind: SimdLayoutError },
/// The layout can vary due to a generic parameter.
///
/// Unlike `Unknown`, this variant is a "soft" error and indicates that the layout
@@ -256,6 +267,10 @@ impl<'tcx> LayoutError<'tcx> {
match self {
Unknown(_) => middle_layout_unknown,
SizeOverflow(_) => middle_layout_size_overflow,
+ InvalidSimd { kind: SimdLayoutError::TooManyLanes(_), .. } => {
+ middle_layout_simd_too_many
+ }
+ InvalidSimd { kind: SimdLayoutError::ZeroLength, .. } => middle_layout_simd_zero_length,
TooGeneric(_) => middle_layout_too_generic,
NormalizationFailure(_, _) => middle_layout_normalization_failure,
Cycle(_) => middle_layout_cycle,
@@ -270,6 +285,10 @@ impl<'tcx> LayoutError<'tcx> {
match self {
Unknown(ty) => E::Unknown { ty },
SizeOverflow(ty) => E::Overflow { ty },
+ InvalidSimd { ty, kind: SimdLayoutError::TooManyLanes(max_lanes) } => {
+ E::SimdTooManyLanes { ty, max_lanes }
+ }
+ InvalidSimd { ty, kind: SimdLayoutError::ZeroLength } => E::SimdZeroLength { ty },
TooGeneric(ty) => E::TooGeneric { ty },
NormalizationFailure(ty, e) => {
E::NormalizationFailure { ty, failure_ty: e.get_type_for_failure() }
@@ -292,6 +311,12 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
LayoutError::SizeOverflow(ty) => {
write!(f, "values of the type `{ty}` are too big for the target architecture")
}
+ LayoutError::InvalidSimd { ty, kind: SimdLayoutError::TooManyLanes(max_lanes) } => {
+ write!(f, "the SIMD type `{ty}` has more elements than the limit {max_lanes}")
+ }
+ LayoutError::InvalidSimd { ty, kind: SimdLayoutError::ZeroLength } => {
+ write!(f, "the SIMD type `{ty}` has zero elements")
+ }
LayoutError::NormalizationFailure(t, e) => write!(
f,
"unable to determine layout for `{}` because `{}` cannot be normalized",
@@ -373,6 +398,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
e @ LayoutError::Cycle(_)
| e @ LayoutError::Unknown(_)
| e @ LayoutError::SizeOverflow(_)
+ | e @ LayoutError::InvalidSimd { .. }
| e @ LayoutError::NormalizationFailure(..)
| e @ LayoutError::ReferencesError(_),
) => return Err(e),
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 2562d2e0b83c5..cabf28197413b 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -254,6 +254,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
| AttributeKind::MacroEscape( .. )
| AttributeKind::RustcLayoutScalarValidRangeStart(..)
| AttributeKind::RustcLayoutScalarValidRangeEnd(..)
+ | AttributeKind::RustcSimdMonomorphizeLaneLimit(..)
| AttributeKind::ExportStable
| AttributeKind::FfiConst(..)
| AttributeKind::UnstableFeatureBound(..)
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index cdb0b5b58da6d..92a1fad47552b 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1937,6 +1937,7 @@ symbols! {
rustc_regions,
rustc_reservation_impl,
rustc_serialize,
+ rustc_simd_monomorphize_lane_limit,
rustc_skip_during_method_dispatch,
rustc_specialization_trait,
rustc_std_internal_symbol,
diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs
index d7ea26a2ab1d0..a02e8ecf613f4 100644
--- a/compiler/rustc_transmute/src/layout/tree.rs
+++ b/compiler/rustc_transmute/src/layout/tree.rs
@@ -279,6 +279,7 @@ pub(crate) mod rustc {
LayoutError::Unknown(..)
| LayoutError::ReferencesError(..)
| LayoutError::TooGeneric(..)
+ | LayoutError::InvalidSimd { .. }
| LayoutError::NormalizationFailure(..) => Self::UnknownLayout,
LayoutError::SizeOverflow(..) => Self::SizeOverflow,
LayoutError::Cycle(err) => Self::TypeError(*err),
diff --git a/compiler/rustc_ty_utils/src/errors.rs b/compiler/rustc_ty_utils/src/errors.rs
index 0298e7e0e9511..f92c405242ce9 100644
--- a/compiler/rustc_ty_utils/src/errors.rs
+++ b/compiler/rustc_ty_utils/src/errors.rs
@@ -78,19 +78,6 @@ pub(crate) struct UnexpectedFnPtrAssociatedItem {
pub span: Span,
}
-#[derive(Diagnostic)]
-#[diag(ty_utils_zero_length_simd_type)]
-pub(crate) struct ZeroLengthSimdType<'tcx> {
- pub ty: Ty<'tcx>,
-}
-
-#[derive(Diagnostic)]
-#[diag(ty_utils_oversized_simd_type)]
-pub(crate) struct OversizedSimdType<'tcx> {
- pub ty: Ty<'tcx>,
- pub max_lanes: u64,
-}
-
#[derive(Diagnostic)]
#[diag(ty_utils_non_primitive_simd_type)]
pub(crate) struct NonPrimitiveSimdType<'tcx> {
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index 79f7e228e2adc..5c4451ce264f0 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -7,11 +7,13 @@ use rustc_abi::{
VariantIdx, Variants, WrappingRange,
};
use rustc_hashes::Hash64;
+use rustc_hir::attrs::AttributeKind;
+use rustc_hir::find_attr;
use rustc_index::IndexVec;
use rustc_middle::bug;
use rustc_middle::query::Providers;
use rustc_middle::ty::layout::{
- FloatExt, HasTyCtxt, IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout,
+ FloatExt, HasTyCtxt, IntegerExt, LayoutCx, LayoutError, LayoutOf, SimdLayoutError, TyAndLayout,
};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{
@@ -22,7 +24,7 @@ use rustc_span::{Symbol, sym};
use tracing::{debug, instrument};
use {rustc_abi as abi, rustc_hir as hir};
-use crate::errors::{NonPrimitiveSimdType, OversizedSimdType, ZeroLengthSimdType};
+use crate::errors::NonPrimitiveSimdType;
mod invariant;
@@ -120,11 +122,11 @@ fn map_error<'tcx>(
}
LayoutCalculatorError::ZeroLengthSimdType => {
// Can't be caught in typeck if the array length is generic.
- cx.tcx().dcx().emit_fatal(ZeroLengthSimdType { ty })
+ LayoutError::InvalidSimd { ty, kind: SimdLayoutError::ZeroLength }
}
LayoutCalculatorError::OversizedSimdType { max_lanes } => {
// Can't be caught in typeck if the array length is generic.
- cx.tcx().dcx().emit_fatal(OversizedSimdType { ty, max_lanes })
+ LayoutError::InvalidSimd { ty, kind: SimdLayoutError::TooManyLanes(max_lanes) }
}
LayoutCalculatorError::NonPrimitiveSimdType(field) => {
// This error isn't caught in typeck, e.g., if
@@ -561,6 +563,22 @@ fn layout_of_uncached<'tcx>(
let e_ly = cx.layout_of(e_ty)?;
+ // Check for the rustc_simd_monomorphize_lane_limit attribute and check the lane limit
+ if let Some(limit) = find_attr!(
+ tcx.get_all_attrs(def.did()),
+ AttributeKind::RustcSimdMonomorphizeLaneLimit(limit) => limit
+ ) {
+ if !limit.value_within_limit(e_len as usize) {
+ return Err(map_error(
+ &cx,
+ ty,
+ rustc_abi::LayoutCalculatorError::OversizedSimdType {
+ max_lanes: limit.0 as u64,
+ },
+ ));
+ }
+ }
+
map_layout(cx.calc.simd_type(e_ly, e_len, def.repr().packed()))?
}
diff --git a/src/librustdoc/html/templates/type_layout.html b/src/librustdoc/html/templates/type_layout.html
index 0034552bdd3b7..49153d58fe98c 100644
--- a/src/librustdoc/html/templates/type_layout.html
+++ b/src/librustdoc/html/templates/type_layout.html
@@ -65,5 +65,10 @@
+ {% when Err(LayoutError::InvalidSimd {..}) %}
+ {# #}
+ Note: Encountered an error during type layout; {#+ #}
+ the vector type had zero elements or too many elements. {# #}
+
{% endmatch %}
{# #}
diff --git a/tests/ui/simd/auxiliary/simd-lane-limit.rs b/tests/ui/simd/auxiliary/simd-lane-limit.rs
new file mode 100644
index 0000000000000..dde6b880c62ec
--- /dev/null
+++ b/tests/ui/simd/auxiliary/simd-lane-limit.rs
@@ -0,0 +1,5 @@
+#![feature(rustc_attrs, repr_simd)]
+
+#[repr(simd, packed)]
+#[rustc_simd_monomorphize_lane_limit = "8"]
+pub struct Simd(pub [T; N]);
diff --git a/tests/ui/simd/monomorphize-too-long.rs b/tests/ui/simd/monomorphize-too-long.rs
index 4fac987b0b5aa..9c83741519178 100644
--- a/tests/ui/simd/monomorphize-too-long.rs
+++ b/tests/ui/simd/monomorphize-too-long.rs
@@ -6,7 +6,5 @@
struct Simd([T; N]);
fn main() {
- let _too_big = Simd([1_u16; 54321]);
+ let _too_big = Simd([1_u16; 54321]); //~ ERROR the SIMD type `Simd` has more elements than the limit 32768
}
-
-//~? ERROR monomorphising SIMD type `Simd` of length greater than 32768
diff --git a/tests/ui/simd/monomorphize-too-long.stderr b/tests/ui/simd/monomorphize-too-long.stderr
index 978eef307abd1..71bc78ef5c955 100644
--- a/tests/ui/simd/monomorphize-too-long.stderr
+++ b/tests/ui/simd/monomorphize-too-long.stderr
@@ -1,4 +1,8 @@
-error: monomorphising SIMD type `Simd` of length greater than 32768
+error: the SIMD type `Simd` has more elements than the limit 32768
+ --> $DIR/monomorphize-too-long.rs:9:9
+ |
+LL | let _too_big = Simd([1_u16; 54321]);
+ | ^^^^^^^^
error: aborting due to 1 previous error
diff --git a/tests/ui/simd/monomorphize-zero-length.rs b/tests/ui/simd/monomorphize-zero-length.rs
index d38870c572d97..f956197a61cf0 100644
--- a/tests/ui/simd/monomorphize-zero-length.rs
+++ b/tests/ui/simd/monomorphize-zero-length.rs
@@ -6,7 +6,5 @@
struct Simd([T; N]);
fn main() {
- let _empty = Simd([1.0; 0]);
+ let _empty = Simd([1.0; 0]); //~ ERROR the SIMD type `Simd` has zero elements
}
-
-//~? ERROR monomorphising SIMD type `Simd` of zero length
diff --git a/tests/ui/simd/monomorphize-zero-length.stderr b/tests/ui/simd/monomorphize-zero-length.stderr
index 738c20fe51a46..66f26d95c9d97 100644
--- a/tests/ui/simd/monomorphize-zero-length.stderr
+++ b/tests/ui/simd/monomorphize-zero-length.stderr
@@ -1,4 +1,8 @@
-error: monomorphising SIMD type `Simd` of zero length
+error: the SIMD type `Simd` has zero elements
+ --> $DIR/monomorphize-zero-length.rs:9:9
+ |
+LL | let _empty = Simd([1.0; 0]);
+ | ^^^^^^
error: aborting due to 1 previous error
diff --git a/tests/ui/simd/simd-lane-limit-err-npow2.rs b/tests/ui/simd/simd-lane-limit-err-npow2.rs
new file mode 100644
index 0000000000000..d5c5c92e953db
--- /dev/null
+++ b/tests/ui/simd/simd-lane-limit-err-npow2.rs
@@ -0,0 +1,12 @@
+//@ build-fail
+//@ aux-crate:simd=simd-lane-limit.rs
+
+extern crate simd;
+
+use simd::Simd;
+
+fn main() {
+ // test non-power-of-two, since #[repr(simd, packed)] has unusual layout
+ let _x: Simd = Simd([0; 24]);
+ //~^ ERROR the SIMD type `simd::Simd` has more elements than the limit 8
+}
diff --git a/tests/ui/simd/simd-lane-limit-err-npow2.stderr b/tests/ui/simd/simd-lane-limit-err-npow2.stderr
new file mode 100644
index 0000000000000..fff26c4c1c1b0
--- /dev/null
+++ b/tests/ui/simd/simd-lane-limit-err-npow2.stderr
@@ -0,0 +1,8 @@
+error: the SIMD type `simd::Simd` has more elements than the limit 8
+ --> $DIR/simd-lane-limit-err-npow2.rs:10:9
+ |
+LL | let _x: Simd = Simd([0; 24]);
+ | ^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/simd/simd-lane-limit-err.rs b/tests/ui/simd/simd-lane-limit-err.rs
new file mode 100644
index 0000000000000..00390bdbdafac
--- /dev/null
+++ b/tests/ui/simd/simd-lane-limit-err.rs
@@ -0,0 +1,11 @@
+//@ build-fail
+//@ aux-crate:simd=simd-lane-limit.rs
+
+extern crate simd;
+
+use simd::Simd;
+
+fn main() {
+ let _x: Simd = Simd([0; 16]);
+ //~^ ERROR the SIMD type `simd::Simd` has more elements than the limit 8
+}
diff --git a/tests/ui/simd/simd-lane-limit-err.stderr b/tests/ui/simd/simd-lane-limit-err.stderr
new file mode 100644
index 0000000000000..3f2eaeda2d415
--- /dev/null
+++ b/tests/ui/simd/simd-lane-limit-err.stderr
@@ -0,0 +1,8 @@
+error: the SIMD type `simd::Simd` has more elements than the limit 8
+ --> $DIR/simd-lane-limit-err.rs:9:9
+ |
+LL | let _x: Simd = Simd([0; 16]);
+ | ^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/simd/simd-lane-limit-ok.rs b/tests/ui/simd/simd-lane-limit-ok.rs
new file mode 100644
index 0000000000000..52fd3158440ad
--- /dev/null
+++ b/tests/ui/simd/simd-lane-limit-ok.rs
@@ -0,0 +1,14 @@
+//@ build-pass
+//@ aux-crate:simd=simd-lane-limit.rs
+
+extern crate simd;
+
+use simd::Simd;
+
+fn main() {
+ let _x: Simd = Simd([0; 4]);
+ let _y: Simd = Simd([0; 8]);
+
+ // test non-power-of-two, since #[repr(simd, packed)] has unusual layout
+ let _z: Simd = Simd([0; 6]);
+}
diff --git a/tests/ui/simd/type-generic-monomorphisation-empty.rs b/tests/ui/simd/type-generic-monomorphisation-empty.rs
index c08dc9fe3df2f..7c43b8914da63 100644
--- a/tests/ui/simd/type-generic-monomorphisation-empty.rs
+++ b/tests/ui/simd/type-generic-monomorphisation-empty.rs
@@ -6,7 +6,5 @@
struct Simd([f32; N]);
fn main() {
- let _ = Simd::<0>([]);
+ let _empty = Simd::<0>([]); //~ ERROR the SIMD type `Simd<0>` has zero elements
}
-
-//~? ERROR monomorphising SIMD type `Simd<0>` of zero length
diff --git a/tests/ui/simd/type-generic-monomorphisation-empty.stderr b/tests/ui/simd/type-generic-monomorphisation-empty.stderr
index fc294607ae310..450db7e47db03 100644
--- a/tests/ui/simd/type-generic-monomorphisation-empty.stderr
+++ b/tests/ui/simd/type-generic-monomorphisation-empty.stderr
@@ -1,4 +1,8 @@
-error: monomorphising SIMD type `Simd<0>` of zero length
+error: the SIMD type `Simd<0>` has zero elements
+ --> $DIR/type-generic-monomorphisation-empty.rs:9:9
+ |
+LL | let _empty = Simd::<0>([]);
+ | ^^^^^^
error: aborting due to 1 previous error
diff --git a/tests/ui/simd/type-generic-monomorphisation-oversized.rs b/tests/ui/simd/type-generic-monomorphisation-oversized.rs
index efe3480317c9e..73a1f00e8c7f0 100644
--- a/tests/ui/simd/type-generic-monomorphisation-oversized.rs
+++ b/tests/ui/simd/type-generic-monomorphisation-oversized.rs
@@ -6,7 +6,6 @@
struct Simd([f32; N]);
fn main() {
- let _ = Simd::<65536>([0.; 65536]);
+ let _x = Simd::<65536>([0.; 65536]);
+ //~^ ERROR the SIMD type `Simd<65536>` has more elements than the limit 32768
}
-
-//~? ERROR monomorphising SIMD type `Simd<65536>` of length greater than 32768
diff --git a/tests/ui/simd/type-generic-monomorphisation-oversized.stderr b/tests/ui/simd/type-generic-monomorphisation-oversized.stderr
index 39ff36799cc92..0065049abd68d 100644
--- a/tests/ui/simd/type-generic-monomorphisation-oversized.stderr
+++ b/tests/ui/simd/type-generic-monomorphisation-oversized.stderr
@@ -1,4 +1,8 @@
-error: monomorphising SIMD type `Simd<65536>` of length greater than 32768
+error: the SIMD type `Simd<65536>` has more elements than the limit 32768
+ --> $DIR/type-generic-monomorphisation-oversized.rs:9:9
+ |
+LL | let _x = Simd::<65536>([0.; 65536]);
+ | ^^
error: aborting due to 1 previous error