Skip to content

Commit

Permalink
Auto merge of #120687 - oli-obk:early_const_prop, r=<try>
Browse files Browse the repository at this point in the history
Run const_prop_lint in check builds, too

implements #108730 (comment)

Turns the const_prop_lint pass into a query that is run alongside borrowck.
  • Loading branch information
bors committed Feb 8, 2024
2 parents 870a01a + f271893 commit 460bf3d
Show file tree
Hide file tree
Showing 137 changed files with 1,343 additions and 616 deletions.
9 changes: 5 additions & 4 deletions compiler/rustc_abi/src/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -426,10 +426,11 @@ where
}
}
}
_ => assert!(
start == Bound::Unbounded && end == Bound::Unbounded,
"nonscalar layout for layout_scalar_valid_range type: {st:#?}",
),
_ => {
if start != Bound::Unbounded || end != Bound::Unbounded {
return None;
}
}
}

Some(st)
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_interface/src/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -738,6 +738,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
// Run unsafety check because it's responsible for stealing and
// deallocating THIR.
tcx.ensure().check_unsafety(def_id);
tcx.ensure().const_prop_lint(def_id);
tcx.ensure().mir_borrowck(def_id)
});
});
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/query/erase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ trivial! {
Option<rustc_target::spec::PanicStrategy>,
Option<usize>,
Result<(), rustc_errors::ErrorGuaranteed>,
Result<(), traits::util::HasImpossiblePredicates>,
Result<(), rustc_middle::traits::query::NoSolution>,
Result<rustc_middle::traits::EvaluationResult, rustc_middle::traits::OverflowError>,
rustc_ast::expand::allocator::AllocatorKind,
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ use crate::traits::query::{
OutlivesBound,
};
use crate::traits::specialization_graph;
use crate::traits::util::HasImpossiblePredicates;
use crate::traits::{
CodegenObligationError, EvaluationResult, ImplSource, ObjectSafetyViolation, ObligationCause,
OverflowError, WellFormedLoc,
Expand Down Expand Up @@ -1018,6 +1019,12 @@ rustc_queries! {
cache_on_disk_if(tcx) { tcx.is_typeck_child(key.to_def_id()) }
}

/// Run the const prop lints on the `mir_promoted` of an item.
query const_prop_lint(key: LocalDefId) -> Result<(), HasImpossiblePredicates> {
desc { |tcx| "checking const prop lints for `{}`", tcx.def_path_str(key) }
cache_on_disk_if { true }
}

/// Gets a complete map from all types to their inherent impls.
/// Not meant to be used directly outside of coherence.
query crate_inherent_impls(k: ()) -> Result<&'tcx CrateInherentImpls, ErrorGuaranteed> {
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_middle/src/traits/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,9 @@ impl<'tcx> Iterator for Elaborator<'tcx> {
}
}
}

