From ea21a8a38f4a9e6b820524e9e908adc3ba16dc99 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 3 Jun 2019 17:34:41 +0200 Subject: [PATCH] some more comments for const_qualif --- src/librustc_mir/transform/qualify_consts.rs | 43 +++++++++++++------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 69cfdbc28eb..26a24d4e36b 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -135,6 +135,12 @@ enum ValueSource<'a, 'tcx> { }, } +/// A "qualif" is a way to lookg for something "bad" in the MIR that would prevent +/// proper const evaluation. So `return true` means "I found something bad, no reason +/// to go on searching". `false` is only returned if we definitely cannot find anything +/// bad anywhere. +/// +/// The default implementations proceed structurally. trait Qualif { const IDX: usize; @@ -285,7 +291,9 @@ fn in_value(cx: &ConstCx<'_, 'tcx>, source: ValueSource<'_, 'tcx>) -> bool { } } -// Constant containing interior mutability (UnsafeCell). +/// Constant containing interior mutability (UnsafeCell). +/// This must be ruled out to make sure that evaluating the constant at compile-time +/// and run-time would produce the same result. struct HasMutInterior; impl Qualif for HasMutInterior { @@ -343,7 +351,9 @@ fn in_rvalue(cx: &ConstCx<'_, 'tcx>, rvalue: &Rvalue<'tcx>) -> bool { } } -// Constant containing an ADT that implements Drop. +/// Constant containing an ADT that implements Drop. +/// This must be ruled out because we cannot run `Drop` during compile-time +/// as that might not be a `const fn`. struct NeedsDrop; impl Qualif for NeedsDrop { @@ -366,8 +376,11 @@ fn in_rvalue(cx: &ConstCx<'_, 'tcx>, rvalue: &Rvalue<'tcx>) -> bool { } } -// Not promotable at all - non-`const fn` calls, asm!, -// pointer comparisons, ptr-to-int casts, etc. +/// Not promotable at all - non-`const fn` calls, asm!, +/// pointer comparisons, ptr-to-int casts, etc. +/// Inside a const context all constness rules apply, so promotion simply has to follow the regular +/// constant rules (modulo interior mutability or `Drop` rules which are handled `HasMutInterior` +/// and `NeedsDrop` respectively). struct IsNotPromotable; impl Qualif for IsNotPromotable { @@ -511,12 +524,9 @@ fn in_call( /// Refers to temporaries which cannot be promoted *implicitly*. /// Explicit promotion happens e.g. for constant arguments declared via `rustc_args_required_const`. -/// Inside a const context all constness rules -/// apply, so implicit promotion simply has to follow the regular constant rules (modulo interior -/// mutability or `Drop` rules which are handled `HasMutInterior` and `NeedsDrop` respectively). -/// Implicit promotion inside regular functions does not happen if `const fn` calls are involved, -/// as the call may be perfectly alright at runtime, but fail at compile time e.g. due to addresses -/// being compared inside the function. +/// Implicit promotion has almost the same rules, except that it does not happen if `const fn` +/// calls are involved. The call may be perfectly alright at runtime, but fail at compile time +/// e.g. due to addresses being compared inside the function. struct IsNotImplicitlyPromotable; impl Qualif for IsNotImplicitlyPromotable { @@ -589,6 +599,11 @@ fn qualifs_in_value(&self, source: ValueSource<'_, 'tcx>) -> PerQualif { } } +/// Checks MIR for const-correctness, using `ConstCx` +/// for value qualifications, and accumulates writes of +/// rvalue/call results to locals, in `local_qualif`. +/// For functions (constant or not), it also records +/// candidates for promotion in `promotion_candidates`. struct Checker<'a, 'tcx> { cx: ConstCx<'a, 'tcx>, @@ -757,6 +772,9 @@ fn assign(&mut self, dest: &Place<'tcx>, source: ValueSource<'_, 'tcx>, location // `let _: &'static _ = &(Cell::new(1), 2).1;` let mut local_qualifs = self.qualifs_in_local(local); local_qualifs[HasMutInterior] = false; + // Make sure there is no reason to prevent promotion. + // This is, in particular, the "implicit promotion" version of + // the check making sure that we don't run drop glue during const-eval. if !local_qualifs.0.iter().any(|&qualif| qualif) { debug!("qualify_consts: promotion candidate: {:?}", candidate); self.promotion_candidates.push(candidate); @@ -920,11 +938,6 @@ fn check_const(&mut self) -> (u8, &'tcx BitSet) { } } -/// Checks MIR for const-correctness, using `ConstCx` -/// for value qualifications, and accumulates writes of -/// rvalue/call results to locals, in `local_qualif`. -/// For functions (constant or not), it also records -/// candidates for promotion in `promotion_candidates`. impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { fn visit_place_base( &mut self,