diff --git a/Cargo.lock b/Cargo.lock index 7f627e2ce6ec1..dda540765c6f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3535,6 +3535,7 @@ dependencies = [ "either", "itertools", "polonius-engine", + "rustc_ast", "rustc_data_structures", "rustc_errors", "rustc_fluent_macro", diff --git a/compiler/rustc_borrowck/Cargo.toml b/compiler/rustc_borrowck/Cargo.toml index 714f46270f92c..53744626c8f7f 100644 --- a/compiler/rustc_borrowck/Cargo.toml +++ b/compiler/rustc_borrowck/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" either = "1.5.0" itertools = "0.11" polonius-engine = "0.13.0" +rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } diff --git a/compiler/rustc_borrowck/messages.ftl b/compiler/rustc_borrowck/messages.ftl index 8c5a1d8970922..a659821518b55 100644 --- a/compiler/rustc_borrowck/messages.ftl +++ b/compiler/rustc_borrowck/messages.ftl @@ -71,6 +71,8 @@ borrowck_higher_ranked_lifetime_error = borrowck_higher_ranked_subtype_error = higher-ranked subtype error +borrowck_intrinsic_const_vector_arg_non_const = argument at index {$index} must be a constant + borrowck_lifetime_constraints_error = lifetime may not live long enough diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs index e321b92603d38..bf9141d12696b 100644 --- a/compiler/rustc_borrowck/src/session_diagnostics.rs +++ b/compiler/rustc_borrowck/src/session_diagnostics.rs @@ -459,3 +459,11 @@ pub(crate) struct SimdShuffleLastConst { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(borrowck_intrinsic_const_vector_arg_non_const)] +pub(crate) struct IntrinsicConstVectorArgNonConst { + #[primary_span] + pub span: Span, + pub index: u128, +} diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index ecc9905e33e85..1c59708d22207 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -50,7 +50,9 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::MoveData; use rustc_mir_dataflow::ResultsCursor; -use crate::session_diagnostics::{MoveUnsized, SimdShuffleLastConst}; +use crate::session_diagnostics::{ + IntrinsicConstVectorArgNonConst, MoveUnsized, SimdShuffleLastConst, +}; use crate::{ borrow_set::BorrowSet, constraints::{OutlivesConstraint, OutlivesConstraintSet}, @@ -1580,6 +1582,35 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } _ => {} } + } else if let Some(attr) = + self.tcx().get_attr(def_id, sym::rustc_intrinsic_const_vector_arg) + { + match attr.meta_item_list() { + Some(items) => { + items.into_iter().for_each(|item: rustc_ast::NestedMetaItem| match item { + rustc_ast::NestedMetaItem::Lit(rustc_ast::MetaItemLit { + kind: rustc_ast::LitKind::Int(index, _), + .. + }) => { + if index >= args.len() as u128 { + span_mirbug!(self, term, "index out of bounds"); + } else { + if !matches!(args[index as usize], Operand::Constant(_)) { + self.tcx().sess.emit_err(IntrinsicConstVectorArgNonConst { + span: term.source_info.span, + index, + }); + } + } + } + _ => { + span_mirbug!(self, term, "invalid index"); + } + }); + } + // Error is reported by `rustc_attr!` + None => (), + } } } debug!(?func_ty); diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index 93fe27e547aef..54269dd79ebcc 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -159,6 +159,11 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { self.context.new_struct_constructor(None, struct_type.as_type(), None, values) } + fn const_vector(&self, values: &[RValue<'gcc>]) -> RValue<'gcc> { + let typ = self.type_vector(values[0].get_type(), values.len() as u64); + self.context.new_rvalue_from_vector(None, typ, values) + } + fn const_to_opt_uint(&self, _v: RValue<'gcc>) -> Option { // TODO(antoyo) None diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index d1b643f49677a..c1c7d2f5bb5f9 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -98,10 +98,6 @@ impl<'ll> CodegenCx<'ll, '_> { unsafe { llvm::LLVMConstArray(ty, elts.as_ptr(), elts.len() as c_uint) } } - pub fn const_vector(&self, elts: &[&'ll Value]) -> &'ll Value { - unsafe { llvm::LLVMConstVector(elts.as_ptr(), elts.len() as c_uint) } - } - pub fn const_bytes(&self, bytes: &[u8]) -> &'ll Value { bytes_in_context(self.llcx, bytes) } @@ -217,6 +213,10 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { struct_in_context(self.llcx, elts, packed) } + fn const_vector(&self, elts: &[&'ll Value]) -> &'ll Value { + unsafe { llvm::LLVMConstVector(elts.as_ptr(), elts.len() as c_uint) } + } + fn const_to_opt_uint(&self, v: &'ll Value) -> Option { try_as_const_integral(v).and_then(|v| unsafe { let mut i = 0u64; diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 5881c6236ece6..1144282483f3c 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -16,6 +16,8 @@ codegen_ssa_cgu_not_recorded = codegen_ssa_check_installed_visual_studio = please ensure that Visual Studio 2017 or later, or Build Tools for Visual Studio were installed with the Visual C++ option. +codegen_ssa_const_vector_evaluation = could not evaluate constant vector at compile time + codegen_ssa_copy_path = could not copy {$from} to {$to}: {$error} codegen_ssa_copy_path_buf = unable to copy {$source_file} to {$output_path}: {$error} diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index ed6ac9f9c5da8..e7e2a9d31bc4a 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -663,6 +663,13 @@ pub struct ShuffleIndicesEvaluation { pub span: Span, } +#[derive(Diagnostic)] +#[diag(codegen_ssa_const_vector_evaluation)] +pub struct ConstVectorEvaluation { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(codegen_ssa_missing_memory_ordering)] pub struct MissingMemoryOrdering; diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index a1662f25e1496..1a92a3ac4ac9f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -5,12 +5,13 @@ use super::{CachedLlbb, FunctionCx, LocalRef}; use crate::base; use crate::common::{self, IntPredicate}; +use crate::errors; use crate::meth; use crate::traits::*; use crate::MemFlags; use rustc_ast as ast; -use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; +use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece, LitKind, MetaItemLit, NestedMetaItem}; use rustc_hir::lang_items::LangItem; use rustc_middle::mir::{self, AssertKind, SwitchTargets, UnwindTerminateReason}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement}; @@ -864,7 +865,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // promotes any complex rvalues to constants. if i == 2 && intrinsic == sym::simd_shuffle { if let mir::Operand::Constant(constant) = arg { - let (llval, ty) = self.simd_shuffle_indices(bx, constant); + let (llval, ty) = self.early_evaluate_const_vector(bx, constant); + let llval = llval.unwrap_or_else(|| { + bx.tcx().sess.emit_err(errors::ShuffleIndicesEvaluation { + span: constant.span, + }); + // We've errored, so we don't have to produce working code. + let llty = bx.backend_type(bx.layout_of(ty)); + bx.const_undef(llty) + }); return OperandRef { val: Immediate(llval), layout: bx.layout_of(ty), @@ -908,9 +917,49 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { (args, None) }; + let const_vec_arg_indexes = (|| { + if let Some(def) = def + && let Some(attr) = + bx.tcx().get_attr(def.def_id(), sym::rustc_intrinsic_const_vector_arg) + { + attr.meta_item_list() + .iter() + .flatten() + .map(|item: &NestedMetaItem| match item { + NestedMetaItem::Lit(MetaItemLit { + kind: LitKind::Int(index, _), .. + }) => *index as usize, + _ => span_bug!(item.span(), "attribute argument must be an integer"), + }) + .collect() + } else { + Vec::::new() + } + })(); + let mut copied_constant_arguments = vec![]; 'make_args: for (i, arg) in first_args.iter().enumerate() { - let mut op = self.codegen_operand(bx, arg); + let mut op = if const_vec_arg_indexes.contains(&i) { + // Force the specified argument to be constant by using const-qualification to promote any complex rvalues to constant. + if let mir::Operand::Constant(constant) = arg + && constant.ty().is_simd() + { + let (llval, ty) = self.early_evaluate_const_vector(bx, &constant); + let llval = llval.unwrap_or_else(|| { + bx.tcx() + .sess + .emit_err(errors::ConstVectorEvaluation { span: constant.span }); + // We've errored, so we don't have to produce working code. + let llty = bx.backend_type(bx.layout_of(ty)); + bx.const_undef(llty) + }); + OperandRef { val: Immediate(llval), layout: bx.layout_of(ty) } + } else { + span_bug!(span, "argument at {i} must be a constant vector"); + } + } else { + self.codegen_operand(bx, arg) + }; if let (0, Some(ty::InstanceDef::Virtual(_, idx))) = (i, def) { match op.val { diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs index 558f64fffc263..4ad97147ba7c1 100644 --- a/compiler/rustc_codegen_ssa/src/mir/constant.rs +++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs @@ -1,4 +1,3 @@ -use crate::errors; use crate::mir::operand::OperandRef; use crate::traits::*; use rustc_middle::mir; @@ -28,7 +27,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { .expect("erroneous constant not captured by required_consts") } - /// This is a convenience helper for `simd_shuffle_indices`. It has the precondition + /// This is a convenience helper for `early_evaluate_const_vector`. It has the precondition /// that the given `constant` is an `Const::Unevaluated` and must be convertible to /// a `ValTree`. If you want a more general version of this, talk to `wg-const-eval` on zulip. /// @@ -63,19 +62,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ) } - /// process constant containing SIMD shuffle indices - pub fn simd_shuffle_indices( + /// process constant SIMD vector or constant containing SIMD shuffle indices + pub fn early_evaluate_const_vector( &mut self, bx: &Bx, constant: &mir::ConstOperand<'tcx>, - ) -> (Bx::Value, Ty<'tcx>) { + ) -> (Option, Ty<'tcx>) { let ty = self.monomorphize(constant.ty()); - let val = self - .eval_unevaluated_mir_constant_to_valtree(constant) - .ok() - .flatten() - .map(|val| { - let field_ty = ty.builtin_index().unwrap(); + let field_ty = if ty.is_simd() { + ty.simd_size_and_type(bx.tcx()).1 + } else { + ty.builtin_index().unwrap() + }; + let val = + self.eval_unevaluated_mir_constant_to_valtree(constant).ok().flatten().map(|val| { let values: Vec<_> = val .unwrap_branch() .iter() @@ -87,17 +87,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }; bx.scalar_to_backend(prim, scalar, bx.immediate_backend_type(layout)) } else { - bug!("simd shuffle field {:?}", field) + bug!("field is not a scalar {:?}", field) } }) .collect(); - bx.const_struct(&values, false) - }) - .unwrap_or_else(|| { - bx.tcx().sess.emit_err(errors::ShuffleIndicesEvaluation { span: constant.span }); - // We've errored, so we don't have to produce working code. - let llty = bx.backend_type(bx.layout_of(ty)); - bx.const_undef(llty) + if ty.is_simd() { + bx.const_vector(&values) + } else { + bx.const_struct(&values, false) + } }); (val, ty) } diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs index 4dff9c7684f18..4c2cdfb37ded7 100644 --- a/compiler/rustc_codegen_ssa/src/traits/consts.rs +++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs @@ -28,6 +28,7 @@ pub trait ConstMethods<'tcx>: BackendTypes { fn const_str(&self, s: &str) -> (Self::Value, Self::Value); fn const_struct(&self, elts: &[Self::Value], packed: bool) -> Self::Value; + fn const_vector(&self, elts: &[Self::Value]) -> Self::Value; fn const_to_opt_uint(&self, v: Self::Value) -> Option; fn const_to_opt_u128(&self, v: Self::Value, sign_ext: bool) -> Option; diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 9754f7acaae17..6137c1712c3ab 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -652,6 +652,9 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!( rustc_const_panic_str, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE ), + rustc_attr!( + rustc_intrinsic_const_vector_arg, Normal, template!(List: "arg1_index, arg2_index, ..."), ErrorFollowing, INTERNAL_UNSTABLE + ), // ========================================================================== // Internal attributes, Layout related: diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index be50aad13032f..39cd5707937ab 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -604,6 +604,18 @@ passes_rustc_allow_const_fn_unstable = passes_rustc_dirty_clean = attribute requires -Z query-dep-graph to be enabled +passes_rustc_intrinsic_const_vector_arg = + attribute should be applied to functions in `extern "unadjusted"` modules + .label = not a function in an `extern "unadjusted"` module + +passes_rustc_intrinsic_const_vector_arg_invalid = attribute requires a parameter index + +passes_rustc_intrinsic_const_vector_arg_non_vector = parameter at index {$index} must be a simd type + .label = parameter is a non-simd type + +passes_rustc_intrinsic_const_vector_arg_out_of_bounds = function does not have a parameter at index {$index} + .label = function has {$arg_count} arguments + passes_rustc_layout_scalar_valid_range_arg = expected exactly one integer literal argument diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 4910d63010c6e..0d6680a2af531 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -10,10 +10,12 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, IntoDiagnosticArg, MultiSpan}; use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; use rustc_hir as hir; -use rustc_hir::def_id::LocalModDefId; +use rustc_hir::def::Res; +use rustc_hir::def_id::{DefId, LocalModDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{ - self, FnSig, ForeignItem, HirId, Item, ItemKind, TraitItem, CRATE_HIR_ID, CRATE_OWNER_ID, + self, FnSig, ForeignItem, HirId, Item, ItemKind, Path, PathSegment, QPath, TraitItem, TyKind, + CRATE_HIR_ID, CRATE_OWNER_ID, }; use rustc_hir::{MethodKind, Target, Unsafety}; use rustc_macros::LintDiagnostic; @@ -198,6 +200,9 @@ impl CheckAttrVisitor<'_> { sym::rustc_safe_intrinsic => { self.check_rustc_safe_intrinsic(hir_id, attr, span, target) } + sym::rustc_intrinsic_const_vector_arg => { + self.check_rustc_intrinsic_const_vector_arg(hir_id, attr, span, target) + } _ => true, }; @@ -2083,6 +2088,89 @@ impl CheckAttrVisitor<'_> { false } + fn check_rustc_intrinsic_const_vector_arg( + &self, + hir_id: HirId, + attr: &Attribute, + span: Span, + target: Target, + ) -> bool { + let hir = self.tcx.hir(); + + if let Target::ForeignFn = target + && let Some(parent) = hir.opt_parent_id(hir_id) + && let hir::Node::Item(Item { + kind: ItemKind::ForeignMod { abi: Abi::Unadjusted, .. }, + .. + }) = hir.get(parent) + { + let Some(list) = attr.meta_item_list() else { + // The attribute form is validated on AST. + return false; + }; + + let Some(decl) = self.tcx.hir().get(hir_id).fn_decl() else { + bug!("should be a function declaration"); + }; + + let arg_count = decl.inputs.len() as u128; + for meta in list { + if let Some(LitKind::Int(val, _)) = meta.lit().map(|lit| &lit.kind) { + if *val >= arg_count { + self.tcx.sess.emit_err(errors::RustcIntrinsicConstVectorArgOutOfBounds { + attr_span: attr.span, + span: span, + index: *val, + arg_count: decl.inputs.len(), + }); + return false; + } + + let param_ty = decl.inputs[*val as usize]; + let type_id: Option = match param_ty.kind { + TyKind::Path(path) => match path { + QPath::Resolved(_, Path { res: Res::Def(_, id), .. }) => Some(*id), + QPath::TypeRelative(_, PathSegment { res: Res::Def(_, id), .. }) => { + Some(*id) + } + _ => None, + }, + _ => None, + }; + + let is_simd = if let Some(type_id) = type_id { + self.tcx + .get_attrs(type_id, sym::repr) + .filter_map(|attr| attr.meta_item_list()) + .flatten() + .any(|hint: NestedMetaItem| hint.name_or_empty() == sym::simd) + } else { + false + }; + if !is_simd { + self.tcx.sess.emit_err(errors::RustcIntrinsicConstVectorArgNonVector { + attr_span: attr.span, + param_span: param_ty.span, + index: *val, + }); + return false; + } + } else { + self.tcx.sess.emit_err(errors::RustcIntrinsicConstVectorArgInvalid { + span: meta.span(), + }); + return false; + } + } + } else { + self.tcx + .sess + .emit_err(errors::RustcIntrinsicConstVectorArg { attr_span: attr.span, span }); + return false; + } + true + } + fn check_rustc_std_internal_symbol( &self, attr: &Attribute, diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 5812744532280..0b15ff35f8137 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -636,6 +636,43 @@ pub struct RustcSafeIntrinsic { pub span: Span, } +#[derive(Diagnostic)] +#[diag(passes_rustc_intrinsic_const_vector_arg_out_of_bounds)] +pub(crate) struct RustcIntrinsicConstVectorArgOutOfBounds { + #[primary_span] + pub attr_span: Span, + #[label] + pub span: Span, + pub index: u128, + pub arg_count: usize, +} + +#[derive(Diagnostic)] +#[diag(passes_rustc_intrinsic_const_vector_arg_non_vector)] +pub(crate) struct RustcIntrinsicConstVectorArgNonVector { + #[primary_span] + pub attr_span: Span, + #[label] + pub param_span: Span, + pub index: u128, +} + +#[derive(Diagnostic)] +#[diag(passes_rustc_intrinsic_const_vector_arg_invalid)] +pub(crate) struct RustcIntrinsicConstVectorArgInvalid { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(passes_rustc_intrinsic_const_vector_arg)] +pub struct RustcIntrinsicConstVectorArg { + #[primary_span] + pub attr_span: Span, + #[label] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(passes_rustc_std_internal_symbol)] pub struct RustcStdInternalSymbol { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index d7e822382ef92..1911da98218f2 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1397,6 +1397,7 @@ symbols! { rustc_if_this_changed, rustc_inherit_overflow_checks, rustc_insignificant_dtor, + rustc_intrinsic_const_vector_arg, rustc_layout, rustc_layout_scalar_valid_range_end, rustc_layout_scalar_valid_range_start, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs index 15dceeb8af254..f1ce043b9c571 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs @@ -488,6 +488,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!( rustc_do_not_const_check, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE ), + rustc_attr!(rustc_intrinsic_const_vector_arg, Normal, template!(List), ErrorFollowing, INTERNAL_UNSTABLE), // ========================================================================== // Internal attributes, Layout related: diff --git a/tests/ui/internal-lints/rustc_intrinsic_const_vector_arg.rs b/tests/ui/internal-lints/rustc_intrinsic_const_vector_arg.rs new file mode 100644 index 0000000000000..2d4bbd470372d --- /dev/null +++ b/tests/ui/internal-lints/rustc_intrinsic_const_vector_arg.rs @@ -0,0 +1,58 @@ +// compile-flags: -Z unstable-options +#![feature(abi_unadjusted)] +#![feature(inline_const)] +#![feature(intrinsics)] +#![allow(non_camel_case_types)] +#![feature(repr_simd)] +#![feature(rustc_attrs)] +#![feature(simd_ffi)] +#![allow(unused)] + +#[repr(simd)] +#[derive(Clone)] +pub struct i8x2(i8, i8); + +extern "unadjusted" { + #[rustc_intrinsic_const_vector_arg] //~ ERROR malformed `rustc_intrinsic_const_vector_arg` attribute input + fn foo1(a: i8x2, b: i8); +} + +extern "unadjusted" { + #[rustc_intrinsic_const_vector_arg = "1"] //~ ERROR malformed `rustc_intrinsic_const_vector_arg` attribute input + fn foo2(a: i8x2, b: i8); +} + +#[rustc_intrinsic_const_vector_arg(0)] //~ ERROR attribute should be applied to functions in `extern "unadjusted"` modules +pub struct foo3(i8x2); + +extern "C" { + #[rustc_intrinsic_const_vector_arg(0)] //~ ERROR attribute should be applied to functions in `extern "unadjusted"` modules + fn foo4(a: i8x2); +} + +extern "unadjusted" { + #[rustc_intrinsic_const_vector_arg(0)] //~ ERROR function does not have a parameter at index 0 + fn foo5(); +} + +extern "unadjusted" { + #[rustc_intrinsic_const_vector_arg(1)] //~ ERROR function does not have a parameter at index 1 + fn foo6(a: i8x2); +} + +extern "unadjusted" { + #[rustc_intrinsic_const_vector_arg("bar")] //~ ERROR attribute requires a parameter index + fn foo7(a: i8x2); +} + +extern "unadjusted" { + #[rustc_intrinsic_const_vector_arg(0,2)] //~ ERROR function does not have a parameter at index 2 + fn foo8(a: i8x2, b: i8); +} + +extern "unadjusted" { + #[rustc_intrinsic_const_vector_arg(0)] //~ ERROR parameter at index 0 must be a simd type + fn foo9(a: i8); +} + +fn main() {} diff --git a/tests/ui/internal-lints/rustc_intrinsic_const_vector_arg.stderr b/tests/ui/internal-lints/rustc_intrinsic_const_vector_arg.stderr new file mode 100644 index 0000000000000..3182a9151d8c9 --- /dev/null +++ b/tests/ui/internal-lints/rustc_intrinsic_const_vector_arg.stderr @@ -0,0 +1,68 @@ +error: malformed `rustc_intrinsic_const_vector_arg` attribute input + --> $DIR/rustc_intrinsic_const_vector_arg.rs:16:5 + | +LL | #[rustc_intrinsic_const_vector_arg] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_intrinsic_const_vector_arg(arg1_index, arg2_index, ...)]` + +error: malformed `rustc_intrinsic_const_vector_arg` attribute input + --> $DIR/rustc_intrinsic_const_vector_arg.rs:21:5 + | +LL | #[rustc_intrinsic_const_vector_arg = "1"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_intrinsic_const_vector_arg(arg1_index, arg2_index, ...)]` + +error: attribute should be applied to functions in `extern "unadjusted"` modules + --> $DIR/rustc_intrinsic_const_vector_arg.rs:25:1 + | +LL | #[rustc_intrinsic_const_vector_arg(0)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | pub struct foo3(i8x2); + | ---------------------- not a function in an `extern "unadjusted"` module + +error: attribute should be applied to functions in `extern "unadjusted"` modules + --> $DIR/rustc_intrinsic_const_vector_arg.rs:29:5 + | +LL | #[rustc_intrinsic_const_vector_arg(0)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn foo4(a: i8x2); + | ----------------- not a function in an `extern "unadjusted"` module + +error: function does not have a parameter at index 0 + --> $DIR/rustc_intrinsic_const_vector_arg.rs:34:5 + | +LL | #[rustc_intrinsic_const_vector_arg(0)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn foo5(); + | ---------- function has 0 arguments + +error: function does not have a parameter at index 1 + --> $DIR/rustc_intrinsic_const_vector_arg.rs:39:5 + | +LL | #[rustc_intrinsic_const_vector_arg(1)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn foo6(a: i8x2); + | ----------------- function has 1 arguments + +error: attribute requires a parameter index + --> $DIR/rustc_intrinsic_const_vector_arg.rs:44:40 + | +LL | #[rustc_intrinsic_const_vector_arg("bar")] + | ^^^^^ + +error: function does not have a parameter at index 2 + --> $DIR/rustc_intrinsic_const_vector_arg.rs:49:5 + | +LL | #[rustc_intrinsic_const_vector_arg(0,2)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn foo8(a: i8x2, b: i8); + | ------------------------ function has 2 arguments + +error: parameter at index 0 must be a simd type + --> $DIR/rustc_intrinsic_const_vector_arg.rs:54:5 + | +LL | #[rustc_intrinsic_const_vector_arg(0)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn foo9(a: i8); + | -- parameter is a non-simd type + +error: aborting due to 9 previous errors + diff --git a/tests/ui/internal-lints/rustc_intrinsic_const_vector_arg_calls.rs b/tests/ui/internal-lints/rustc_intrinsic_const_vector_arg_calls.rs new file mode 100644 index 0000000000000..00c341ff4f423 --- /dev/null +++ b/tests/ui/internal-lints/rustc_intrinsic_const_vector_arg_calls.rs @@ -0,0 +1,34 @@ +// compile-flags: -Z unstable-options +#![feature(abi_unadjusted)] +#![feature(inline_const)] +#![feature(intrinsics)] +#![allow(non_camel_case_types)] +#![feature(repr_simd)] +#![feature(rustc_attrs)] +#![feature(simd_ffi)] +#![allow(unused)] + +#[repr(simd)] +#[derive(Clone)] +pub struct i8x2(i8, i8); + +extern "unadjusted" { + #[rustc_intrinsic_const_vector_arg(0)] // OK + fn foo1(a: i8x2); +} + +extern "unadjusted" { + #[rustc_intrinsic_const_vector_arg(0,1)] // OK + fn foo2(a: i8x2, b: i8x2); +} + +fn main() { + unsafe { + foo1(i8x2(0,1)); //~ ERROR argument at index 0 must be a constant + foo1({ i8x2(0,1) }); //~ ERROR argument at index 0 must be a constant + foo1(const { i8x2(0,1) }); // OK + + foo2(const { i8x2(0,1) }, { i8x2(2,3) }); //~ ERROR argument at index 1 must be a constant + foo2(const { i8x2(0,1) }, const { i8x2(2,3) }); // OK + } +} diff --git a/tests/ui/internal-lints/rustc_intrinsic_const_vector_arg_calls.stderr b/tests/ui/internal-lints/rustc_intrinsic_const_vector_arg_calls.stderr new file mode 100644 index 0000000000000..43a7d73efa5c3 --- /dev/null +++ b/tests/ui/internal-lints/rustc_intrinsic_const_vector_arg_calls.stderr @@ -0,0 +1,20 @@ +error: argument at index 0 must be a constant + --> $DIR/rustc_intrinsic_const_vector_arg_calls.rs:27:9 + | +LL | foo1(i8x2(0,1)); + | ^^^^^^^^^^^^^^^ + +error: argument at index 0 must be a constant + --> $DIR/rustc_intrinsic_const_vector_arg_calls.rs:28:9 + | +LL | foo1({ i8x2(0,1) }); + | ^^^^^^^^^^^^^^^^^^^ + +error: argument at index 1 must be a constant + --> $DIR/rustc_intrinsic_const_vector_arg_calls.rs:31:9 + | +LL | foo2(const { i8x2(0,1) }, { i8x2(2,3) }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/simd/intrinsic/inlining-issue67557-ice.rs b/tests/ui/simd/intrinsic/inlining-issue67557-ice.rs index 5ca684a9d7831..6dc9ff250c4ab 100644 --- a/tests/ui/simd/intrinsic/inlining-issue67557-ice.rs +++ b/tests/ui/simd/intrinsic/inlining-issue67557-ice.rs @@ -1,5 +1,5 @@ -// This used to cause an ICE for an internal index out of range due to simd_shuffle_indices being -// passed the wrong Instance, causing issues with inlining. See #67557. +// This used to cause an ICE for an internal index out of range due to early_evaluate_const_vector +// being passed the wrong Instance, causing issues with inlining. See #67557. // // run-pass // compile-flags: -Zmir-opt-level=4 diff --git a/tests/ui/simd/intrinsic/inlining-issue67557.rs b/tests/ui/simd/intrinsic/inlining-issue67557.rs index 5633ad70cd318..f2b634d4bea4e 100644 --- a/tests/ui/simd/intrinsic/inlining-issue67557.rs +++ b/tests/ui/simd/intrinsic/inlining-issue67557.rs @@ -1,5 +1,5 @@ -// This used to cause assert_10_13 to unexpectingly fail, due to simd_shuffle_indices being passed -// the wrong Instance, causing issues with inlining. See #67557. +// This used to cause assert_10_13 to unexpectingly fail, due to early_evaluate_const_vector +// being passed the wrong Instance, causing issues with inlining. See #67557. // // run-pass // compile-flags: -Zmir-opt-level=4