/// Used as an error type to signal that an item may have an invalid body, because its
/// where bounds are trivially not satisfyable.
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[derive(HashStable, Encodable, Decodable)]
pub struct HasImpossiblePredicates;
62 changes: 40 additions & 22 deletions compiler/rustc_mir_transform/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ use rustc_middle::mir::{
SourceInfo, Statement, StatementKind, TerminatorKind, START_BLOCK,
};
use rustc_middle::query::Providers;
use rustc_middle::traits::util::HasImpossiblePredicates;
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
use rustc_span::{source_map::Spanned, sym, DUMMY_SP};
use rustc_trait_selection::traits;
Expand Down Expand Up @@ -142,6 +143,7 @@ pub fn provide(providers: &mut Providers) {
is_ctfe_mir_available: |tcx, did| is_mir_available(tcx, did),
mir_callgraph_reachable: inline::cycle::mir_callgraph_reachable,
mir_inliner_callees: inline::cycle::mir_inliner_callees,
const_prop_lint,
promoted_mir,
deduced_param_attrs: deduce_param_attrs::deduced_param_attrs,
..*providers
Expand Down Expand Up @@ -398,28 +400,11 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> {
body
}

/// Obtain just the main MIR (no promoteds) and run some cleanups on it. This also runs
/// mir borrowck *before* doing so in order to ensure that borrowck can be run and doesn't
/// end up missing the source MIR due to stealing happening.
fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> {
if tcx.is_coroutine(def.to_def_id()) {
tcx.ensure_with_value().mir_coroutine_witnesses(def);
}
let mir_borrowck = tcx.mir_borrowck(def);

let is_fn_like = tcx.def_kind(def).is_fn_like();
if is_fn_like {
// Do not compute the mir call graph without said call graph actually being used.
if pm::should_run_pass(tcx, &inline::Inline) {
tcx.ensure_with_value().mir_inliner_callees(ty::InstanceDef::Item(def.to_def_id()));
}
}

fn const_prop_lint(tcx: TyCtxt<'_>, def: LocalDefId) -> Result<(), HasImpossiblePredicates> {
let (body, _) = tcx.mir_promoted(def);
let mut body = body.steal();
if let Some(error_reported) = mir_borrowck.tainted_by_errors {
body.tainted_by_errors = Some(error_reported);
}
let body = body.borrow();

let mir_borrowck = tcx.mir_borrowck(def);

// Check if it's even possible to satisfy the 'where' clauses
// for this item.
Expand Down Expand Up @@ -455,6 +440,40 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &
.iter()
.filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None });
if traits::impossible_predicates(tcx, traits::elaborate(tcx, predicates).collect()) {
Err(HasImpossiblePredicates)
} else {
if mir_borrowck.tainted_by_errors.is_none() && body.tainted_by_errors.is_none() {
const_prop_lint::ConstPropLint.run_lint(tcx, &body);
}
Ok(())
}
}

/// Obtain just the main MIR (no promoteds) and run some cleanups on it. This also runs
/// mir borrowck *before* doing so in order to ensure that borrowck can be run and doesn't
/// end up missing the source MIR due to stealing happening.
fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> {
if tcx.is_coroutine(def.to_def_id()) {
tcx.ensure_with_value().mir_coroutine_witnesses(def);
}
let mir_borrowck = tcx.mir_borrowck(def);
let has_impossible_predicates = tcx.const_prop_lint(def);

let is_fn_like = tcx.def_kind(def).is_fn_like();
if is_fn_like {
// Do not compute the mir call graph without said call graph actually being used.
if pm::should_run_pass(tcx, &inline::Inline) {
tcx.ensure_with_value().mir_inliner_callees(ty::InstanceDef::Item(def.to_def_id()));
}
}

let (body, _) = tcx.mir_promoted(def);
let mut body = body.steal();
if let Some(error_reported) = mir_borrowck.tainted_by_errors {
body.tainted_by_errors = Some(error_reported);
}

if let Err(HasImpossiblePredicates) = has_impossible_predicates {
trace!("found unsatisfiable predicates for {:?}", body.source);
// Clear the body to only contain a single `unreachable` statement.
let bbs = body.basic_blocks.as_mut();
Expand Down Expand Up @@ -538,7 +557,6 @@ fn run_runtime_lowering_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
&elaborate_box_derefs::ElaborateBoxDerefs,
&coroutine::StateTransform,
&add_retag::AddRetag,
&Lint(const_prop_lint::ConstPropLint),
];
pm::run_passes_no_validate(tcx, body, passes, Some(MirPhase::Runtime(RuntimePhase::Initial)));
}
Expand Down
4 changes: 2 additions & 2 deletions src/doc/rustc/src/lints/levels.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ level is capped via cap-lints.
A 'deny' lint produces an error if you violate it. For example, this code
runs into the `exceeding_bitshifts` lint.

