diff --git a/Cargo.lock b/Cargo.lock index 3355e1ddaef86..3d43e3929c11a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3779,6 +3779,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 bafc62c7318b4..a53267502f901 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.12" 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 c14a617eb91fe..826cf2a83d10e 100644 --- a/compiler/rustc_borrowck/messages.ftl +++ b/compiler/rustc_borrowck/messages.ftl @@ -74,6 +74,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 40c2ef1c91e14..b59e5f6c41d64 100644 --- a/compiler/rustc_borrowck/src/session_diagnostics.rs +++ b/compiler/rustc_borrowck/src/session_diagnostics.rs @@ -479,3 +479,11 @@ pub(crate) struct SimdIntrinsicArgConst { pub arg: usize, pub intrinsic: String, } + +#[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 db4b5209145f0..87fc911b09254 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -51,7 +51,9 @@ use rustc_mir_dataflow::move_paths::MoveData; use rustc_mir_dataflow::ResultsCursor; use crate::renumber::RegionCtxt; -use crate::session_diagnostics::{MoveUnsized, SimdIntrinsicArgConst}; +use crate::session_diagnostics::{ + IntrinsicConstVectorArgNonConst, MoveUnsized, SimdIntrinsicArgConst, +}; use crate::{ borrow_set::BorrowSet, constraints::{OutlivesConstraint, OutlivesConstraintSet}, @@ -1630,6 +1632,33 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { intrinsic: name.to_string(), }); } + } 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| { + if let Some(rustc_ast::LitKind::Int(index, _)) = + item.lit().map(|lit| &lit.kind) + { + if let Some(arg) = args.get::(index.get() as usize) { + if !matches!(arg, Spanned { node: Operand::Constant(_), .. }) { + self.tcx().dcx().emit_err( + IntrinsicConstVectorArgNonConst { + span: term.source_info.span, + index: index.get(), + }, + ); + } + } + } else { + span_mirbug!(self, term, "literal kind"); + } + }); + } + None => (), + } + // Error is reported by `rustc_attr!` } } debug!(?func_ty); diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index 70f0dc37e39da..aa02bf118e93d 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -161,6 +161,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 fe64649cf70fb..0ed12b60ad6d1 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -224,6 +224,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 000fe2e3ce0f5..5b375aaabaf24 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -19,6 +19,8 @@ codegen_ssa_check_installed_visual_studio = please ensure that Visual Studio 201 codegen_ssa_compiler_builtins_cannot_call = `compiler_builtins` cannot call functions through upstream monomorphizations; encountered invalid call from `{$caller}` to `{$callee}` +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} @@ -31,6 +33,7 @@ codegen_ssa_expected_used_symbol = expected `used`, `used(compiler)` or `used(li codegen_ssa_extern_funcs_not_found = some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified + codegen_ssa_extract_bundled_libs_archive_member = failed to get data from archive member '{$rlib}': {$error} codegen_ssa_extract_bundled_libs_convert_name = failed to convert name '{$rlib}': {$error} codegen_ssa_extract_bundled_libs_mmap_file = failed to mmap file '{$rlib}': {$error} @@ -60,6 +63,8 @@ codegen_ssa_incorrect_cgu_reuse_type = codegen_ssa_insufficient_vs_code_product = VS Code is a different product, and is not sufficient. +codegen_ssa_invalid_intrinsic_const_vector_arg = invalid argument, must be integer literal + codegen_ssa_invalid_link_ordinal_nargs = incorrect number of arguments to `#[link_ordinal]` .note = the attribute requires exactly one argument diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index bfa4c683d56ed..9cee66ba06464 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -1,4 +1,4 @@ -use rustc_ast::{ast, attr, MetaItemKind, NestedMetaItem}; +use rustc_ast::{ast, attr, LitKind, MetaItemKind, MetaItemLit, NestedMetaItem}; use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr}; use rustc_errors::{codes::*, struct_span_code_err, DiagMessage, SubdiagMessage}; use rustc_hir as hir; @@ -523,6 +523,26 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { )) }) } + sym::rustc_intrinsic_const_vector_arg => { + let mut indicies: Vec = Vec::new(); + if let Some(item_list) = attr.meta_item_list() { + for item in item_list { + match item { + NestedMetaItem::Lit(MetaItemLit { + kind: LitKind::Int(index, _), + .. + }) => { + indicies.push(index.get() as usize); + } + _ => { + tcx.dcx() + .emit_err(errors::IntrinsicConstVectorArg { span: attr.span }); + } + } + } + } + codegen_fn_attrs.const_vector_indices = Some(indicies); + } _ => {} } } diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index e9d31db92541b..9e7316557bc87 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -598,6 +598,20 @@ 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_invalid_intrinsic_const_vector_arg)] +pub struct IntrinsicConstVectorArg { + #[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 c9c8f02c491bd..8274f5988112e 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -5,7 +5,7 @@ use super::{CachedLlbb, FunctionCx, LocalRef}; use crate::base::{self, is_call_from_compiler_builtins_to_upstream_monomorphization}; use crate::common::{self, IntPredicate}; -use crate::errors::CompilerBuiltinsCannotCall; +use crate::errors; use crate::meth; use crate::traits::*; use crate::MemFlags; @@ -169,7 +169,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { if destination.is_some() { let caller = with_no_trimmed_paths!(tcx.def_path_str(fx.instance.def_id())); let callee = with_no_trimmed_paths!(tcx.def_path_str(instance.def_id())); - tcx.dcx().emit_err(CompilerBuiltinsCannotCall { caller, callee }); + tcx.dcx().emit_err(errors::CompilerBuiltinsCannotCall { caller, callee }); } else { info!( "compiler_builtins call to diverging function {:?} replaced with abort", @@ -925,7 +925,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // checked by the type-checker. if i == 2 && intrinsic.name == sym::simd_shuffle { if let mir::Operand::Constant(constant) = &arg.node { - let (llval, ty) = self.simd_shuffle_indices(bx, constant); + let (llval, ty) = self.early_evaluate_const_vector(bx, constant); + return OperandRef { val: Immediate(llval), layout: bx.layout_of(ty), @@ -1003,9 +1004,32 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { (args, None) }; + let const_vec_arg_indexes = if let Some(def) = def { + let val = bx.tcx().codegen_fn_attrs(def.def_id()); + let const_vector_indices = &val.const_vector_indices; + if let Some(const_vector_i) = const_vector_indices { + &const_vector_i.as_ref() + } else { + &Vec::::new() + } + } 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.node); + let mut op = if const_vec_arg_indexes.contains(&i) { + if let mir::Operand::Constant(constant) = &arg.node + && constant.ty().is_simd() + { + let (llval, ty) = self.early_evaluate_const_vector(bx, &constant); + 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.node) + }; if let (0, Some(ty::InstanceKind::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 35e9a3b7dc206..69c917c843f05 100644 --- a/compiler/rustc_codegen_ssa/src/mir/constant.rs +++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs @@ -4,6 +4,7 @@ use crate::traits::*; use rustc_middle::mir; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::layout::HasTyCtxt; +use rustc_middle::ty::ValTree; use rustc_middle::ty::{self, Ty}; use rustc_middle::{bug, span_bug}; use rustc_target::abi::Abi; @@ -29,7 +30,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { .expect("erroneous constant missed by mono item collection") } - /// 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. /// @@ -60,36 +61,48 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.cx.tcx().const_eval_resolve_for_typeck(ty::ParamEnv::reveal_all(), uv, constant.span) } - /// 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>) { let ty = self.monomorphize(constant.ty()); + let ty_is_simd = ty.is_simd(); + 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() .map(|x| x.ok()) .flatten() .map(|val| { - let field_ty = ty.builtin_index().unwrap(); - let values: Vec<_> = val - .unwrap_branch() - .iter() - .map(|field| { - if let Some(prim) = field.try_to_scalar() { - let layout = bx.layout_of(field_ty); - let Abi::Scalar(scalar) = layout.abi else { - bug!("from_const: invalid ByVal layout: {:#?}", layout); - }; - bx.scalar_to_backend(prim, scalar, bx.immediate_backend_type(layout)) - } else { - bug!("simd shuffle field {:?}", field) + let mut values: Vec = Vec::new(); + // For reliably being able to handle either: + // pub struct defn(i32, i32) + // call(1, 0); + // OR + // pub struct defn([i32, 2]) + // call([1, 0]); + // + // And outputting: @call(<2 x i32> ) + // thus treating them the same if they are a const vector + for field in val.unwrap_branch().iter() { + match field { + ValTree::Branch(_) => { + let scalars = self.flatten_branch_to_scalars(bx, &field, field_ty); + values.extend(scalars); + } + ValTree::Leaf(_) => { + let scalar = self.extract_scalar(bx, &field, field_ty); + values.push(scalar); } - }) - .collect(); - bx.const_struct(&values, false) + } + } + if ty_is_simd { bx.const_vector(&values) } else { bx.const_struct(&values, false) } }) .unwrap_or_else(|| { bx.tcx().dcx().emit_err(errors::ShuffleIndicesEvaluation { span: constant.span }); @@ -99,4 +112,34 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }); (val, ty) } + + fn flatten_branch_to_scalars( + &mut self, + bx: &Bx, + branch: &ValTree<'tcx>, + field_ty: Ty<'tcx>, + ) -> Vec { + branch + .unwrap_branch() + .iter() + .map(|field| match field { + ValTree::Branch(_) => { + bug!("Cannot have arbitrarily nested const vectors: {:#?}", field) + } + ValTree::Leaf(_) => self.extract_scalar(bx, field, field_ty), + }) + .collect() + } + + fn extract_scalar(&mut self, bx: &Bx, field: &ValTree<'tcx>, field_ty: Ty<'tcx>) -> Bx::Value { + if let Some(prim) = field.try_to_scalar() { + let layout = bx.layout_of(field_ty); + let Abi::Scalar(scalar) = layout.abi else { + bug!("from_const: invalid ByVal layout: {:#?}", layout); + }; + bx.scalar_to_backend(prim, scalar, bx.immediate_backend_type(layout)) + } else { + bug!("field is not a scalar {:?}", field) + } + } } diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs index 3da732602c520..e6539b075e3db 100644 --- a/compiler/rustc_codegen_ssa/src/traits/consts.rs +++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs @@ -29,6 +29,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 7b27049a579a1..78d00bf8744de 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -837,6 +837,9 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_runtime, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, INTERNAL_UNSTABLE ), + rustc_attr!( + rustc_intrinsic_const_vector_arg, Normal, template!(List: "arg1_index, arg2_index, ..."), ErrorFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE + ), // ========================================================================== // Internal attributes, Layout related: diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 3ddf889b63afe..c7998c5f44c03 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -48,6 +48,9 @@ pub struct CodegenFnAttrs { /// The `#[patchable_function_entry(...)]` attribute. Indicates how many nops should be around /// the function entry. pub patchable_function_entry: Option, + /// The `#[rustc_intrinsic_const_vector_arg(...)]` attribute. The indices + /// of const vector arguments + pub const_vector_indices: Option>, } #[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)] @@ -148,6 +151,7 @@ impl CodegenFnAttrs { instruction_set: None, alignment: None, patchable_function_entry: None, + const_vector_indices: None, } } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 1d93cbaddd6fe..506b239c29bf1 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -601,6 +601,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 defined in the local crate + .label = parameter is a non-simd type or is not defined locally + +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 ce2fa83810fe8..d53af47555fb4 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -11,11 +11,14 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, IntoDiagArg, MultiSpan}; use rustc_errors::{DiagCtxtHandle, StashKey}; use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; -use rustc_hir::def_id::LocalModDefId; +use rustc_hir as hir; +use rustc_hir::def::Res; +use rustc_hir::def_id::{DefId, LocalModDefId}; + use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{self as hir}; 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, Safety, Target}; use rustc_macros::LintDiagnostic; @@ -206,6 +209,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [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, }; @@ -2084,6 +2090,112 @@ impl<'tcx> CheckAttrVisitor<'tcx> { false } + fn check_rustc_intrinsic_const_vector_arg( + &self, + hir_id: HirId, + attr: &Attribute, + span: Span, + target: Target, + ) -> bool { + if let Target::ForeignFn = target + && let hir::Node::Item(Item { + kind: ItemKind::ForeignMod { abi: Abi::Unadjusted, .. }, + .. + }) = self.tcx.parent_hir_node(hir_id) + { + let Some(list) = attr.meta_item_list() else { + // The attribute form is validated on AST. + return false; + }; + + let Some(decl) = self.tcx.hir_node(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.dcx().emit_err(errors::RustcIntrinsicConstVectorArgOutOfBounds { + attr_span: attr.span, + span: span, + index: val.get(), + arg_count: decl.inputs.len(), + }); + return false; + } + + fn get_type_def(tcx: TyCtxt<'_>, param_ty: rustc_hir::Ty<'_>) -> Option { + let type_id: Option = match param_ty.kind { + TyKind::Path(path) => match path { + QPath::Resolved(_, Path { res: Res::Def(_, id), .. }) + | QPath::TypeRelative( + _, + PathSegment { res: Res::Def(_, id), .. }, + ) + | QPath::Resolved( + _, + Path { res: Res::SelfTyAlias { alias_to: id, .. }, .. }, + ) + | QPath::TypeRelative( + _, + PathSegment { + res: Res::SelfTyAlias { alias_to: id, .. }, .. + }, + ) => Some(*id), + _ => None, + }, + _ => None, + }; + if let Some(type_id) = type_id + && let Some(did) = type_id.as_local() + { + if let Some(param_ty) = + tcx.hir_node(tcx.local_def_id_to_hir_id(did)).ty() + { + return get_type_def(tcx, *param_ty); + } else { + return Some(type_id); + } + } + None + } + + let param_ty = decl.inputs[val.get() as usize]; + let type_id = get_type_def(self.tcx, param_ty); + 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.dcx().emit_err(errors::RustcIntrinsicConstVectorArgNonVector { + attr_span: attr.span, + param_span: param_ty.span, + index: val.get(), + }); + return false; + } + } else { + self.tcx.dcx().emit_err(errors::RustcIntrinsicConstVectorArgInvalid { + span: meta.span(), + }); + return false; + } + } + } else { + self.tcx + .dcx() + .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 58d27d5b4bbaa..5e2b3b30a8ce3 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -617,6 +617,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 5ae0138911673..1fadd4c5a347b 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1632,6 +1632,7 @@ symbols! { rustc_inherit_overflow_checks, rustc_insignificant_dtor, rustc_intrinsic, + rustc_intrinsic_const_vector_arg, rustc_intrinsic_must_be_overridden, rustc_layout, rustc_layout_scalar_valid_range_end, 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..43285dfd1c059 --- /dev/null +++ b/tests/ui/internal-lints/rustc_intrinsic_const_vector_arg.rs @@ -0,0 +1,66 @@ +//@ compile-flags: -Z unstable-options +#![feature(abi_unadjusted)] +#![feature(intrinsics)] +#![allow(non_camel_case_types)] +#![feature(portable_simd)] +#![feature(repr_simd)] +#![feature(rustc_attrs)] +#![feature(simd_ffi)] +#![allow(unused)] + +use std::simd::prelude::Simd; + +#[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 invalid argument, must be integer literal + //~^ 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 defined in the local crate + fn foo9(a: i8); +} + +extern "unadjusted" { + #[rustc_intrinsic_const_vector_arg(0)] //~ ERROR parameter at index 0 must be a simd type defined in the local crate + fn foo10(a: Simd); +} + +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..33cbc68dc58a3 --- /dev/null +++ b/tests/ui/internal-lints/rustc_intrinsic_const_vector_arg.stderr @@ -0,0 +1,82 @@ +error: malformed `rustc_intrinsic_const_vector_arg` attribute input + --> $DIR/rustc_intrinsic_const_vector_arg.rs:18: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:23: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:27: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:31: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:36: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:41: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:46: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:52: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 defined in the local crate + --> $DIR/rustc_intrinsic_const_vector_arg.rs:57:5 + | +LL | #[rustc_intrinsic_const_vector_arg(0)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn foo9(a: i8); + | -- parameter is a non-simd type or is not defined locally + +error: parameter at index 0 must be a simd type defined in the local crate + --> $DIR/rustc_intrinsic_const_vector_arg.rs:62:5 + | +LL | #[rustc_intrinsic_const_vector_arg(0)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn foo10(a: Simd); + | ----------- parameter is a non-simd type or is not defined locally + +error: invalid argument, must be integer literal + --> $DIR/rustc_intrinsic_const_vector_arg.rs:46:5 + | +LL | #[rustc_intrinsic_const_vector_arg("bar")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 11 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..ce40deede1c3d --- /dev/null +++ b/tests/ui/internal-lints/rustc_intrinsic_const_vector_arg_calls.rs @@ -0,0 +1,69 @@ +//@ compile-flags: -Z unstable-options +#![feature(abi_unadjusted)] +#![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); + +#[repr(simd)] +#[derive(Clone)] +pub struct f32x2(f32, f32); + +#[repr(simd)] +#[derive(Clone)] +pub struct i8x2_arr([i8; 2]); + +#[repr(simd)] +#[derive(Clone)] +pub struct f32x2_arr([f32; 2]); + +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); +} + +extern "unadjusted" { + #[rustc_intrinsic_const_vector_arg(0)] // OK + fn foo3(a: i8x2_arr); +} + +extern "unadjusted" { + #[rustc_intrinsic_const_vector_arg(0)] // OK + fn foo4(a: f32x2); +} + +extern "unadjusted" { + #[rustc_intrinsic_const_vector_arg(0)] // OK + fn foo5(a: f32x2_arr); +} + +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 + + foo3(i8x2_arr([0, 1])); //~ ERROR argument at index 0 must be a constant + foo3(const { i8x2_arr([0, 1]) }); // OK + + foo4(f32x2(0.0, 1.0)); //~ ERROR argument at index 0 must be a constant + foo4(const { f32x2(0.0, 1.0) }); // OK + + foo5(f32x2_arr([0.0, 1.0])); //~ ERROR argument at index 0 must be a constant + foo5(const { f32x2_arr([0.0, 1.0]) }); // 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..b76fc807fb522 --- /dev/null +++ b/tests/ui/internal-lints/rustc_intrinsic_const_vector_arg_calls.stderr @@ -0,0 +1,38 @@ +error: argument at index 0 must be a constant + --> $DIR/rustc_intrinsic_const_vector_arg_calls.rs:53:9 + | +LL | foo1(i8x2(0, 1)); + | ^^^^^^^^^^^^^^^^ + +error: argument at index 0 must be a constant + --> $DIR/rustc_intrinsic_const_vector_arg_calls.rs:54:9 + | +LL | foo1({ i8x2(0, 1) }); + | ^^^^^^^^^^^^^^^^^^^^ + +error: argument at index 1 must be a constant + --> $DIR/rustc_intrinsic_const_vector_arg_calls.rs:57:9 + | +LL | foo2(const { i8x2(0, 1) }, { i8x2(2, 3) }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: argument at index 0 must be a constant + --> $DIR/rustc_intrinsic_const_vector_arg_calls.rs:60:9 + | +LL | foo3(i8x2_arr([0, 1])); + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: argument at index 0 must be a constant + --> $DIR/rustc_intrinsic_const_vector_arg_calls.rs:63:9 + | +LL | foo4(f32x2(0.0, 1.0)); + | ^^^^^^^^^^^^^^^^^^^^^ + +error: argument at index 0 must be a constant + --> $DIR/rustc_intrinsic_const_vector_arg_calls.rs:66:9 + | +LL | foo5(f32x2_arr([0.0, 1.0])); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors + diff --git a/tests/ui/simd/intrinsic/inlining-issue67557-ice.rs b/tests/ui/simd/intrinsic/inlining-issue67557-ice.rs index 928d3824703e7..630af4da539b5 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 b8b8dbba547d1..f3896b36e412b 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