Skip to content

Commit 6add19d

Browse files
committed
Run const_prop_lint in check builds, too
1 parent 5af2130 commit 6add19d

File tree

159 files changed

+2308
-1234
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

159 files changed

+2308
-1234
lines changed

compiler/rustc_interface/src/passes.rs

+2
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,8 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
734734
// Run unsafety check because it's responsible for stealing and
735735
// deallocating THIR.
736736
tcx.ensure().check_unsafety(def_id);
737+
tcx.ensure().const_prop_lint(def_id);
738+
tcx.ensure().const_prop_lint_promoteds(def_id);
737739
tcx.ensure().mir_borrowck(def_id)
738740
});
739741
});

compiler/rustc_middle/src/mir/tcx.rs

+4
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ impl<'tcx> PlaceTy<'tcx> {
7676
if self.variant_index.is_some() && !matches!(elem, ProjectionElem::Field(..)) {
7777
bug!("cannot use non field projection on downcasted place")
7878
}
79+
if self.ty.references_error() {
80+
// Cannot do anything useful with error types
81+
return PlaceTy::from_ty(self.ty);
82+
}
7983
let answer = match *elem {
8084
ProjectionElem::Deref => {
8185
let ty = self

compiler/rustc_middle/src/query/erase.rs

+1
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ trivial! {
243243
Option<usize>,
244244
Option<rustc_span::Symbol>,
245245
Result<(), rustc_errors::ErrorGuaranteed>,
246+
Result<(), traits::util::HasImpossiblePredicates>,
246247
Result<(), rustc_middle::traits::query::NoSolution>,
247248
Result<rustc_middle::traits::EvaluationResult, rustc_middle::traits::OverflowError>,
248249
rustc_ast::expand::allocator::AllocatorKind,

compiler/rustc_middle/src/query/mod.rs

+13
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ use crate::traits::query::{
4040
OutlivesBound,
4141
};
4242
use crate::traits::specialization_graph;
43+
use crate::traits::util::HasImpossiblePredicates;
4344
use crate::traits::{
4445
CodegenObligationError, EvaluationResult, ImplSource, ObjectSafetyViolation, ObligationCause,
4546
OverflowError, WellFormedLoc,
@@ -1015,6 +1016,18 @@ rustc_queries! {
10151016
cache_on_disk_if(tcx) { tcx.is_typeck_child(key.to_def_id()) }
10161017
}
10171018

1019+
/// Run the const prop lints on the `mir_promoted` of an item.
1020+
query const_prop_lint(key: LocalDefId) -> Result<(), HasImpossiblePredicates> {
1021+
desc { |tcx| "running const prop lints for `{}`", tcx.def_path_str(key) }
1022+
cache_on_disk_if { true }
1023+
}
1024+
1025+
/// Run the const prop lints on the promoted consts of an item.
1026+
query const_prop_lint_promoteds(key: LocalDefId) -> Result<(), HasImpossiblePredicates> {
1027+
desc { |tcx| "running const prop lints for promoteds of `{}`", tcx.def_path_str(key) }
1028+
cache_on_disk_if { true }
1029+
}
1030+
10181031
/// Gets a complete map from all types to their inherent impls.
10191032
/// Not meant to be used directly outside of coherence.
10201033
query crate_inherent_impls(k: ()) -> Result<&'tcx CrateInherentImpls, ErrorGuaranteed> {

compiler/rustc_middle/src/traits/util.rs

+6
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,9 @@ impl<'tcx> Iterator for Elaborator<'tcx> {
6060
}
6161
}
6262
}
63+
64+
/// Used as an error type to signal that an item may have an invalid body, because its
65+
/// where bounds are trivially not satisfyable.
66+
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
67+
#[derive(HashStable, Encodable, Decodable)]
68+
pub struct HasImpossiblePredicates;

compiler/rustc_middle/src/ty/util.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -659,10 +659,17 @@ impl<'tcx> TyCtxt<'tcx> {
659659
/// Get the type of the pointer to the static that we use in MIR.
660660
pub fn static_ptr_ty(self, def_id: DefId) -> Ty<'tcx> {
661661
// Make sure that any constants in the static's type are evaluated.
662-
let static_ty = self.normalize_erasing_regions(
662+
let mut static_ty = self.normalize_erasing_regions(
663663
ty::ParamEnv::empty(),
664664
self.type_of(def_id).instantiate_identity(),
665665
);
666+
if !static_ty.is_sized(self, ty::ParamEnv::reveal_all()) {
667+
static_ty = Ty::new_error_with_message(
668+
self,
669+
self.def_span(def_id),
670+
"unsized statics are forbidden and error in wfcheck",
671+
);
672+
}
666673

667674
// Make sure that accesses to unsafe statics end up using raw pointers.
668675
// For thread-locals, this needs to be kept in sync with `Rvalue::ty`.

compiler/rustc_mir_transform/src/const_prop_lint.rs

+6
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,11 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
261261
// manually normalized.
262262
let val = self.tcx.try_normalize_erasing_regions(self.param_env, c.const_).ok()?;
263263

264+
// Unsized constants are illegal and already errored in wfcheck
265+
if !val.ty().is_sized(self.tcx, self.param_env) {
266+
return None;
267+
}
268+
264269
self.use_ecx(|this| this.ecx.eval_mir_constant(&val, Some(c.span), None))?
265270
.as_mplace_or_imm()
266271
.right()
@@ -471,6 +476,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
471476
let value_const = self.use_ecx(|this| this.ecx.read_scalar(value))?;
472477

473478
if expected != value_const {
479+
trace!("assertion failed");
474480
// Poison all places this operand references so that further code
475481
// doesn't use the invalid value
476482
if let Some(place) = cond.place() {

compiler/rustc_mir_transform/src/lib.rs

+65-18
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ use rustc_middle::mir::{
3838
SourceInfo, Statement, StatementKind, TerminatorKind, START_BLOCK,
3939
};
4040
use rustc_middle::query::Providers;
41+
use rustc_middle::traits::util::HasImpossiblePredicates;
4142
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
4243
use rustc_span::{source_map::Spanned, sym, DUMMY_SP};
4344
use rustc_trait_selection::traits;
@@ -137,6 +138,8 @@ pub fn provide(providers: &mut Providers) {
137138
is_ctfe_mir_available: |tcx, did| is_mir_available(tcx, did),
138139
mir_callgraph_reachable: inline::cycle::mir_callgraph_reachable,
139140
mir_inliner_callees: inline::cycle::mir_inliner_callees,
141+
const_prop_lint,
142+
const_prop_lint_promoteds,
140143
promoted_mir,
141144
deduced_param_attrs: deduce_param_attrs::deduced_param_attrs,
142145
..*providers
@@ -393,6 +396,39 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> {
393396
body
394397
}
395398

399+
fn const_prop_lint(tcx: TyCtxt<'_>, def: LocalDefId) -> Result<(), HasImpossiblePredicates> {
400+
let (body, _) = tcx.mir_promoted(def);
401+
let body = body.borrow();
402+
403+
let mir_borrowck = tcx.mir_borrowck(def);
404+
405+
check_impossible_predicates(tcx, def)?;
406+
if mir_borrowck.tainted_by_errors.is_none() && body.tainted_by_errors.is_none() {
407+
const_prop_lint::ConstPropLint.run_lint(tcx, &body);
408+
}
409+
Ok(())
410+
}
411+
412+
fn const_prop_lint_promoteds(
413+
tcx: TyCtxt<'_>,
414+
def: LocalDefId,
415+
) -> Result<(), HasImpossiblePredicates> {
416+
let (_, promoteds) = tcx.mir_promoted(def);
417+
let promoteds = promoteds.borrow();
418+
419+
let mir_borrowck = tcx.mir_borrowck(def);
420+
421+
check_impossible_predicates(tcx, def)?;
422+
if mir_borrowck.tainted_by_errors.is_none() {
423+
for body in &*promoteds {
424+
if body.tainted_by_errors.is_none() {
425+
const_prop_lint::ConstPropLint.run_lint(tcx, &body);
426+
}
427+
}
428+
}
429+
Ok(())
430+
}
431+
396432
/// Obtain just the main MIR (no promoteds) and run some cleanups on it. This also runs
397433
/// mir borrowck *before* doing so in order to ensure that borrowck can be run and doesn't
398434
/// end up missing the source MIR due to stealing happening.
@@ -401,6 +437,7 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &
401437
tcx.ensure_with_value().mir_coroutine_witnesses(def);
402438
}
403439
let mir_borrowck = tcx.mir_borrowck(def);
440+
let impossible_predicates = tcx.const_prop_lint(def);
404441

405442
let is_fn_like = tcx.def_kind(def).is_fn_like();
406443
if is_fn_like {
@@ -415,7 +452,30 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &
415452
if let Some(error_reported) = mir_borrowck.tainted_by_errors {
416453
body.tainted_by_errors = Some(error_reported);
417454
}
455+
if impossible_predicates.is_err() {
456+
trace!("found unsatisfiable predicates for {:?}", body.source);
457+
// Clear the body to only contain a single `unreachable` statement.
458+
let bbs = body.basic_blocks.as_mut();
459+
bbs.raw.truncate(1);
460+
bbs[START_BLOCK].statements.clear();
461+
bbs[START_BLOCK].terminator_mut().kind = TerminatorKind::Unreachable;
462+
body.var_debug_info.clear();
463+
body.local_decls.raw.truncate(body.arg_count + 1);
464+
}
418465

466+
run_analysis_to_runtime_passes(tcx, &mut body);
467+
468+
// Now that drop elaboration has been performed, we can check for
469+
// unconditional drop recursion.
470+
rustc_mir_build::lints::check_drop_recursion(tcx, &body);
471+
472+
tcx.alloc_steal_mir(body)
473+
}
474+
475+
fn check_impossible_predicates(
476+
tcx: TyCtxt<'_>,
477+
def: LocalDefId,
478+
) -> Result<(), HasImpossiblePredicates> {
419479
// Check if it's even possible to satisfy the 'where' clauses
420480
// for this item.
421481
//
@@ -445,28 +505,15 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &
445505
// the normalization code (leading to cycle errors), since
446506
// it's usually never invoked in this way.
447507
let predicates = tcx
448-
.predicates_of(body.source.def_id())
508+
.predicates_of(def)
449509
.predicates
450510
.iter()
451511
.filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None });
452512
if traits::impossible_predicates(tcx, traits::elaborate(tcx, predicates).collect()) {
453-
trace!("found unsatisfiable predicates for {:?}", body.source);
454-
// Clear the body to only contain a single `unreachable` statement.
455-
let bbs = body.basic_blocks.as_mut();
456-
bbs.raw.truncate(1);
457-
bbs[START_BLOCK].statements.clear();
458-
bbs[START_BLOCK].terminator_mut().kind = TerminatorKind::Unreachable;
459-
body.var_debug_info.clear();
460-
body.local_decls.raw.truncate(body.arg_count + 1);
513+
Err(HasImpossiblePredicates)
514+
} else {
515+
Ok(())
461516
}
462-
463-
run_analysis_to_runtime_passes(tcx, &mut body);
464-
465-
// Now that drop elaboration has been performed, we can check for
466-
// unconditional drop recursion.
467-
rustc_mir_build::lints::check_drop_recursion(tcx, &body);
468-
469-
tcx.alloc_steal_mir(body)
470517
}
471518

472519
// Made public such that `mir_drops_elaborated_and_const_checked` can be overridden
@@ -533,7 +580,6 @@ fn run_runtime_lowering_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
533580
&elaborate_box_derefs::ElaborateBoxDerefs,
534581
&coroutine::StateTransform,
535582
&add_retag::AddRetag,
536-
&Lint(const_prop_lint::ConstPropLint),
537583
];
538584
pm::run_passes_no_validate(tcx, body, passes, Some(MirPhase::Runtime(RuntimePhase::Initial)));
539585
}
@@ -678,6 +724,7 @@ fn promoted_mir(tcx: TyCtxt<'_>, def: LocalDefId) -> &IndexVec<Promoted, Body<'_
678724
}
679725

680726
tcx.ensure_with_value().mir_borrowck(def);
727+
tcx.ensure().const_prop_lint_promoteds(def);
681728
let mut promoted = tcx.mir_promoted(def).1.steal();
682729

683730
for body in &mut promoted {

src/doc/rustc/src/lints/levels.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ level is capped via cap-lints.
7171
A 'deny' lint produces an error if you violate it. For example, this code
7272
runs into the `exceeding_bitshifts` lint.
7373

74-
```rust,no_run
74+
```rust,compile_fail
7575
fn main() {
7676
100u8 << 10;
7777
}
@@ -246,7 +246,7 @@ pub fn foo() {}
246246
This is the maximum level for all lints. So for example, if we take our
247247
code sample from the "deny" lint level above:
248248
249-
```rust,no_run
249+
```rust,compile_fail
250250
fn main() {
251251
100u8 << 10;
252252
}

src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,8 @@ fn main() {
3535
x[const { idx() }]; // Ok, should not produce stderr.
3636
x[const { idx4() }]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays.
3737
const { &ARR[idx()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
38-
const { &ARR[idx4()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
39-
//
40-
//~^^ ERROR: failed
38+
// FIXME errors in rustc and subsequently blocks all lints in this file. Can reenable once solved on the rustc side
39+
//const { &ARR[idx4()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
4140

4241
let y = &x;
4342
y[0]; // Ok, referencing shouldn't affect this lint. See the issue 6021
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,3 @@
1-
error[E0080]: evaluation of `main::{constant#3}` failed
2-
--> $DIR/test.rs:38:14
3-
|
4-
LL | const { &ARR[idx4()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
5-
| ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4
6-
7-
note: erroneous constant encountered
8-
--> $DIR/test.rs:38:5
9-
|
10-
LL | const { &ARR[idx4()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
11-
| ^^^^^^^^^^^^^^^^^^^^^^
12-
131
error: indexing may panic
142
--> $DIR/test.rs:29:5
153
|
@@ -21,39 +9,39 @@ LL | x[index];
219
= help: to override `-D warnings` add `#[allow(clippy::indexing_slicing)]`
2210

2311
error: indexing may panic
24-
--> $DIR/test.rs:47:5
12+
--> $DIR/test.rs:46:5
2513
|
2614
LL | v[0];
2715
| ^^^^
2816
|
2917
= help: consider using `.get(n)` or `.get_mut(n)` instead
3018

3119
error: indexing may panic
32-
--> $DIR/test.rs:48:5
20+
--> $DIR/test.rs:47:5
3321
|
3422
LL | v[10];
3523
| ^^^^^
3624
|
3725
= help: consider using `.get(n)` or `.get_mut(n)` instead
3826

3927
error: indexing may panic
40-
--> $DIR/test.rs:49:5
28+
--> $DIR/test.rs:48:5
4129
|
4230
LL | v[1 << 3];
4331
| ^^^^^^^^^
4432
|
4533
= help: consider using `.get(n)` or `.get_mut(n)` instead
4634

4735
error: indexing may panic
48-
--> $DIR/test.rs:55:5
36+
--> $DIR/test.rs:54:5
4937
|
5038
LL | v[N];
5139
| ^^^^
5240
|
5341
= help: consider using `.get(n)` or `.get_mut(n)` instead
5442

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

69-
error: aborting due to 8 previous errors
57+
error: aborting due to 7 previous errors
7058

7159
For more information about this error, try `rustc --explain E0080`.

src/tools/clippy/tests/ui/indexing_slicing_index.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ fn main() {
4545
const { &ARR[idx()] };
4646
//~^ ERROR: indexing may panic
4747
// This should be linted, since `suppress-restriction-lint-in-const` default is false.
48-
const { &ARR[idx4()] };
49-
//~^ ERROR: indexing may panic
48+
// FIXME can't include here for now, as the error on it causes all lints to get silenced
49+
//const { &ARR[idx4()] };
5050

5151
let y = &x;
5252
// Ok, referencing shouldn't affect this lint. See the issue 6021

0 commit comments

Comments
 (0)