Skip to content

Commit 22e1778

Browse files
committed
rustc_args_required_const is no longer a promotion site
1 parent e1ff91f commit 22e1778

11 files changed

+28
-283
lines changed

compiler/rustc_mir/src/transform/promote_consts.rs

+28-161
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,16 @@
1212
//! initialization and can otherwise silence errors, if
1313
//! move analysis runs after promotion on broken MIR.
1414
15-
use rustc_ast::LitKind;
1615
use rustc_hir as hir;
17-
use rustc_hir::def_id::DefId;
1816
use rustc_middle::mir::traversal::ReversePostorder;
1917
use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
2018
use rustc_middle::mir::*;
2119
use rustc_middle::ty::cast::CastTy;
2220
use rustc_middle::ty::subst::InternalSubsts;
2321
use rustc_middle::ty::{self, List, TyCtxt, TypeFoldable};
24-
use rustc_span::symbol::sym;
2522
use rustc_span::Span;
2623

2724
use rustc_index::vec::{Idx, IndexVec};
28-
use rustc_target::spec::abi::Abi;
2925

3026
use std::cell::Cell;
3127
use std::{cmp, iter, mem};
@@ -101,47 +97,16 @@ impl TempState {
10197
pub enum Candidate {
10298
/// Borrow of a constant temporary, candidate for lifetime extension.
10399
Ref(Location),
104-
105-
/// Currently applied to function calls where the callee has the unstable
106-
/// `#[rustc_args_required_const]` attribute as well as the SIMD shuffle
107-
/// intrinsic. The intrinsic requires the arguments are indeed constant and
108-
/// the attribute currently provides the semantic requirement that arguments
109-
/// must be constant.
110-
Argument { bb: BasicBlock, index: usize },
111100
}
112101

113102
impl Candidate {
114-
/// Returns `true` if we should use the "explicit" rules for promotability for this `Candidate`.
115-
fn forces_explicit_promotion(&self) -> bool {
116-
match self {
117-
Candidate::Ref(_) => false,
118-
Candidate::Argument { .. } => true,
119-
}
120-
}
121-
122103
fn source_info(&self, body: &Body<'_>) -> SourceInfo {
123104
match self {
124105
Candidate::Ref(location) => *body.source_info(*location),
125-
Candidate::Argument { bb, .. } => *body.source_info(body.terminator_loc(*bb)),
126106
}
127107
}
128108
}
129109

130-
fn args_required_const(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Vec<usize>> {
131-
let attrs = tcx.get_attrs(def_id);
132-
let attr = attrs.iter().find(|a| tcx.sess.check_name(a, sym::rustc_args_required_const))?;
133-
let mut ret = vec![];
134-
for meta in attr.meta_item_list()? {
135-
match meta.literal()?.kind {
136-
LitKind::Int(a, _) => {
137-
ret.push(a as usize);
138-
}
139-
_ => bug!("invalid arg index"),
140-
}
141-
}
142-
Some(ret)
143-
}
144-
145110
struct Collector<'a, 'tcx> {
146111
ccx: &'a ConstCx<'a, 'tcx>,
147112
temps: IndexVec<Local, TempState>,
@@ -208,31 +173,6 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> {
208173
_ => {}
209174
}
210175
}
211-
212-
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
213-
self.super_terminator(terminator, location);
214-
215-
if let TerminatorKind::Call { ref func, .. } = terminator.kind {
216-
if let ty::FnDef(def_id, _) = *func.ty(self.ccx.body, self.ccx.tcx).kind() {
217-
let fn_sig = self.ccx.tcx.fn_sig(def_id);
218-
if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = fn_sig.abi() {
219-
let name = self.ccx.tcx.item_name(def_id);
220-
// FIXME(eddyb) use `#[rustc_args_required_const(2)]` for shuffles.
221-
if name.as_str().starts_with("simd_shuffle") {
222-
self.candidates.push(Candidate::Argument { bb: location.block, index: 2 });
223-
224-
return; // Don't double count `simd_shuffle` candidates
225-
}
226-
}
227-
228-
if let Some(constant_args) = args_required_const(self.ccx.tcx, def_id) {
229-
for index in constant_args {
230-
self.candidates.push(Candidate::Argument { bb: location.block, index });
231-
}
232-
}
233-
}
234-
}
235-
}
236176
}
237177