```rust,no_run
```rust,compile_fail
fn main() {
100u8 << 10;
}
Expand Down Expand Up @@ -246,7 +246,7 @@ pub fn foo() {}
This is the maximum level for all lints. So for example, if we take our
code sample from the "deny" lint level above:
```rust,no_run
```rust,compile_fail
fn main() {
100u8 << 10;
}
Expand Down
5 changes: 2 additions & 3 deletions src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,8 @@ fn main() {
x[const { idx() }]; // Ok, should not produce stderr.
x[const { idx4() }]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays.
const { &ARR[idx()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
const { &ARR[idx4()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
//
//~^^ ERROR: failed
// FIXME errors in rustc and subsequently blocks all lints in this file. Can reenable once solved on the rustc side
//const { &ARR[idx4()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.

let y = &x;
y[0]; // Ok, referencing shouldn't affect this lint. See the issue 6021
Expand Down
24 changes: 6 additions & 18 deletions src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr
Original file line number Diff line number Diff line change
@@ -1,15 +1,3 @@
error[E0080]: evaluation of `main::{constant#3}` failed
--> $DIR/test.rs:38:14
|
LL | const { &ARR[idx4()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
| ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4

note: erroneous constant encountered
--> $DIR/test.rs:38:5
|
LL | const { &ARR[idx4()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
| ^^^^^^^^^^^^^^^^^^^^^^

error: indexing may panic
--> $DIR/test.rs:29:5
|
Expand All @@ -21,39 +9,39 @@ LL | x[index];
= help: to override `-D warnings` add `#[allow(clippy::indexing_slicing)]`

error: indexing may panic
--> $DIR/test.rs:47:5
--> $DIR/test.rs:46:5
|
LL | v[0];
| ^^^^
|
= help: consider using `.get(n)` or `.get_mut(n)` instead

error: indexing may panic
--> $DIR/test.rs:48:5
--> $DIR/test.rs:47:5
|
LL | v[10];
| ^^^^^
|
= help: consider using `.get(n)` or `.get_mut(n)` instead

error: indexing may panic
--> $DIR/test.rs:49:5
--> $DIR/test.rs:48:5
|
LL | v[1 << 3];
| ^^^^^^^^^
|
= help: consider using `.get(n)` or `.get_mut(n)` instead

error: indexing may panic
--> $DIR/test.rs:55:5
--> $DIR/test.rs:54:5
|
LL | v[N];
| ^^^^
|
= help: consider using `.get(n)` or `.get_mut(n)` instead

error: indexing may panic
--> $DIR/test.rs:56:5
--> $DIR/test.rs:55:5
|
LL | v[M];
| ^^^^
Expand All @@ -66,6 +54,6 @@ error[E0080]: evaluation of constant value failed
LL | const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts.
| ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4

error: aborting due to 8 previous errors
error: aborting due to 7 previous errors

For more information about this error, try `rustc --explain E0080`.
4 changes: 2 additions & 2 deletions src/tools/clippy/tests/ui/indexing_slicing_index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ fn main() {
const { &ARR[idx()] };
//~^ ERROR: indexing may panic
// This should be linted, since `suppress-restriction-lint-in-const` default is false.
const { &ARR[idx4()] };
//~^ ERROR: indexing may panic
// FIXME can't include here for now, as the error on it causes all lints to get silenced
//const { &ARR[idx4()] };

let y = &x;
// Ok, referencing shouldn't affect this lint. See the issue 6021
Expand Down
23 changes: 1 addition & 22 deletions src/tools/clippy/tests/ui/indexing_slicing_index.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,6 @@ LL | const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts.
= help: consider using `.get(n)` or `.get_mut(n)` instead
= note: the suggestion might not be applicable in constant blocks

error[E0080]: evaluation of `main::{constant#3}` failed
--> $DIR/indexing_slicing_index.rs:48:14
|
LL | const { &ARR[idx4()] };
| ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4

note: erroneous constant encountered
--> $DIR/indexing_slicing_index.rs:48:5
|
LL | const { &ARR[idx4()] };
| ^^^^^^^^^^^^^^^^^^^^^^

error: indexing may panic
--> $DIR/indexing_slicing_index.rs:29:5
|
Expand Down Expand Up @@ -62,15 +50,6 @@ LL | const { &ARR[idx()] };
= help: consider using `.get(n)` or `.get_mut(n)` instead
= note: the suggestion might not be applicable in constant blocks

error: indexing may panic
--> $DIR/indexing_slicing_index.rs:48:14
|
LL | const { &ARR[idx4()] };
| ^^^^^^^^^^^
|
= help: consider using `.get(n)` or `.get_mut(n)` instead
= note: the suggestion might not be applicable in constant blocks

error: index is out of bounds
--> $DIR/indexing_slicing_index.rs:55:5
|
Expand Down Expand Up @@ -135,6 +114,6 @@ error[E0080]: evaluation of constant value failed
LL | const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts.
| ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4

error: aborting due to 17 previous errors
error: aborting due to 15 previous errors

For more information about this error, try `rustc --explain E0080`.
2 changes: 1 addition & 1 deletion tests/mir-opt/dataflow-const-prop/enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ fn statics() {

static RC: &E = &E::V2(4);

// CHECK: [[t:_.*]] = const {alloc2: &&E};
// CHECK: [[t:_.*]] = const {alloc4: &&E};
// CHECK: [[e2]] = (*[[t]]);
let e2 = RC;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,15 @@
let mut _0: ();
let mut _1: u32;
let mut _2: i64;
let mut _3: i64;
let mut _4: u32;
let mut _5: usize;
let mut _3: usize;

bb0: {
- _1 = const 1_i32 as u32 (Transmute);
- _2 = const 1_u64 as i64 (Transmute);
- _3 = const 1_isize as usize (Transmute);
+ _1 = const 1_i32 as u32 (IntToInt);
_2 = const 1_i32 as i64 (Transmute);
- _3 = const 1_u64 as i64 (Transmute);
+ _3 = const 1_u64 as i64 (IntToInt);
_4 = const 1_u64 as u32 (Transmute);
- _5 = const 1_isize as usize (Transmute);
+ _5 = const 1_isize as usize (IntToInt);
+ _2 = const 1_u64 as i64 (IntToInt);
+ _3 = const 1_isize as usize (IntToInt);
return;
}
}
Expand Down
11 changes: 5 additions & 6 deletions tests/mir-opt/instsimplify/combine_transmutes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#![feature(custom_mir)]

use std::intrinsics::mir::*;
use std::mem::{MaybeUninit, ManuallyDrop, transmute};
use std::mem::{transmute, ManuallyDrop, MaybeUninit};

// EMIT_MIR combine_transmutes.identity_transmutes.InstSimplify.diff
pub unsafe fn identity_transmutes() {
Expand All @@ -25,19 +25,15 @@ pub unsafe fn integer_transmutes() {
// CHECK-LABEL: fn integer_transmutes(
// CHECK-NOT: _i32 as u32 (Transmute);
// CHECK: _i32 as u32 (IntToInt);
// CHECK: _i32 as i64 (Transmute);
// CHECK-NOT: _u64 as i64 (Transmute);
// CHECK: _u64 as i64 (IntToInt);
// CHECK: _u64 as u32 (Transmute);
// CHECK-NOT: _isize as usize (Transmute);
// CHECK: _isize as usize (IntToInt);

mir! {
{
let A = CastTransmute::<i32, u32>(1); // Can be a cast
let B = CastTransmute::<i32, i64>(1); // UB
let C = CastTransmute::<u64, i64>(1); // Can be a cast
let D = CastTransmute::<u64, u32>(1); // UB
let E = CastTransmute::<isize, usize>(1); // Can be a cast
Return()
}
Expand All @@ -62,4 +58,7 @@ pub unsafe fn adt_transmutes() {
let _a: ManuallyDrop<String> = transmute(MaybeUninit::<String>::uninit());
}

pub union Union32 { u32: u32, i32: i32 }
pub union Union32 {
u32: u32,
i32: i32,
}

0 comments on commit 460bf3d

Please sign in to comment.