mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
rustc: Add #[rustc_args_required_const]
This commit adds a new unstable attribute to the compiler which requires that arguments to a function are always provided as constants. The primary use case for this is SIMD intrinsics where arguments are defined by vendors to be constant and in LLVM they indeed must be constant as well. For now this is mostly just a semantic guarantee in rustc that an argument is a constant when invoked, phases like trans don't actually take advantage of it yet. This means that we'll be able to use this in stdsimd but we won't be able to remove the `constify_*` macros just yet. Hopefully soon though!
This commit is contained in:
parent
b0a396bb0a
commit
27a4e73ca5
@ -71,9 +71,12 @@ pub enum Candidate {
|
||||
/// Borrow of a constant temporary.
|
||||
Ref(Location),
|
||||
|
||||
/// Array of indices found in the third argument of
|
||||
/// a call to one of the simd_shuffleN intrinsics.
|
||||
ShuffleIndices(BasicBlock)
|
||||
/// 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 },
|
||||
}
|
||||
|
||||
struct TempCollector<'tcx> {
|
||||
@ -303,10 +306,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
||||
_ => bug!()
|
||||
}
|
||||
}
|
||||
Candidate::ShuffleIndices(bb) => {
|
||||
Candidate::Argument { bb, index } => {
|
||||
match self.source[bb].terminator_mut().kind {
|
||||
TerminatorKind::Call { ref mut args, .. } => {
|
||||
Rvalue::Use(mem::replace(&mut args[2], new_operand))
|
||||
Rvalue::Use(mem::replace(&mut args[index], new_operand))
|
||||
}
|
||||
_ => bug!()
|
||||
}
|
||||
@ -359,15 +362,15 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
|
||||
}
|
||||
(statement.source_info.span, dest.ty(mir, tcx).to_ty(tcx))
|
||||
}
|
||||
Candidate::ShuffleIndices(bb) => {
|
||||
Candidate::Argument { bb, index } => {
|
||||
let terminator = mir[bb].terminator();
|
||||
let ty = match terminator.kind {
|
||||
TerminatorKind::Call { ref args, .. } => {
|
||||
args[2].ty(mir, tcx)
|
||||
args[index].ty(mir, tcx)
|
||||
}
|
||||
_ => {
|
||||
span_bug!(terminator.source_info.span,
|
||||
"expected simd_shuffleN call to promote");
|
||||
"expected call argument to promote");
|
||||
}
|
||||
};
|
||||
(terminator.source_info.span, ty)
|
||||
|
@ -17,6 +17,7 @@
|
||||
use rustc_data_structures::bitvec::BitVector;
|
||||
use rustc_data_structures::indexed_set::IdxSetBuf;
|
||||
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc::hir;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::middle::const_val::ConstVal;
|
||||
@ -30,6 +31,7 @@ use rustc::mir::visit::{PlaceContext, Visitor};
|
||||
use rustc::middle::lang_items;
|
||||
use syntax::abi::Abi;
|
||||
use syntax::attr;
|
||||
use syntax::ast::LitKind;
|
||||
use syntax::feature_gate::UnstableFeatures;
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
|
||||
@ -407,7 +409,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Candidate::ShuffleIndices(_) => {}
|
||||
Candidate::Argument { .. } => {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -730,8 +732,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
||||
self.visit_operand(func, location);
|
||||
|
||||
let fn_ty = func.ty(self.mir, self.tcx);
|
||||
let mut callee_def_id = None;
|
||||
let (mut is_shuffle, mut is_const_fn) = (false, None);
|
||||
if let ty::TyFnDef(def_id, _) = fn_ty.sty {
|
||||
callee_def_id = Some(def_id);
|
||||
match self.tcx.fn_sig(def_id).abi() {
|
||||
Abi::RustIntrinsic |
|
||||
Abi::PlatformIntrinsic => {
|
||||
@ -754,17 +758,39 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
let constant_arguments = callee_def_id.and_then(|id| {
|
||||
args_required_const(self.tcx, id)
|
||||
});
|
||||
for (i, arg) in args.iter().enumerate() {
|
||||
self.nest(|this| {
|
||||
this.visit_operand(arg, location);
|
||||
if is_shuffle && i == 2 && this.mode == Mode::Fn {
|
||||
let candidate = Candidate::ShuffleIndices(bb);
|
||||
if this.mode != Mode::Fn {
|
||||
return
|
||||
}
|
||||
let candidate = Candidate::Argument { bb, index: i };
|
||||
if is_shuffle && i == 2 {
|
||||
if this.can_promote() {
|
||||
this.promotion_candidates.push(candidate);
|
||||
} else {
|
||||
span_err!(this.tcx.sess, this.span, E0526,
|
||||
"shuffle indices are not constant");
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
let constant_arguments = match constant_arguments.as_ref() {
|
||||
Some(s) => s,
|
||||
None => return,
|
||||
};
|
||||
if !constant_arguments.contains(&i) {
|
||||
return
|
||||
}
|
||||
if this.can_promote() {
|
||||
this.promotion_candidates.push(candidate);
|
||||
} else {
|
||||
this.tcx.sess.span_err(this.span,
|
||||
&format!("argument {} is required to be a constant",
|
||||
i + 1));
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -1085,3 +1111,16 @@ impl MirPass for QualifyAndPromoteConstants {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn args_required_const(tcx: TyCtxt, def_id: DefId) -> Option<FxHashSet<usize>> {
|
||||
let attrs = tcx.get_attrs(def_id);
|
||||
let attr = attrs.iter().find(|a| a.check_name("rustc_args_required_const"))?;
|
||||
let mut ret = FxHashSet();
|
||||
for meta in attr.meta_item_list()? {
|
||||
match meta.literal()?.node {
|
||||
LitKind::Int(a, _) => { ret.insert(a as usize); }
|
||||
_ => return None,
|
||||
}
|
||||
}
|
||||
Some(ret)
|
||||
}
|
||||
|
36
src/test/compile-fail/rustc-args-required-const.rs
Normal file
36
src/test/compile-fail/rustc-args-required-const.rs
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(attr_literals, rustc_attrs, const_fn)]
|
||||
|
||||
#[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);
|
||||
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
|
||||
}
|
Loading…
Reference in New Issue
Block a user