Auto merge of #85110 - RalfJung:no-rustc_args_required_const, r=oli-obk
Remove rustc_args_required_const attribute Now that stdarch no longer needs it (thanks `@Amanieu!),` we can kill the `rustc_args_required_const` attribute. This means that lifetime extension of references to temporaries is the only remaining job that promotion is performing. :-) r? `@oli-obk` Fixes https://github.com/rust-lang/rust/issues/69493
This commit is contained in:
commit
d2df620789
33 changed files with 111 additions and 613 deletions
|
@ -14,7 +14,6 @@ use rustc_middle::ty::cast::{CastTy, IntTy};
|
||||||
use rustc_middle::ty::layout::HasTyCtxt;
|
use rustc_middle::ty::layout::HasTyCtxt;
|
||||||
use rustc_middle::ty::{self, adjustment::PointerCast, Instance, Ty, TyCtxt};
|
use rustc_middle::ty::{self, adjustment::PointerCast, Instance, Ty, TyCtxt};
|
||||||
use rustc_span::source_map::{Span, DUMMY_SP};
|
use rustc_span::source_map::{Span, DUMMY_SP};
|
||||||
use rustc_span::symbol::sym;
|
|
||||||
use rustc_target::abi::{Abi, Int, LayoutOf, Variants};
|
use rustc_target::abi::{Abi, Int, LayoutOf, Variants};
|
||||||
|
|
||||||
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
|
@ -187,9 +186,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
mir::CastKind::Pointer(PointerCast::ReifyFnPointer) => {
|
mir::CastKind::Pointer(PointerCast::ReifyFnPointer) => {
|
||||||
match *operand.layout.ty.kind() {
|
match *operand.layout.ty.kind() {
|
||||||
ty::FnDef(def_id, substs) => {
|
ty::FnDef(def_id, substs) => {
|
||||||
if bx.cx().tcx().has_attr(def_id, sym::rustc_args_required_const) {
|
|
||||||
bug!("reifying a fn ptr that requires const arguments");
|
|
||||||
}
|
|
||||||
let instance = ty::Instance::resolve_for_fn_ptr(
|
let instance = ty::Instance::resolve_for_fn_ptr(
|
||||||
bx.tcx(),
|
bx.tcx(),
|
||||||
ty::ParamEnv::reveal_all(),
|
ty::ParamEnv::reveal_all(),
|
||||||
|
|
|
@ -469,7 +469,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
rustc_attr!(rustc_promotable, AssumedUsed, template!(Word), IMPL_DETAIL),
|
rustc_attr!(rustc_promotable, AssumedUsed, template!(Word), IMPL_DETAIL),
|
||||||
rustc_attr!(rustc_args_required_const, AssumedUsed, template!(List: "N"), INTERNAL_UNSTABLE),
|
|
||||||
rustc_attr!(rustc_legacy_const_generics, AssumedUsed, template!(List: "N"), INTERNAL_UNSTABLE),
|
rustc_attr!(rustc_legacy_const_generics, AssumedUsed, template!(List: "N"), INTERNAL_UNSTABLE),
|
||||||
|
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
|
@ -7,7 +7,6 @@ use rustc_middle::mir::CastKind;
|
||||||
use rustc_middle::ty::adjustment::PointerCast;
|
use rustc_middle::ty::adjustment::PointerCast;
|
||||||
use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
|
use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
|
||||||
use rustc_middle::ty::{self, FloatTy, Ty, TypeAndMut};
|
use rustc_middle::ty::{self, FloatTy, Ty, TypeAndMut};
|
||||||
use rustc_span::symbol::sym;
|
|
||||||
use rustc_target::abi::{Integer, LayoutOf, Variants};
|
use rustc_target::abi::{Integer, LayoutOf, Variants};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
@ -49,13 +48,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
// All reifications must be monomorphic, bail out otherwise.
|
// All reifications must be monomorphic, bail out otherwise.
|
||||||
ensure_monomorphic_enough(*self.tcx, src.layout.ty)?;
|
ensure_monomorphic_enough(*self.tcx, src.layout.ty)?;
|
||||||
|
|
||||||
if self.tcx.has_attr(def_id, sym::rustc_args_required_const) {
|
|
||||||
span_bug!(
|
|
||||||
self.cur_span(),
|
|
||||||
"reifying a fn ptr that requires const arguments"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let instance = ty::Instance::resolve_for_fn_ptr(
|
let instance = ty::Instance::resolve_for_fn_ptr(
|
||||||
*self.tcx,
|
*self.tcx,
|
||||||
self.param_env,
|
self.param_env,
|
||||||
|
|
|
@ -305,7 +305,6 @@ where
|
||||||
let base_intern_mode = match intern_kind {
|
let base_intern_mode = match intern_kind {
|
||||||
InternKind::Static(mutbl) => InternMode::Static(mutbl),
|
InternKind::Static(mutbl) => InternMode::Static(mutbl),
|
||||||
// `Constant` includes array lengths.
|
// `Constant` includes array lengths.
|
||||||
// `Promoted` includes non-`Copy` array initializers and `rustc_args_required_const` arguments.
|
|
||||||
InternKind::Constant | InternKind::Promoted => InternMode::Const,
|
InternKind::Constant | InternKind::Promoted => InternMode::Const,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ use rustc_middle::mir::*;
|
||||||
use rustc_middle::ty::subst::SubstsRef;
|
use rustc_middle::ty::subst::SubstsRef;
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||||
use rustc_span::symbol::{sym, Symbol};
|
use rustc_span::symbol::{sym, Symbol};
|
||||||
|
use rustc_span::Span;
|
||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
|
|
||||||
pub struct LowerIntrinsics;
|
pub struct LowerIntrinsics;
|
||||||
|
@ -119,6 +120,9 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
|
||||||
terminator.kind = TerminatorKind::Goto { target };
|
terminator.kind = TerminatorKind::Goto { target };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_ if intrinsic_name.as_str().starts_with("simd_shuffle") => {
|
||||||
|
validate_simd_shuffle(tcx, args, terminator.source_info.span);
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -132,9 +136,19 @@ fn resolve_rust_intrinsic(
|
||||||
) -> Option<(Symbol, SubstsRef<'tcx>)> {
|
) -> Option<(Symbol, SubstsRef<'tcx>)> {
|
||||||
if let ty::FnDef(def_id, substs) = *func_ty.kind() {
|
if let ty::FnDef(def_id, substs) = *func_ty.kind() {
|
||||||
let fn_sig = func_ty.fn_sig(tcx);
|
let fn_sig = func_ty.fn_sig(tcx);
|
||||||
if fn_sig.abi() == Abi::RustIntrinsic {
|
if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = fn_sig.abi() {
|
||||||
return Some((tcx.item_name(def_id), substs));
|
return Some((tcx.item_name(def_id), substs));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn validate_simd_shuffle(tcx: TyCtxt<'tcx>, args: &[Operand<'tcx>], span: Span) {
|
||||||
|
match &args[2] {
|
||||||
|
Operand::Constant(_) => {} // all good
|
||||||
|
_ => {
|
||||||
|
let msg = format!("last argument of `simd_shuffle` is required to be a `const` item");
|
||||||
|
tcx.sess.span_err(span, &msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -12,20 +12,16 @@
|
||||||
//! initialization and can otherwise silence errors, if
|
//! initialization and can otherwise silence errors, if
|
||||||
//! move analysis runs after promotion on broken MIR.
|
//! move analysis runs after promotion on broken MIR.
|
||||||
|
|
||||||
use rustc_ast::LitKind;
|
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::DefId;
|
|
||||||
use rustc_middle::mir::traversal::ReversePostorder;
|
use rustc_middle::mir::traversal::ReversePostorder;
|
||||||
use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
|
use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
|
||||||
use rustc_middle::mir::*;
|
use rustc_middle::mir::*;
|
||||||
use rustc_middle::ty::cast::CastTy;
|
use rustc_middle::ty::cast::CastTy;
|
||||||
use rustc_middle::ty::subst::InternalSubsts;
|
use rustc_middle::ty::subst::InternalSubsts;
|
||||||
use rustc_middle::ty::{self, List, TyCtxt, TypeFoldable};
|
use rustc_middle::ty::{self, List, TyCtxt, TypeFoldable};
|
||||||
use rustc_span::symbol::sym;
|
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
|
||||||
use rustc_index::vec::{Idx, IndexVec};
|
use rustc_index::vec::{Idx, IndexVec};
|
||||||
use rustc_target::spec::abi::Abi;
|
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::{cmp, iter, mem};
|
use std::{cmp, iter, mem};
|
||||||
|
@ -36,8 +32,8 @@ use crate::transform::MirPass;
|
||||||
|
|
||||||
/// A `MirPass` for promotion.
|
/// A `MirPass` for promotion.
|
||||||
///
|
///
|
||||||
/// Promotion is the extraction of promotable temps into separate MIR bodies. This pass also emits
|
/// Promotion is the extraction of promotable temps into separate MIR bodies so they can have
|
||||||
/// errors when promotion of `#[rustc_args_required_const]` arguments fails.
|
/// `'static` lifetime.
|
||||||
///
|
///
|
||||||
/// After this pass is run, `promoted_fragments` will hold the MIR body corresponding to each
|
/// After this pass is run, `promoted_fragments` will hold the MIR body corresponding to each
|
||||||
/// newly created `Constant`.
|
/// newly created `Constant`.
|
||||||
|
@ -101,47 +97,16 @@ impl TempState {
|
||||||
pub enum Candidate {
|
pub enum Candidate {
|
||||||
/// Borrow of a constant temporary, candidate for lifetime extension.
|
/// Borrow of a constant temporary, candidate for lifetime extension.
|
||||||
Ref(Location),
|
Ref(Location),
|
||||||
|
|
||||||
/// Currently applied to function calls where the callee has the unstable
|
|
||||||
/// `#[rustc_args_required_const]` attribute as well as the SIMD shuffle
|
|
||||||
/// intrinsic. The intrinsic requires the arguments are indeed constant and
|
|
||||||
/// the attribute currently provides the semantic requirement that arguments
|
|
||||||
/// must be constant.
|
|
||||||
Argument { bb: BasicBlock, index: usize },
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Candidate {
|
impl Candidate {
|
||||||
/// Returns `true` if we should use the "explicit" rules for promotability for this `Candidate`.
|
|
||||||
fn forces_explicit_promotion(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
Candidate::Ref(_) => false,
|
|
||||||
Candidate::Argument { .. } => true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn source_info(&self, body: &Body<'_>) -> SourceInfo {
|
fn source_info(&self, body: &Body<'_>) -> SourceInfo {
|
||||||
match self {
|
match self {
|
||||||
Candidate::Ref(location) => *body.source_info(*location),
|
Candidate::Ref(location) => *body.source_info(*location),
|
||||||
Candidate::Argument { bb, .. } => *body.source_info(body.terminator_loc(*bb)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn args_required_const(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Vec<usize>> {
|
|
||||||
let attrs = tcx.get_attrs(def_id);
|
|
||||||
let attr = attrs.iter().find(|a| tcx.sess.check_name(a, sym::rustc_args_required_const))?;
|
|
||||||
let mut ret = vec![];
|
|
||||||
for meta in attr.meta_item_list()? {
|
|
||||||
match meta.literal()?.kind {
|
|
||||||
LitKind::Int(a, _) => {
|
|
||||||
ret.push(a as usize);
|
|
||||||
}
|
|
||||||
_ => bug!("invalid arg index"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(ret)
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Collector<'a, 'tcx> {
|
struct Collector<'a, 'tcx> {
|
||||||
ccx: &'a ConstCx<'a, 'tcx>,
|
ccx: &'a ConstCx<'a, 'tcx>,
|
||||||
temps: IndexVec<Local, TempState>,
|
temps: IndexVec<Local, TempState>,
|
||||||
|
@ -208,31 +173,6 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> {
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
|
|
||||||
self.super_terminator(terminator, location);
|
|
||||||
|
|
||||||
if let TerminatorKind::Call { ref func, .. } = terminator.kind {
|
|
||||||
if let ty::FnDef(def_id, _) = *func.ty(self.ccx.body, self.ccx.tcx).kind() {
|
|
||||||
let fn_sig = self.ccx.tcx.fn_sig(def_id);
|
|
||||||
if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = fn_sig.abi() {
|
|
||||||
let name = self.ccx.tcx.item_name(def_id);
|
|
||||||
// FIXME(eddyb) use `#[rustc_args_required_const(2)]` for shuffles.
|
|
||||||
if name.as_str().starts_with("simd_shuffle") {
|
|
||||||
self.candidates.push(Candidate::Argument { bb: location.block, index: 2 });
|
|
||||||
|
|
||||||
return; // Don't double count `simd_shuffle` candidates
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(constant_args) = args_required_const(self.ccx.tcx, def_id) {
|
|
||||||
for index in constant_args {
|
|
||||||
self.candidates.push(Candidate::Argument { bb: location.block, index });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn collect_temps_and_candidates(
|
pub fn collect_temps_and_candidates(
|
||||||
|
@ -256,14 +196,6 @@ pub fn collect_temps_and_candidates(
|
||||||
struct Validator<'a, 'tcx> {
|
struct Validator<'a, 'tcx> {
|
||||||
ccx: &'a ConstCx<'a, 'tcx>,
|
ccx: &'a ConstCx<'a, 'tcx>,
|
||||||
temps: &'a IndexVec<Local, TempState>,
|
temps: &'a IndexVec<Local, TempState>,
|
||||||
|
|
||||||
/// Explicit promotion happens e.g. for constant arguments declared via
|
|
||||||
/// `rustc_args_required_const`.
|
|
||||||
/// Implicit promotion has almost the same rules, except that disallows `const fn`
|
|
||||||
/// except for those marked `#[rustc_promotable]`. This is to avoid changing
|
|
||||||
/// a legitimate run-time operation into a failing compile-time operation
|
|
||||||
/// e.g. due to addresses being compared inside the function.
|
|
||||||
explicit: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::ops::Deref for Validator<'a, 'tcx> {
|
impl std::ops::Deref for Validator<'a, 'tcx> {
|
||||||
|
@ -280,8 +212,6 @@ impl<'tcx> Validator<'_, 'tcx> {
|
||||||
fn validate_candidate(&self, candidate: Candidate) -> Result<(), Unpromotable> {
|
fn validate_candidate(&self, candidate: Candidate) -> Result<(), Unpromotable> {
|
||||||
match candidate {
|
match candidate {
|
||||||
Candidate::Ref(loc) => {
|
Candidate::Ref(loc) => {
|
||||||
assert!(!self.explicit);
|
|
||||||
|
|
||||||
let statement = &self.body[loc.block].statements[loc.statement_index];
|
let statement = &self.body[loc.block].statements[loc.statement_index];
|
||||||
match &statement.kind {
|
match &statement.kind {
|
||||||
StatementKind::Assign(box (_, Rvalue::Ref(_, kind, place))) => {
|
StatementKind::Assign(box (_, Rvalue::Ref(_, kind, place))) => {
|
||||||
|
@ -310,15 +240,6 @@ impl<'tcx> Validator<'_, 'tcx> {
|
||||||
_ => bug!(),
|
_ => bug!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Candidate::Argument { bb, index } => {
|
|
||||||
assert!(self.explicit);
|
|
||||||
|
|
||||||
let terminator = self.body[bb].terminator();
|
|
||||||
match &terminator.kind {
|
|
||||||
TerminatorKind::Call { args, .. } => self.validate_operand(&args[index]),
|
|
||||||
_ => bug!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -448,12 +369,10 @@ impl<'tcx> Validator<'_, 'tcx> {
|
||||||
ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {}
|
ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {}
|
||||||
|
|
||||||
ProjectionElem::Index(local) => {
|
ProjectionElem::Index(local) => {
|
||||||
if !self.explicit {
|
|
||||||
let mut promotable = false;
|
let mut promotable = false;
|
||||||
// Only accept if we can predict the index and are indexing an array.
|
// Only accept if we can predict the index and are indexing an array.
|
||||||
let val = if let TempState::Defined { location: loc, .. } =
|
let val =
|
||||||
self.temps[local]
|
if let TempState::Defined { location: loc, .. } = self.temps[local] {
|
||||||
{
|
|
||||||
let block = &self.body[loc.block];
|
let block = &self.body[loc.block];
|
||||||
if loc.statement_index < block.statements.len() {
|
if loc.statement_index < block.statements.len() {
|
||||||
let statement = &block.statements[loc.statement_index];
|
let statement = &block.statements[loc.statement_index];
|
||||||
|
@ -476,8 +395,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
||||||
match ty.kind() {
|
match ty.kind() {
|
||||||
ty::Array(_, len) => {
|
ty::Array(_, len) => {
|
||||||
// It's an array; determine its length.
|
// It's an array; determine its length.
|
||||||
if let Some(len) =
|
if let Some(len) = len.try_eval_usize(self.tcx, self.param_env)
|
||||||
len.try_eval_usize(self.tcx, self.param_env)
|
|
||||||
{
|
{
|
||||||
// If the index is in-bounds, go ahead.
|
// If the index is in-bounds, go ahead.
|
||||||
if idx < len {
|
if idx < len {
|
||||||
|
@ -491,7 +409,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
||||||
if !promotable {
|
if !promotable {
|
||||||
return Err(Unpromotable);
|
return Err(Unpromotable);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
self.validate_local(local)?;
|
self.validate_local(local)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -636,7 +554,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
||||||
|
|
||||||
match op {
|
match op {
|
||||||
BinOp::Div | BinOp::Rem => {
|
BinOp::Div | BinOp::Rem => {
|
||||||
if !self.explicit && lhs_ty.is_integral() {
|
if lhs_ty.is_integral() {
|
||||||
// Integer division: the RHS must be a non-zero const.
|
// Integer division: the RHS must be a non-zero const.
|
||||||
let const_val = match rhs {
|
let const_val = match rhs {
|
||||||
Operand::Constant(c) => {
|
Operand::Constant(c) => {
|
||||||
|
@ -721,10 +639,9 @@ impl<'tcx> Validator<'_, 'tcx> {
|
||||||
) -> Result<(), Unpromotable> {
|
) -> Result<(), Unpromotable> {
|
||||||
let fn_ty = callee.ty(self.body, self.tcx);
|
let fn_ty = callee.ty(self.body, self.tcx);
|
||||||
|
|
||||||
// When doing explicit promotion and inside const/static items, we promote all (eligible) function calls.
|
// Inside const/static items, we promote all (eligible) function calls.
|
||||||
// Everywhere else, we require `#[rustc_promotable]` on the callee.
|
// Everywhere else, we require `#[rustc_promotable]` on the callee.
|
||||||
let promote_all_const_fn = self.explicit
|
let promote_all_const_fn = matches!(
|
||||||
|| matches!(
|
|
||||||
self.const_kind,
|
self.const_kind,
|
||||||
Some(hir::ConstContext::Static(_) | hir::ConstContext::Const)
|
Some(hir::ConstContext::Static(_) | hir::ConstContext::Const)
|
||||||
);
|
);
|
||||||
|
@ -765,41 +682,12 @@ pub fn validate_candidates(
|
||||||
temps: &IndexVec<Local, TempState>,
|
temps: &IndexVec<Local, TempState>,
|
||||||
candidates: &[Candidate],
|
candidates: &[Candidate],
|
||||||
) -> Vec<Candidate> {
|
) -> Vec<Candidate> {
|
||||||
let mut validator = Validator { ccx, temps, explicit: false };
|
let validator = Validator { ccx, temps };
|
||||||
|
|
||||||
candidates
|
candidates
|
||||||
.iter()
|
.iter()
|
||||||
.copied()
|
.copied()
|
||||||
.filter(|&candidate| {
|
.filter(|&candidate| validator.validate_candidate(candidate).is_ok())
|
||||||
validator.explicit = candidate.forces_explicit_promotion();
|
|
||||||
|
|
||||||
// FIXME(eddyb) also emit the errors for shuffle indices
|
|
||||||
// and `#[rustc_args_required_const]` arguments here.
|
|
||||||
|
|
||||||
let is_promotable = validator.validate_candidate(candidate).is_ok();
|
|
||||||
|
|
||||||
// If we use explicit validation, we carry the risk of turning a legitimate run-time
|
|
||||||
// operation into a failing compile-time operation. Make sure that does not happen
|
|
||||||
// by asserting that there is no possible run-time behavior here in case promotion
|
|
||||||
// fails.
|
|
||||||
if validator.explicit && !is_promotable {
|
|
||||||
ccx.tcx.sess.delay_span_bug(
|
|
||||||
ccx.body.span,
|
|
||||||
"Explicit promotion requested, but failed to promote",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
match candidate {
|
|
||||||
Candidate::Argument { bb, index } if !is_promotable => {
|
|
||||||
let span = ccx.body[bb].terminator().source_info.span;
|
|
||||||
let msg = format!("argument {} is required to be a constant", index + 1);
|
|
||||||
ccx.tcx.sess.span_err(span, &msg);
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
|
|
||||||
is_promotable
|
|
||||||
})
|
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1039,26 +927,6 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
||||||
_ => bug!(),
|
_ => bug!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Candidate::Argument { bb, index } => {
|
|
||||||
let terminator = blocks[bb].terminator_mut();
|
|
||||||
match terminator.kind {
|
|
||||||
TerminatorKind::Call { ref mut args, .. } => {
|
|
||||||
let ty = args[index].ty(local_decls, self.tcx);
|
|
||||||
let span = terminator.source_info.span;
|
|
||||||
|
|
||||||
Rvalue::Use(mem::replace(&mut args[index], promoted_operand(ty, span)))
|
|
||||||
}
|
|
||||||
// We expected a `TerminatorKind::Call` for which we'd like to promote an
|
|
||||||
// argument. `qualify_consts` saw a `TerminatorKind::Call` here, but
|
|
||||||
// we are seeing a `Goto`. That means that the `promote_temps` method
|
|
||||||
// already promoted this call away entirely. This case occurs when calling
|
|
||||||
// a function requiring a constant argument and as that constant value
|
|
||||||
// providing a value whose computation contains another call to a function
|
|
||||||
// requiring a constant argument.
|
|
||||||
TerminatorKind::Goto { .. } => return None,
|
|
||||||
_ => bug!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1113,7 +981,6 @@ pub fn promote_candidates<'tcx>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Candidate::Argument { .. } => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Declare return place local so that `mir::Body::new` doesn't complain.
|
// Declare return place local so that `mir::Body::new` doesn't complain.
|
||||||
|
|
|
@ -13,9 +13,7 @@ use rustc_errors::{pluralize, struct_span_err, Applicability};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::LocalDefId;
|
use rustc_hir::def_id::LocalDefId;
|
||||||
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
|
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
|
||||||
use rustc_hir::{
|
use rustc_hir::{self, FnSig, ForeignItem, HirId, Item, ItemKind, TraitItem, CRATE_HIR_ID};
|
||||||
self, FnSig, ForeignItem, ForeignItemKind, HirId, Item, ItemKind, TraitItem, CRATE_HIR_ID,
|
|
||||||
};
|
|
||||||
use rustc_hir::{MethodKind, Target};
|
use rustc_hir::{MethodKind, Target};
|
||||||
use rustc_session::lint::builtin::{
|
use rustc_session::lint::builtin::{
|
||||||
CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, UNUSED_ATTRIBUTES,
|
CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, UNUSED_ATTRIBUTES,
|
||||||
|
@ -81,9 +79,6 @@ impl CheckAttrVisitor<'tcx> {
|
||||||
sym::doc => self.check_doc_attrs(attr, hir_id, target, &mut specified_inline),
|
sym::doc => self.check_doc_attrs(attr, hir_id, target, &mut specified_inline),
|
||||||
sym::no_link => self.check_no_link(hir_id, &attr, span, target),
|
sym::no_link => self.check_no_link(hir_id, &attr, span, target),
|
||||||
sym::export_name => self.check_export_name(hir_id, &attr, span, target),
|
sym::export_name => self.check_export_name(hir_id, &attr, span, target),
|
||||||
sym::rustc_args_required_const => {
|
|
||||||
self.check_rustc_args_required_const(&attr, span, target, item)
|
|
||||||
}
|
|
||||||
sym::rustc_layout_scalar_valid_range_start
|
sym::rustc_layout_scalar_valid_range_start
|
||||||
| sym::rustc_layout_scalar_valid_range_end => {
|
| sym::rustc_layout_scalar_valid_range_end => {
|
||||||
self.check_rustc_layout_scalar_valid_range(&attr, span, target)
|
self.check_rustc_layout_scalar_valid_range(&attr, span, target)
|
||||||
|
@ -948,79 +943,6 @@ impl CheckAttrVisitor<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if `#[rustc_args_required_const]` is applied to a function and has a valid argument.
|
|
||||||
fn check_rustc_args_required_const(
|
|
||||||
&self,
|
|
||||||
attr: &Attribute,
|
|
||||||
span: &Span,
|
|
||||||
target: Target,
|
|
||||||
item: Option<ItemLike<'_>>,
|
|
||||||
) -> bool {
|
|
||||||
let is_function = matches!(target, Target::Fn | Target::Method(..) | Target::ForeignFn);
|
|
||||||
if !is_function {
|
|
||||||
self.tcx
|
|
||||||
.sess
|
|
||||||
.struct_span_err(attr.span, "attribute should be applied to a function")
|
|
||||||
.span_label(*span, "not a function")
|
|
||||||
.emit();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let list = match attr.meta_item_list() {
|
|
||||||
// The attribute form is validated on AST.
|
|
||||||
None => return false,
|
|
||||||
Some(it) => it,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut invalid_args = vec![];
|
|
||||||
for meta in list {
|
|
||||||
if let Some(LitKind::Int(val, _)) = meta.literal().map(|lit| &lit.kind) {
|
|
||||||
if let Some(ItemLike::Item(Item {
|
|
||||||
kind: ItemKind::Fn(FnSig { decl, .. }, ..),
|
|
||||||
..
|
|
||||||
}))
|
|
||||||
| Some(ItemLike::ForeignItem(ForeignItem {
|
|
||||||
kind: ForeignItemKind::Fn(decl, ..),
|
|
||||||
..
|
|
||||||
})) = item
|
|
||||||
{
|
|
||||||
let arg_count = decl.inputs.len() as u128;
|
|
||||||
if *val >= arg_count {
|
|
||||||
let span = meta.span();
|
|
||||||
self.tcx
|
|
||||||
.sess
|
|
||||||
.struct_span_err(span, "index exceeds number of arguments")
|
|
||||||
.span_label(
|
|
||||||
span,
|
|
||||||
format!(
|
|
||||||
"there {} only {} argument{}",
|
|
||||||
if arg_count != 1 { "are" } else { "is" },
|
|
||||||
arg_count,
|
|
||||||
pluralize!(arg_count)
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
bug!("should be a function item");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
invalid_args.push(meta.span());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !invalid_args.is_empty() {
|
|
||||||
self.tcx
|
|
||||||
.sess
|
|
||||||
.struct_span_err(invalid_args, "arguments should be non-negative integers")
|
|
||||||
.emit();
|
|
||||||
false
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_rustc_layout_scalar_valid_range(
|
fn check_rustc_layout_scalar_valid_range(
|
||||||
&self,
|
&self,
|
||||||
attr: &Attribute,
|
attr: &Attribute,
|
||||||
|
|
|
@ -994,7 +994,6 @@ symbols! {
|
||||||
rustc_allocator,
|
rustc_allocator,
|
||||||
rustc_allocator_nounwind,
|
rustc_allocator_nounwind,
|
||||||
rustc_allow_const_fn_unstable,
|
rustc_allow_const_fn_unstable,
|
||||||
rustc_args_required_const,
|
|
||||||
rustc_attrs,
|
rustc_attrs,
|
||||||
rustc_builtin_macro,
|
rustc_builtin_macro,
|
||||||
rustc_capture_analysis,
|
rustc_capture_analysis,
|
||||||
|
|
|
@ -1537,8 +1537,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.check_rustc_args_require_const(def_id, hir_id, span);
|
|
||||||
|
|
||||||
debug!("instantiate_value_path: type of {:?} is {:?}", hir_id, ty_substituted);
|
debug!("instantiate_value_path: type of {:?} is {:?}", hir_id, ty_substituted);
|
||||||
self.write_substs(hir_id, substs);
|
self.write_substs(hir_id, substs);
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ use rustc_middle::ty::adjustment::AllowTwoPhase;
|
||||||
use rustc_middle::ty::fold::TypeFoldable;
|
use rustc_middle::ty::fold::TypeFoldable;
|
||||||
use rustc_middle::ty::{self, Ty};
|
use rustc_middle::ty::{self, Ty};
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_span::symbol::{sym, Ident};
|
use rustc_span::symbol::Ident;
|
||||||
use rustc_span::{self, MultiSpan, Span};
|
use rustc_span::{self, MultiSpan, Span};
|
||||||
use rustc_trait_selection::traits::{self, ObligationCauseCode, StatementAsExpression};
|
use rustc_trait_selection::traits::{self, ObligationCauseCode, StatementAsExpression};
|
||||||
|
|
||||||
|
@ -720,34 +720,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
ty
|
ty
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(in super::super) fn check_rustc_args_require_const(
|
|
||||||
&self,
|
|
||||||
def_id: DefId,
|
|
||||||
hir_id: hir::HirId,
|
|
||||||
span: Span,
|
|
||||||
) {
|
|
||||||
// We're only interested in functions tagged with
|
|
||||||
// #[rustc_args_required_const], so ignore anything that's not.
|
|
||||||
if !self.tcx.has_attr(def_id, sym::rustc_args_required_const) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If our calling expression is indeed the function itself, we're good!
|
|
||||||
// If not, generate an error that this can only be called directly.
|
|
||||||
if let Node::Expr(expr) = self.tcx.hir().get(self.tcx.hir().get_parent_node(hir_id)) {
|
|
||||||
if let ExprKind::Call(ref callee, ..) = expr.kind {
|
|
||||||
if callee.hir_id == hir_id {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.tcx.sess.span_err(
|
|
||||||
span,
|
|
||||||
"this function can only be invoked directly, not through a function pointer",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A common error is to add an extra semicolon:
|
/// A common error is to add an extra semicolon:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 6c4f4e1990b76be8a07bde1956d2e3452fd55ee4
|
Subproject commit c14e98417feb406df66e821ccd81e1293b4baa6f
|
|
@ -11,7 +11,8 @@ extern "platform-intrinsic" {
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
unsafe {
|
unsafe {
|
||||||
let _: I32x2 = simd_shuffle2(I32x2(1, 2), I32x2(3, 4), [0, 0]);
|
const IDX: [u32; 2] = [0, 0];
|
||||||
let _: I32x2 = simd_shuffle2(I32x2(1, 2), I32x2(3, 4), [0, 0]);
|
let _: I32x2 = simd_shuffle2(I32x2(1, 2), I32x2(3, 4), IDX);
|
||||||
|
let _: I32x2 = simd_shuffle2(I32x2(1, 2), I32x2(3, 4), IDX);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
// check-pass
|
|
||||||
|
|
||||||
#![feature(rustc_attrs)]
|
|
||||||
|
|
||||||
#[rustc_args_required_const(0)]
|
|
||||||
pub const fn a(value: u8) -> u8 {
|
|
||||||
value
|
|
||||||
}
|
|
||||||
|
|
||||||
#[rustc_args_required_const(0)]
|
|
||||||
pub fn b(_: u8) {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let _ = b(a(0));
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
#![feature(rustc_attrs)]
|
|
||||||
|
|
||||||
#[rustc_args_required_const(0)]
|
|
||||||
fn foo(_imm8: i32) {}
|
|
||||||
|
|
||||||
fn bar() {
|
|
||||||
let imm8 = 3;
|
|
||||||
foo(imm8) //~ ERROR argument 1 is required to be a constant
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {}
|
|
|
@ -1,8 +0,0 @@
|
||||||
error: argument 1 is required to be a constant
|
|
||||||
--> $DIR/const_arg_local.rs:8:5
|
|
||||||
|
|
|
||||||
LL | foo(imm8)
|
|
||||||
| ^^^^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
#![feature(rustc_attrs)]
|
|
||||||
|
|
||||||
#[rustc_args_required_const(0)]
|
|
||||||
fn foo(_imm8: i32) {}
|
|
||||||
|
|
||||||
fn bar() {
|
|
||||||
foo(*&mut 42) //~ ERROR argument 1 is required to be a constant
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {}
|
|
|
@ -1,8 +0,0 @@
|
||||||
error: argument 1 is required to be a constant
|
|
||||||
--> $DIR/const_arg_promotable.rs:7:5
|
|
||||||
|
|
|
||||||
LL | foo(*&mut 42)
|
|
||||||
| ^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
// This test is a regression test for a bug where we only checked function calls in no-const
|
|
||||||
// functions for `rustc_args_required_const` arguments. This meant that even though `bar` needs its
|
|
||||||
// argument to be const, inside a const fn (callable at runtime), the value for it may come from a
|
|
||||||
// non-constant (namely an argument to the const fn).
|
|
||||||
|
|
||||||
#![feature(rustc_attrs)]
|
|
||||||
const fn foo(a: i32) {
|
|
||||||
bar(a); //~ ERROR argument 1 is required to be a constant
|
|
||||||
}
|
|
||||||
|
|
||||||
#[rustc_args_required_const(0)]
|
|
||||||
const fn bar(_: i32) {}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
// this function call will pass a runtime-value (number of program arguments) to `foo`, which
|
|
||||||
// will in turn forward it to `bar`, which expects a compile-time argument
|
|
||||||
foo(std::env::args().count() as i32);
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
error: argument 1 is required to be a constant
|
|
||||||
--> $DIR/const_arg_promotable2.rs:8:5
|
|
||||||
|
|
|
||||||
LL | bar(a);
|
|
||||||
| ^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
#![feature(rustc_attrs)]
|
|
||||||
|
|
||||||
#[rustc_args_required_const(0)]
|
|
||||||
fn foo(_imm8: i32) {}
|
|
||||||
|
|
||||||
fn bar(imm8: i32) {
|
|
||||||
foo(imm8) //~ ERROR argument 1 is required to be a constant
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {}
|
|
|
@ -1,8 +0,0 @@
|
||||||
error: argument 1 is required to be a constant
|
|
||||||
--> $DIR/const_arg_wrapper.rs:7:5
|
|
||||||
|
|
|
||||||
LL | foo(imm8)
|
|
||||||
| ^^^^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
#![feature(rustc_attrs)]
|
|
||||||
|
|
||||||
#[rustc_args_required_const(0)]
|
|
||||||
fn foo(_a: i32) {
|
|
||||||
}
|
|
||||||
|
|
||||||
#[rustc_args_required_const(1)]
|
|
||||||
fn bar(_a: i32, _b: i32) {
|
|
||||||
}
|
|
||||||
|
|
||||||
const A: i32 = 3;
|
|
||||||
|
|
||||||
const fn baz() -> i32 {
|
|
||||||
3
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
foo(2);
|
|
||||||
foo(2 + 3);
|
|
||||||
const BAZ: i32 = baz();
|
|
||||||
foo(BAZ);
|
|
||||||
let a = 4;
|
|
||||||
foo(A);
|
|
||||||
foo(a); //~ ERROR: argument 1 is required to be a constant
|
|
||||||
bar(a, 3);
|
|
||||||
bar(a, a); //~ ERROR: argument 2 is required to be a constant
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
error: argument 1 is required to be a constant
|
|
||||||
--> $DIR/rustc-args-required-const.rs:24:5
|
|
||||||
|
|
|
||||||
LL | foo(a);
|
|
||||||
| ^^^^^^
|
|
||||||
|
|
||||||
error: argument 2 is required to be a constant
|
|
||||||
--> $DIR/rustc-args-required-const.rs:26:5
|
|
||||||
|
|
|
||||||
LL | bar(a, a);
|
|
||||||
| ^^^^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
#![feature(rustc_attrs)]
|
|
||||||
|
|
||||||
#[rustc_args_required_const(0)] //~ ERROR index exceeds number of arguments
|
|
||||||
fn foo1() {}
|
|
||||||
|
|
||||||
#[rustc_args_required_const(1)] //~ ERROR index exceeds number of arguments
|
|
||||||
fn foo2(_: u8) {}
|
|
||||||
|
|
||||||
#[rustc_args_required_const(a)] //~ ERROR arguments should be non-negative integers
|
|
||||||
fn foo4() {}
|
|
||||||
|
|
||||||
#[rustc_args_required_const(1, a, 2, b)] //~ ERROR arguments should be non-negative integers
|
|
||||||
fn foo5(_: u8, _: u8, _: u8) {}
|
|
||||||
|
|
||||||
#[rustc_args_required_const(0)] //~ ERROR attribute should be applied to a function
|
|
||||||
struct S;
|
|
||||||
|
|
||||||
#[rustc_args_required_const(0usize)] //~ ERROR suffixed literals are not allowed in attributes
|
|
||||||
fn foo6(_: u8) {}
|
|
||||||
|
|
||||||
extern {
|
|
||||||
#[rustc_args_required_const(1)] //~ ERROR index exceeds number of arguments
|
|
||||||
fn foo7(_: u8);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[rustc_args_required_const] //~ ERROR malformed `rustc_args_required_const` attribute
|
|
||||||
fn bar1() {}
|
|
||||||
|
|
||||||
#[rustc_args_required_const = 1] //~ ERROR malformed `rustc_args_required_const` attribute
|
|
||||||
fn bar2() {}
|
|
||||||
|
|
||||||
fn main() {}
|
|
|
@ -1,60 +0,0 @@
|
||||||
error: suffixed literals are not allowed in attributes
|
|
||||||
--> $DIR/invalid-rustc_args_required_const-arguments.rs:18:29
|
|
||||||
|
|
|
||||||
LL | #[rustc_args_required_const(0usize)]
|
|
||||||
| ^^^^^^
|
|
||||||
|
|
|
||||||
= help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
|
|
||||||
|
|
||||||
error: malformed `rustc_args_required_const` attribute input
|
|
||||||
--> $DIR/invalid-rustc_args_required_const-arguments.rs:26:1
|
|
||||||
|
|
|
||||||
LL | #[rustc_args_required_const]
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_args_required_const(N)]`
|
|
||||||
|
|
||||||
error: malformed `rustc_args_required_const` attribute input
|
|
||||||
--> $DIR/invalid-rustc_args_required_const-arguments.rs:29:1
|
|
||||||
|
|
|
||||||
LL | #[rustc_args_required_const = 1]
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_args_required_const(N)]`
|
|
||||||
|
|
||||||
error: index exceeds number of arguments
|
|
||||||
--> $DIR/invalid-rustc_args_required_const-arguments.rs:3:29
|
|
||||||
|
|
|
||||||
LL | #[rustc_args_required_const(0)]
|
|
||||||
| ^ there are only 0 arguments
|
|
||||||
|
|
||||||
error: index exceeds number of arguments
|
|
||||||
--> $DIR/invalid-rustc_args_required_const-arguments.rs:6:29
|
|
||||||
|
|
|
||||||
LL | #[rustc_args_required_const(1)]
|
|
||||||
| ^ there is only 1 argument
|
|
||||||
|
|
||||||
error: arguments should be non-negative integers
|
|
||||||
--> $DIR/invalid-rustc_args_required_const-arguments.rs:9:29
|
|
||||||
|
|
|
||||||
LL | #[rustc_args_required_const(a)]
|
|
||||||
| ^
|
|
||||||
|
|
||||||
error: arguments should be non-negative integers
|
|
||||||
--> $DIR/invalid-rustc_args_required_const-arguments.rs:12:32
|
|
||||||
|
|
|
||||||
LL | #[rustc_args_required_const(1, a, 2, b)]
|
|
||||||
| ^ ^
|
|
||||||
|
|
||||||
error: attribute should be applied to a function
|
|
||||||
--> $DIR/invalid-rustc_args_required_const-arguments.rs:15:1
|
|
||||||
|
|
|
||||||
LL | #[rustc_args_required_const(0)]
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
LL | struct S;
|
|
||||||
| --------- not a function
|
|
||||||
|
|
||||||
error: index exceeds number of arguments
|
|
||||||
--> $DIR/invalid-rustc_args_required_const-arguments.rs:22:33
|
|
||||||
|
|
|
||||||
LL | #[rustc_args_required_const(1)]
|
|
||||||
| ^ there is only 1 argument
|
|
||||||
|
|
||||||
error: aborting due to 9 previous errors
|
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
// run-pass
|
|
||||||
// ignore-emscripten FIXME(#45351)
|
|
||||||
|
|
||||||
#![feature(platform_intrinsics, repr_simd)]
|
|
||||||
|
|
||||||
extern "platform-intrinsic" {
|
|
||||||
fn simd_shuffle2<T, U>(x: T, y: T, idx: [u32; 2]) -> U;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(simd)]
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
struct u64x2(u64, u64);
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let a = u64x2(1, 2);
|
|
||||||
let r: u64x2 = unsafe { simd_shuffle2(a, a, [0-0, 0-0]) };
|
|
||||||
assert_eq!(r.0, 1);
|
|
||||||
assert_eq!(r.1, 1);
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
#![feature(rustc_attrs)]
|
|
||||||
|
|
||||||
#[rustc_args_required_const(0)]
|
|
||||||
fn foo(_a: i32) {
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let a = foo; //~ ERROR: this function can only be invoked directly
|
|
||||||
a(2);
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
error: this function can only be invoked directly, not through a function pointer
|
|
||||||
--> $DIR/rustc-args-required-const2.rs:8:13
|
|
||||||
|
|
|
||||||
LL | let a = foo;
|
|
||||||
| ^^^
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
|
||||||
|
|
|
@ -50,25 +50,28 @@ fn main() {
|
||||||
simd_extract::<_, f32>(x, 0);
|
simd_extract::<_, f32>(x, 0);
|
||||||
//~^ ERROR expected return type `i32` (element of input `i32x4`), found `f32`
|
//~^ ERROR expected return type `i32` (element of input `i32x4`), found `f32`
|
||||||
|
|
||||||
simd_shuffle2::<i32, i32>(0, 0, [0; 2]);
|
const IDX2: [u32; 2] = [0; 2];
|
||||||
|
simd_shuffle2::<i32, i32>(0, 0, IDX2);
|
||||||
//~^ ERROR expected SIMD input type, found non-SIMD `i32`
|
//~^ ERROR expected SIMD input type, found non-SIMD `i32`
|
||||||
simd_shuffle4::<i32, i32>(0, 0, [0; 4]);
|
const IDX4: [u32; 4] = [0; 4];
|
||||||
|
simd_shuffle4::<i32, i32>(0, 0, IDX4);
|
||||||
//~^ ERROR expected SIMD input type, found non-SIMD `i32`
|
//~^ ERROR expected SIMD input type, found non-SIMD `i32`
|
||||||
simd_shuffle8::<i32, i32>(0, 0, [0; 8]);
|
const IDX8: [u32; 8] = [0; 8];
|
||||||
|
simd_shuffle8::<i32, i32>(0, 0, IDX8);
|
||||||
//~^ ERROR expected SIMD input type, found non-SIMD `i32`
|
//~^ ERROR expected SIMD input type, found non-SIMD `i32`
|
||||||
|
|
||||||
simd_shuffle2::<_, f32x2>(x, x, [0; 2]);
|
simd_shuffle2::<_, f32x2>(x, x, IDX2);
|
||||||
//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32`
|
//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32`
|
||||||
simd_shuffle4::<_, f32x4>(x, x, [0; 4]);
|
simd_shuffle4::<_, f32x4>(x, x, IDX4);
|
||||||
//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32`
|
//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32`
|
||||||
simd_shuffle8::<_, f32x8>(x, x, [0; 8]);
|
simd_shuffle8::<_, f32x8>(x, x, IDX8);
|
||||||
//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32`
|
//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32`
|
||||||
|
|
||||||
simd_shuffle2::<_, i32x8>(x, x, [0; 2]);
|
simd_shuffle2::<_, i32x8>(x, x, IDX2);
|
||||||
//~^ ERROR expected return type of length 2, found `i32x8` with length 8
|
//~^ ERROR expected return type of length 2, found `i32x8` with length 8
|
||||||
simd_shuffle4::<_, i32x8>(x, x, [0; 4]);
|
simd_shuffle4::<_, i32x8>(x, x, IDX4);
|
||||||
//~^ ERROR expected return type of length 4, found `i32x8` with length 8
|
//~^ ERROR expected return type of length 4, found `i32x8` with length 8
|
||||||
simd_shuffle8::<_, i32x2>(x, x, [0; 8]);
|
simd_shuffle8::<_, i32x2>(x, x, IDX8);
|
||||||
//~^ ERROR expected return type of length 8, found `i32x2` with length 2
|
//~^ ERROR expected return type of length 8, found `i32x2` with length 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,58 +17,58 @@ LL | simd_extract::<_, f32>(x, 0);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error[E0511]: invalid monomorphization of `simd_shuffle2` intrinsic: expected SIMD input type, found non-SIMD `i32`
|
error[E0511]: invalid monomorphization of `simd_shuffle2` intrinsic: expected SIMD input type, found non-SIMD `i32`
|
||||||
--> $DIR/simd-intrinsic-generic-elements.rs:53:9
|
--> $DIR/simd-intrinsic-generic-elements.rs:54:9
|
||||||
|
|
|
|
||||||
LL | simd_shuffle2::<i32, i32>(0, 0, [0; 2]);
|
LL | simd_shuffle2::<i32, i32>(0, 0, IDX2);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error[E0511]: invalid monomorphization of `simd_shuffle4` intrinsic: expected SIMD input type, found non-SIMD `i32`
|
error[E0511]: invalid monomorphization of `simd_shuffle4` intrinsic: expected SIMD input type, found non-SIMD `i32`
|
||||||
--> $DIR/simd-intrinsic-generic-elements.rs:55:9
|
|
||||||
|
|
|
||||||
LL | simd_shuffle4::<i32, i32>(0, 0, [0; 4]);
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error[E0511]: invalid monomorphization of `simd_shuffle8` intrinsic: expected SIMD input type, found non-SIMD `i32`
|
|
||||||
--> $DIR/simd-intrinsic-generic-elements.rs:57:9
|
--> $DIR/simd-intrinsic-generic-elements.rs:57:9
|
||||||
|
|
|
|
||||||
LL | simd_shuffle8::<i32, i32>(0, 0, [0; 8]);
|
LL | simd_shuffle4::<i32, i32>(0, 0, IDX4);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error[E0511]: invalid monomorphization of `simd_shuffle2` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32`
|
error[E0511]: invalid monomorphization of `simd_shuffle8` intrinsic: expected SIMD input type, found non-SIMD `i32`
|
||||||
--> $DIR/simd-intrinsic-generic-elements.rs:60:9
|
--> $DIR/simd-intrinsic-generic-elements.rs:60:9
|
||||||
|
|
|
|
||||||
LL | simd_shuffle2::<_, f32x2>(x, x, [0; 2]);
|
LL | simd_shuffle8::<i32, i32>(0, 0, IDX8);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0511]: invalid monomorphization of `simd_shuffle2` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32`
|
||||||
|
--> $DIR/simd-intrinsic-generic-elements.rs:63:9
|
||||||
|
|
|
||||||
|
LL | simd_shuffle2::<_, f32x2>(x, x, IDX2);
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error[E0511]: invalid monomorphization of `simd_shuffle4` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32`
|
error[E0511]: invalid monomorphization of `simd_shuffle4` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32`
|
||||||
--> $DIR/simd-intrinsic-generic-elements.rs:62:9
|
--> $DIR/simd-intrinsic-generic-elements.rs:65:9
|
||||||
|
|
|
|
||||||
LL | simd_shuffle4::<_, f32x4>(x, x, [0; 4]);
|
LL | simd_shuffle4::<_, f32x4>(x, x, IDX4);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error[E0511]: invalid monomorphization of `simd_shuffle8` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32`
|
error[E0511]: invalid monomorphization of `simd_shuffle8` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32`
|
||||||
--> $DIR/simd-intrinsic-generic-elements.rs:64:9
|
|
||||||
|
|
|
||||||
LL | simd_shuffle8::<_, f32x8>(x, x, [0; 8]);
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error[E0511]: invalid monomorphization of `simd_shuffle2` intrinsic: expected return type of length 2, found `i32x8` with length 8
|
|
||||||
--> $DIR/simd-intrinsic-generic-elements.rs:67:9
|
--> $DIR/simd-intrinsic-generic-elements.rs:67:9
|
||||||
|
|
|
|
||||||
LL | simd_shuffle2::<_, i32x8>(x, x, [0; 2]);
|
LL | simd_shuffle8::<_, f32x8>(x, x, IDX8);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0511]: invalid monomorphization of `simd_shuffle2` intrinsic: expected return type of length 2, found `i32x8` with length 8
|
||||||
|
--> $DIR/simd-intrinsic-generic-elements.rs:70:9
|
||||||
|
|
|
||||||
|
LL | simd_shuffle2::<_, i32x8>(x, x, IDX2);
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error[E0511]: invalid monomorphization of `simd_shuffle4` intrinsic: expected return type of length 4, found `i32x8` with length 8
|
error[E0511]: invalid monomorphization of `simd_shuffle4` intrinsic: expected return type of length 4, found `i32x8` with length 8
|
||||||
--> $DIR/simd-intrinsic-generic-elements.rs:69:9
|
--> $DIR/simd-intrinsic-generic-elements.rs:72:9
|
||||||
|
|
|
|
||||||
LL | simd_shuffle4::<_, i32x8>(x, x, [0; 4]);
|
LL | simd_shuffle4::<_, i32x8>(x, x, IDX4);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error[E0511]: invalid monomorphization of `simd_shuffle8` intrinsic: expected return type of length 8, found `i32x2` with length 2
|
error[E0511]: invalid monomorphization of `simd_shuffle8` intrinsic: expected return type of length 8, found `i32x2` with length 2
|
||||||
--> $DIR/simd-intrinsic-generic-elements.rs:71:9
|
--> $DIR/simd-intrinsic-generic-elements.rs:74:9
|
||||||
|
|
|
|
||||||
LL | simd_shuffle8::<_, i32x2>(x, x, [0; 8]);
|
LL | simd_shuffle8::<_, i32x2>(x, x, IDX8);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to 12 previous errors
|
error: aborting due to 12 previous errors
|
||||||
|
|
||||||
|
|
|
@ -21,5 +21,6 @@ fn main() {
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
unsafe fn inline_me() -> Simd2 {
|
unsafe fn inline_me() -> Simd2 {
|
||||||
simd_shuffle2(Simd2(10, 11), Simd2(12, 13), [0, 3])
|
const IDX: [u32; 2] = [0, 3];
|
||||||
|
simd_shuffle2(Simd2(10, 11), Simd2(12, 13), IDX)
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,8 @@ struct Simd2(u8, u8);
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
unsafe {
|
unsafe {
|
||||||
let p_res: Simd2 = simd_shuffle2(Simd2(10, 11), Simd2(12, 13), [0, 1]);
|
const IDX: [u32; 2] = [0, 1];
|
||||||
|
let p_res: Simd2 = simd_shuffle2(Simd2(10, 11), Simd2(12, 13), IDX);
|
||||||
let a_res: Simd2 = inline_me();
|
let a_res: Simd2 = inline_me();
|
||||||
|
|
||||||
assert_10_11(p_res);
|
assert_10_11(p_res);
|
||||||
|
@ -36,5 +37,6 @@ fn assert_10_13(x: Simd2) {
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
unsafe fn inline_me() -> Simd2 {
|
unsafe fn inline_me() -> Simd2 {
|
||||||
simd_shuffle2(Simd2(10, 11), Simd2(12, 13), [0, 3])
|
const IDX: [u32; 2] = [0, 3];
|
||||||
|
simd_shuffle2(Simd2(10, 11), Simd2(12, 13), IDX)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
// ignore-emscripten FIXME(#45351) hits an LLVM assert
|
// ignore-emscripten FIXME(#45351) hits an LLVM assert
|
||||||
|
|
||||||
#![feature(repr_simd, platform_intrinsics)]
|
#![feature(repr_simd, platform_intrinsics)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
#![feature(inline_const)]
|
||||||
|
|
||||||
#[repr(simd)]
|
#[repr(simd)]
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
|
@ -82,19 +84,19 @@ fn main() {
|
||||||
let y4 = i32x4(140, 141, 142, 143);
|
let y4 = i32x4(140, 141, 142, 143);
|
||||||
let y8 = i32x8(180, 181, 182, 183, 184, 185, 186, 187);
|
let y8 = i32x8(180, 181, 182, 183, 184, 185, 186, 187);
|
||||||
unsafe {
|
unsafe {
|
||||||
all_eq!(simd_shuffle2(x2, y2, [3, 0]), i32x2(121, 20));
|
all_eq!(simd_shuffle2(x2, y2, const { [3u32, 0] }), i32x2(121, 20));
|
||||||
all_eq!(simd_shuffle4(x2, y2, [3, 0, 1, 2]), i32x4(121, 20, 21, 120));
|
all_eq!(simd_shuffle4(x2, y2, const { [3u32, 0, 1, 2] }), i32x4(121, 20, 21, 120));
|
||||||
all_eq!(simd_shuffle8(x2, y2, [3, 0, 1, 2, 1, 2, 3, 0]),
|
all_eq!(simd_shuffle8(x2, y2, const { [3u32, 0, 1, 2, 1, 2, 3, 0] }),
|
||||||
i32x8(121, 20, 21, 120, 21, 120, 121, 20));
|
i32x8(121, 20, 21, 120, 21, 120, 121, 20));
|
||||||
|
|
||||||
all_eq!(simd_shuffle2(x4, y4, [7, 2]), i32x2(143, 42));
|
all_eq!(simd_shuffle2(x4, y4, const { [7u32, 2] }), i32x2(143, 42));
|
||||||
all_eq!(simd_shuffle4(x4, y4, [7, 2, 5, 0]), i32x4(143, 42, 141, 40));
|
all_eq!(simd_shuffle4(x4, y4, const { [7u32, 2, 5, 0] }), i32x4(143, 42, 141, 40));
|
||||||
all_eq!(simd_shuffle8(x4, y4, [7, 2, 5, 0, 3, 6, 4, 1]),
|
all_eq!(simd_shuffle8(x4, y4, const { [7u32, 2, 5, 0, 3, 6, 4, 1] }),
|
||||||
i32x8(143, 42, 141, 40, 43, 142, 140, 41));
|
i32x8(143, 42, 141, 40, 43, 142, 140, 41));
|
||||||
|
|
||||||
all_eq!(simd_shuffle2(x8, y8, [11, 5]), i32x2(183, 85));
|
all_eq!(simd_shuffle2(x8, y8, const { [11u32, 5] }), i32x2(183, 85));
|
||||||
all_eq!(simd_shuffle4(x8, y8, [11, 5, 15, 0]), i32x4(183, 85, 187, 80));
|
all_eq!(simd_shuffle4(x8, y8, const { [11u32, 5, 15, 0] }), i32x4(183, 85, 187, 80));
|
||||||
all_eq!(simd_shuffle8(x8, y8, [11, 5, 15, 0, 3, 8, 12, 1]),
|
all_eq!(simd_shuffle8(x8, y8, const { [11u32, 5, 15, 0, 3, 8, 12, 1] }),
|
||||||
i32x8(183, 85, 187, 80, 83, 180, 184, 81));
|
i32x8(183, 85, 187, 80, 83, 180, 184, 81));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue