Skip to content

Commit 993322e

Browse files
authored
Rollup merge of #48018 - alexcrichton:require-const-arg, r=eddyb
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!
2 parents 6908fb7 + 27a4e73 commit 993322e

File tree

3 files changed

+89
-11
lines changed

3 files changed

+89
-11
lines changed

src/librustc_mir/transform/promote_consts.rs

+11-8
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,12 @@ pub enum Candidate {
7171
/// Borrow of a constant temporary.
7272
Ref(Location),
7373

74-
/// Array of indices found in the third argument of
75-
/// a call to one of the simd_shuffleN intrinsics.
76-
ShuffleIndices(BasicBlock)
74+
/// Currently applied to function calls where the callee has the unstable
75+
/// `#[rustc_args_required_const]` attribute as well as the SIMD shuffle
76+
/// intrinsic. The intrinsic requires the arguments are indeed constant and
77+
/// the attribute currently provides the semantic requirement that arguments
78+
/// must be constant.
79+
Argument { bb: BasicBlock, index: usize },
7780
}
7881

7982
struct TempCollector<'tcx> {
@@ -303,10 +306,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
303306
_ => bug!()
304307
}
305308
}
306-
Candidate::ShuffleIndices(bb) => {
309+
Candidate::Argument { bb, index } => {
307310
match self.source[bb].terminator_mut().kind {
308311
TerminatorKind::Call { ref mut args, .. } => {
309-
Rvalue::Use(mem::replace(&mut args[2], new_operand))
312+
Rvalue::Use(mem::replace(&mut args[index], new_operand))
310313
}
311314
_ => bug!()
312315
}
@@ -359,15 +362,15 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
359362
}
360363
(statement.source_info.span, dest.ty(mir, tcx).to_ty(tcx))
361364
}
362-
Candidate::ShuffleIndices(bb) => {
365+
Candidate::Argument { bb, index } => {
363366
let terminator = mir[bb].terminator();
364367
let ty = match terminator.kind {
365368
TerminatorKind::Call { ref args, .. } => {
366-
args[2].ty(mir, tcx)
369+
args[index].ty(mir, tcx)
367370
}
368371
_ => {
369372
span_bug!(terminator.source_info.span,
370-
"expected simd_shuffleN call to promote");
373+
"expected call argument to promote");
371374
}
372375
};
373376
(terminator.source_info.span, ty)

src/librustc_mir/transform/qualify_consts.rs

+42-3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use rustc_data_structures::bitvec::BitVector;
1818
use rustc_data_structures::indexed_set::IdxSetBuf;
1919
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
20+
use rustc_data_structures::fx::FxHashSet;
2021
use rustc::hir;
2122
use rustc::hir::def_id::DefId;
2223
use rustc::middle::const_val::ConstVal;
@@ -30,6 +31,7 @@ use rustc::mir::visit::{PlaceContext, Visitor};
3031
use rustc::middle::lang_items;
3132
use syntax::abi::Abi;
3233
use syntax::attr;
34+
use syntax::ast::LitKind;
3335
use syntax::feature_gate::UnstableFeatures;
3436
use syntax_pos::{Span, DUMMY_SP};
3537

@@ -407,7 +409,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
407409
_ => {}
408410
}
409411
}
410-
Candidate::ShuffleIndices(_) => {}
412+
Candidate::Argument { .. } => {}
411413
}
412414
}
413415

@@ -730,8 +732,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
730732
self.visit_operand(func, location);
731733

732734
let fn_ty = func.ty(self.mir, self.tcx);
735+
let mut callee_def_id = None;
733736
let (mut is_shuffle, mut is_const_fn) = (false, None);
734737
if let ty::TyFnDef(def_id, _) = fn_ty.sty {
738+
callee_def_id = Some(def_id);
735739
match self.tcx.fn_sig(def_id).abi() {
736740
Abi::RustIntrinsic |
737741
Abi::PlatformIntrinsic => {
@@ -754,17 +758,39 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
754758
}
755759
}
756760

761+
let constant_arguments = callee_def_id.and_then(|id| {
762+
args_required_const(self.tcx, id)
763+
});
757764
for (i, arg) in args.iter().enumerate() {
758765
self.nest(|this| {
759766
this.visit_operand(arg, location);
760-
if is_shuffle && i == 2 && this.mode == Mode::Fn {
761-
let candidate = Candidate::ShuffleIndices(bb);
767+
if this.mode != Mode::Fn {
768+
return
769+
}
770+
let candidate = Candidate::Argument { bb, index: i };
771+
if is_shuffle && i == 2 {
762772
if this.can_promote() {
763773
this.promotion_candidates.push(candidate);
764774
} else {
765775
span_err!(this.tcx.sess, this.span, E0526,
766776
"shuffle indices are not constant");
767777
}
778+
return
779+
}
780+
781+
let constant_arguments = match constant_arguments.as_ref() {
782+
Some(s) => s,
783+
None => return,
784+
};
785+
if !constant_arguments.contains(&i) {
786+
return
787+
}
788+
if this.can_promote() {
789+
this.promotion_candidates.push(candidate);
790+
} else {
791+
this.tcx.sess.span_err(this.span,
792+
&format!("argument {} is required to be a constant",
793+
i + 1));
768794
}
769795
});
770796
}
@@ -1085,3 +1111,16 @@ impl MirPass for QualifyAndPromoteConstants {
10851111
}
10861112
}
10871113
}
1114+
1115+
fn args_required_const(tcx: TyCtxt, def_id: DefId) -> Option<FxHashSet<usize>> {
1116+
let attrs = tcx.get_attrs(def_id);
1117+
let attr = attrs.iter().find(|a| a.check_name("rustc_args_required_const"))?;
1118+
let mut ret = FxHashSet();
1119+
for meta in attr.meta_item_list()? {
1120+
match meta.literal()?.node {
1121+
LitKind::Int(a, _) => { ret.insert(a as usize); }
1122+
_ => return None,
1123+
}
1124+
}
1125+
Some(ret)
1126+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(attr_literals, rustc_attrs, const_fn)]
12+
13+
#[rustc_args_required_const(0)]
14+
fn foo(_a: i32) {
15+
}
16+
17+
#[rustc_args_required_const(1)]
18+
fn bar(_a: i32, _b: i32) {
19+
}
20+
21+
const A: i32 = 3;
22+
23+
const fn baz() -> i32 {
24+
3
25+
}
26+
27+
fn main() {
28+
foo(2);
29+
foo(2 + 3);
30+
foo(baz());
31+
let a = 4;
32+
foo(A);
33+
foo(a); //~ ERROR: argument 1 is required to be a constant
34+
bar(a, 3);
35+
bar(a, a); //~ ERROR: argument 2 is required to be a constant
36+
}

0 commit comments

Comments
 (0)