238178
pub fn collect_temps_and_candidates(
@@ -256,14 +196,6 @@ pub fn collect_temps_and_candidates(
256196
struct Validator<'a, 'tcx> {
257197
ccx: &'a ConstCx<'a, 'tcx>,
258198
temps: &'a IndexVec<Local, TempState>,
259-
260-
/// Explicit promotion happens e.g. for constant arguments declared via
261-
/// `rustc_args_required_const`.
262-
/// Implicit promotion has almost the same rules, except that disallows `const fn`
263-
/// except for those marked `#[rustc_promotable]`. This is to avoid changing
264-
/// a legitimate run-time operation into a failing compile-time operation
265-
/// e.g. due to addresses being compared inside the function.
266-
explicit: bool,
267199
}
268200

269201
impl std::ops::Deref for Validator<'a, 'tcx> {
@@ -280,8 +212,6 @@ impl<'tcx> Validator<'_, 'tcx> {
280212
fn validate_candidate(&self, candidate: Candidate) -> Result<(), Unpromotable> {
281213
match candidate {
282214
Candidate::Ref(loc) => {
283-
assert!(!self.explicit);
284-
285215
let statement = &self.body[loc.block].statements[loc.statement_index];
286216
match &statement.kind {
287217
StatementKind::Assign(box (_, Rvalue::Ref(_, kind, place))) => {
@@ -310,15 +240,6 @@ impl<'tcx> Validator<'_, 'tcx> {
310240
_ => bug!(),
311241
}
312242
}
313-
Candidate::Argument { bb, index } => {
314-
assert!(self.explicit);
315-
316-
let terminator = self.body[bb].terminator();
317-
match &terminator.kind {
318-
TerminatorKind::Call { args, .. } => self.validate_operand(&args[index]),
319-
_ => bug!(),
320-
}
321-
}
322243
}
323244
}
324245

@@ -448,12 +369,10 @@ impl<'tcx> Validator<'_, 'tcx> {
448369
ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {}
449370

450371
ProjectionElem::Index(local) => {
451-
if !self.explicit {
452-
let mut promotable = false;
453-
// Only accept if we can predict the index and are indexing an array.
454-
let val = if let TempState::Defined { location: loc, .. } =
455-
self.temps[local]
456-
{
372+
let mut promotable = false;
373+
// Only accept if we can predict the index and are indexing an array.
374+
let val =
375+
if let TempState::Defined { location: loc, .. } = self.temps[local] {
457376
let block = &self.body[loc.block];
458377
if loc.statement_index < block.statements.len() {
459378
let statement = &block.statements[loc.statement_index];
@@ -470,28 +389,27 @@ impl<'tcx> Validator<'_, 'tcx> {
470389
} else {
471390
None
472391
};
473-
if let Some(idx) = val {
474-
// Determine the type of the thing we are indexing.
475-
let ty = place_base.ty(self.body, self.tcx).ty;
476-
match ty.kind() {
477-
ty::Array(_, len) => {
478-
// It's an array; determine its length.
479-
if let Some(len) =
480-
len.try_eval_usize(self.tcx, self.param_env)
481-
{
482-
// If the index is in-bounds, go ahead.
483-
if idx < len {
484-
promotable = true;
485-
}
392+
if let Some(idx) = val {
393+
// Determine the type of the thing we are indexing.
394+
let ty = place_base.ty(self.body, self.tcx).ty;
395+
match ty.kind() {
396+
ty::Array(_, len) => {
397+
// It's an array; determine its length.
398+
if let Some(len) = len.try_eval_usize(self.tcx, self.param_env)
399+
{
400+
// If the index is in-bounds, go ahead.
401+
if idx < len {
402+
promotable = true;
486403
}
487404
}
488-
_ => {}
489405
}
406+
_ => {}
490407
}
491-
if !promotable {
492-
return Err(Unpromotable);
493-
}
494408
}
409+
if !promotable {
410+
return Err(Unpromotable);
411+
}
412+
495413
self.validate_local(local)?;
496414
}
497415

@@ -636,7 +554,7 @@ impl<'tcx> Validator<'_, 'tcx> {
636554

637555
match op {
638556
BinOp::Div | BinOp::Rem => {
639-
if !self.explicit && lhs_ty.is_integral() {
557+
if lhs_ty.is_integral() {
640558
// Integer division: the RHS must be a non-zero const.
641559
let const_val = match rhs {
642560
Operand::Constant(c) => {
@@ -721,13 +639,12 @@ impl<'tcx> Validator<'_, 'tcx> {
721639
) -> Result<(), Unpromotable> {
722640
let fn_ty = callee.ty(self.body, self.tcx);
723641

724-
// When doing explicit promotion and inside const/static items, we promote all (eligible) function calls.
642+
// Inside const/static items, we promote all (eligible) function calls.
725643
// Everywhere else, we require `#[rustc_promotable]` on the callee.
726-
let promote_all_const_fn = self.explicit
727-
|| matches!(
728-
self.const_kind,
729-
Some(hir::ConstContext::Static(_) | hir::ConstContext::Const)
730-
);
644+
let promote_all_const_fn = matches!(
645+
self.const_kind,
646+
Some(hir::ConstContext::Static(_) | hir::ConstContext::Const)
647+
);
731648
if !promote_all_const_fn {
732649
if let ty::FnDef(def_id, _) = *fn_ty.kind() {
733650
// Never promote runtime `const fn` calls of
@@ -765,41 +682,12 @@ pub fn validate_candidates(
765682
temps: &IndexVec<Local, TempState>,
766683
candidates: &[Candidate],
767684
) -> Vec<Candidate> {
768-
let mut validator = Validator { ccx, temps, explicit: false };
685+
let validator = Validator { ccx, temps };
769686

770687
candidates
771688
.iter()
772689
.copied()
773-
.filter(|&candidate| {
774-
validator.explicit = candidate.forces_explicit_promotion();
775-
776-
// FIXME(eddyb) also emit the errors for shuffle indices
777-
// and `#[rustc_args_required_const]` arguments here.
778-
779-
let is_promotable = validator.validate_candidate(candidate).is_ok();
780-
781-
// If we use explicit validation, we carry the risk of turning a legitimate run-time
782-
// operation into a failing compile-time operation. Make sure that does not happen
783-
// by asserting that there is no possible run-time behavior here in case promotion
784-
// fails.
785-
if validator.explicit && !is_promotable {
786-
ccx.tcx.sess.delay_span_bug(
787-
ccx.body.span,
788-
"Explicit promotion requested, but failed to promote",
789-
);
790-
}
791-
792-
match candidate {
793-
Candidate::Argument { bb, index } if !is_promotable => {
794-
let span = ccx.body[bb].terminator().source_info.span;
795-
let msg = format!("argument {} is required to be a constant", index + 1);
796-
ccx.tcx.sess.span_err(span, &msg);
797-
}
798-
_ => (),
799-
}
800-
801-
is_promotable
802-
})
690+
.filter(|&candidate| validator.validate_candidate(candidate).is_ok())
803691
.collect()
804692
}
805693

@@ -1039,26 +927,6 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
1039927
_ => bug!(),
1040928
}
1041929
}
1042-
Candidate::Argument { bb, index } => {
1043-
let terminator = blocks[bb].terminator_mut();
1044-
match terminator.kind {
1045-
TerminatorKind::Call { ref mut args, .. } => {
1046-
let ty = args[index].ty(local_decls, self.tcx);
1047-
let span = terminator.source_info.span;
1048-
1049-
Rvalue::Use(mem::replace(&mut args[index], promoted_operand(ty, span)))
1050-
}
1051-
// We expected a `TerminatorKind::Call` for which we'd like to promote an
1052-
// argument. `qualify_consts` saw a `TerminatorKind::Call` here, but
1053-
// we are seeing a `Goto`. That means that the `promote_temps` method
1054-
// already promoted this call away entirely. This case occurs when calling
1055-
// a function requiring a constant argument and as that constant value
1056-
// providing a value whose computation contains another call to a function
1057-
// requiring a constant argument.
1058-
TerminatorKind::Goto { .. } => return None,
1059-
_ => bug!(),
1060-
}
1061-
}
1062930
}
1063931
};
1064932

@@ -1113,7 +981,6 @@ pub fn promote_candidates<'tcx>(
1113981
}
1114982
}
1115983
}
1116-
Candidate::Argument { .. } => {}
1117984
}
1118985

1119986
// Declare return place local so that `mir::Body::new` doesn't complain.

src/test/ui/consts/const_arg_local.rs

-11
This file was deleted.

src/test/ui/consts/const_arg_local.stderr

-8
This file was deleted.

src/test/ui/consts/const_arg_promotable.rs

-10
This file was deleted.

src/test/ui/consts/const_arg_promotable.stderr

-8
This file was deleted.

src/test/ui/consts/const_arg_promotable2.rs

-18
This file was deleted.

src/test/ui/consts/const_arg_promotable2.stderr

-8
This file was deleted.

src/test/ui/consts/const_arg_wrapper.rs

-10
This file was deleted.

src/test/ui/consts/const_arg_wrapper.stderr

-8
This file was deleted.

0 commit comments

Comments
 (0)