Skip to content

Commit 602cf09

Browse files
Check impossible predicates, use it to skip NoopMethodCall and Inline
1 parent 99b70ee commit 602cf09

File tree

10 files changed

+127
-73
lines changed

10 files changed

+127
-73
lines changed

compiler/rustc_lint/src/noop_method_call.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,16 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
6767
// we need to perform substitution.
6868
return;
6969
}
70+
71+
if cx.tcx.instantiated_item_has_impossible_predicates((did, substs)) {
72+
tracing::trace!("NoopMethodCall skipped for {:?}: found unsatisfiable predicates", did);
73+
return;
74+
}
75+
7076
let param_env = cx.tcx.param_env(trait_id);
7177
// Resolve the trait method instance.
7278
let Ok(Some(i)) = ty::Instance::resolve(cx.tcx, param_env, did, substs) else {
73-
return
79+
return;
7480
};
7581
// (Re)check that it implements the noop diagnostic.
7682
let Some(name) = cx.tcx.get_diagnostic_name(i.def_id()) else { return };

compiler/rustc_middle/src/mir/mono.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ impl<'tcx> MonoItem<'tcx> {
175175
MonoItem::GlobalAsm(..) => return true,
176176
};
177177

178-
!tcx.subst_and_check_impossible_predicates((def_id, &substs))
178+
!tcx.instantiated_item_has_impossible_predicates((def_id, &substs))
179179
}
180180

181181
pub fn local_span(&self, tcx: TyCtxt<'tcx>) -> Option<Span> {

compiler/rustc_middle/src/query/mod.rs

+31-3
Original file line numberDiff line numberDiff line change
@@ -1870,10 +1870,38 @@ rustc_queries! {
18701870
remap_env_constness
18711871
}
18721872

1873-
query subst_and_check_impossible_predicates(key: (DefId, SubstsRef<'tcx>)) -> bool {
1873+
query instantiated_item_has_impossible_predicates(key: (DefId, SubstsRef<'tcx>)) -> bool {
18741874
desc { |tcx|
1875-
"impossible substituted predicates:`{}`",
1876-
tcx.def_path_str(key.0)
1875+
"`{}` has impossible predicates after substituting `{:?}`",
1876+
tcx.def_path_str(key.0), key.1
1877+
}
1878+
}
1879+
1880+
// Check if it's even possible to satisfy the 'where' clauses
1881+
// for this item, without substitutions.
1882+
//
1883+
// We don't usually need to worry about this kind of case,
1884+
// since we would get a compilation error if the user tried
1885+
// to call it. However, since we can do certain mir optimizations
1886+
// and lints even without any calls to the function, we need to
1887+
// make sure that it even makes sense to try to evaluate predicates
1888+
// dependent on the where-clause of this function.
1889+
//
1890+
// We manually filter the predicates, skipping anything that's not
1891+
// "global". We are in a potentially generic context
1892+
// (e.g. we are evaluating a function without substituting generic
1893+
// parameters), so this filtering serves two purposes:
1894+
//
1895+
// 1. We skip evaluating any predicates that we would
1896+
// never be able prove are unsatisfiable (e.g. `<T as Foo>`
1897+
// 2. We avoid trying to normalize predicates involving generic
1898+
// parameters (e.g. `<T as Foo>::MyItem`). This can confuse
1899+
// the normalization code (leading to cycle errors), since
1900+
// it's usually never invoked in this way.
1901+
query item_has_impossible_predicates_for_item(key: DefId) -> bool {
1902+
desc { |tcx|
1903+
"`{}` has impossible predicates",
1904+
tcx.def_path_str(key)
18771905
}
18781906
}
18791907

compiler/rustc_mir_transform/src/const_prop.rs

+1-36
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ use rustc_middle::ty::{self, ConstKind, Instance, ParamEnv, Ty, TyCtxt, TypeFold
2222
use rustc_span::{def_id::DefId, Span};
2323
use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout};
2424
use rustc_target::spec::abi::Abi;
25-
use rustc_trait_selection::traits;
2625

2726
use crate::MirPass;
2827
use rustc_const_eval::interpret::{
@@ -90,41 +89,7 @@ impl<'tcx> MirPass<'tcx> for ConstProp {
9089
return;
9190
}
9291

93-
// Check if it's even possible to satisfy the 'where' clauses
94-
// for this item.
95-
// This branch will never be taken for any normal function.
96-
// However, it's possible to `#!feature(trivial_bounds)]` to write
97-
// a function with impossible to satisfy clauses, e.g.:
98-
// `fn foo() where String: Copy {}`
99-
//
100-
// We don't usually need to worry about this kind of case,
101-
// since we would get a compilation error if the user tried
102-
// to call it. However, since we can do const propagation
103-
// even without any calls to the function, we need to make
104-
// sure that it even makes sense to try to evaluate the body.
105-
// If there are unsatisfiable where clauses, then all bets are
106-
// off, and we just give up.
107-
//
108-
// We manually filter the predicates, skipping anything that's not
109-
// "global". We are in a potentially generic context
110-
// (e.g. we are evaluating a function without substituting generic
111-
// parameters, so this filtering serves two purposes:
112-
//
113-
// 1. We skip evaluating any predicates that we would
114-
// never be able prove are unsatisfiable (e.g. `<T as Foo>`
115-
// 2. We avoid trying to normalize predicates involving generic
116-
// parameters (e.g. `<T as Foo>::MyItem`). This can confuse
117-
// the normalization code (leading to cycle errors), since
118-
// it's usually never invoked in this way.
119-
let predicates = tcx
120-
.predicates_of(def_id.to_def_id())
121-
.predicates
122-
.iter()
123-
.filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None });
124-
if traits::impossible_predicates(
125-
tcx,
126-
traits::elaborate_predicates(tcx, predicates).map(|o| o.predicate).collect(),
127-
) {
92+
if tcx.item_has_impossible_predicates_for_item(def_id) {
12893
trace!("ConstProp skipped for {:?}: found unsatisfiable predicates", def_id);
12994
return;
13095
}

compiler/rustc_mir_transform/src/inline.rs

+5-10
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ use rustc_index::vec::Idx;
66
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
77
use rustc_middle::mir::visit::*;
88
use rustc_middle::mir::*;
9-
use rustc_middle::traits::ObligationCause;
109
use rustc_middle::ty::subst::Subst;
1110
use rustc_middle::ty::{self, ConstKind, Instance, InstanceDef, ParamEnv, Ty, TyCtxt};
1211
use rustc_span::{hygiene::ExpnKind, ExpnData, LocalExpnId, Span};
@@ -74,18 +73,14 @@ fn inline<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
7473
return false;
7574
}
7675

77-
let param_env = tcx.param_env_reveal_all_normalized(def_id);
78-
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
79-
let param_env = rustc_trait_selection::traits::normalize_param_env_or_error(
80-
tcx,
81-
def_id.to_def_id(),
82-
param_env,
83-
ObligationCause::misc(body.span, hir_id),
84-
);
76+
if tcx.item_has_impossible_predicates_for_item(def_id) {
77+
trace!("Inline skipped for {:?}: found unsatisfiable predicates", def_id);
78+
return false;
79+
}
8580

8681
let mut this = Inliner {
8782
tcx,
88-
param_env,
83+
param_env: tcx.param_env_reveal_all_normalized(def_id),
8984
codegen_fn_attrs: tcx.codegen_fn_attrs(def_id),
9085
history: Vec::new(),
9186
changed: false,

compiler/rustc_trait_selection/src/traits/mod.rs

+26-4
Original file line numberDiff line numberDiff line change
@@ -454,17 +454,38 @@ pub fn impossible_predicates<'tcx>(
454454
result
455455
}
456456

457-
fn subst_and_check_impossible_predicates<'tcx>(
457+
fn instantiated_item_has_impossible_predicates<'tcx>(
458458
tcx: TyCtxt<'tcx>,
459459
key: (DefId, SubstsRef<'tcx>),
460460
) -> bool {
461-
debug!("subst_and_check_impossible_predicates(key={:?})", key);
461+
debug!("instantiated_item_has_impossible_predicates(key={:?})", key);
462462

463463
let mut predicates = tcx.predicates_of(key.0).instantiate(tcx, key.1).predicates;
464464
predicates.retain(|predicate| !predicate.needs_subst());
465465
let result = impossible_predicates(tcx, predicates);
466466

467-
debug!("subst_and_check_impossible_predicates(key={:?}) = {:?}", key, result);
467+
debug!("instantiated_item_has_impossible_predicates(key={:?}) = {:?}", key, result);
468+
result
469+
}
470+
471+
fn item_has_impossible_predicates_for_item<'tcx>(tcx: TyCtxt<'tcx>, key: DefId) -> bool {
472+
debug!("item_has_impossible_predicates_for_item(key={:?})", key);
473+
474+
let result = impossible_predicates(
475+
tcx,
476+
elaborate_predicates_with_span(
477+
tcx,
478+
tcx.predicates_of(key)
479+
.predicates
480+
.iter()
481+
.filter(|predicate| predicate.is_global())
482+
.copied(),
483+
)
484+
.map(|o| o.predicate)
485+
.collect(),
486+
);
487+
488+
debug!("item_has_impossible_predicates_for_item(key={:?}) = {:?}", key, result);
468489
result
469490
}
470491

@@ -847,7 +868,8 @@ pub fn provide(providers: &mut ty::query::Providers) {
847868
own_existential_vtable_entries,
848869
vtable_entries,
849870
vtable_trait_upcasting_coercion_new_vptr_slot,
850-
subst_and_check_impossible_predicates,
871+
instantiated_item_has_impossible_predicates,
872+
item_has_impossible_predicates_for_item,
851873
thir_abstract_const: |tcx, def_id| {
852874
let def_id = def_id.expect_local();
853875
if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {

src/test/ui/trait-bounds/issue-93008.rs

+11-6
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
1-
// compile-flags: -Zmir-opt-level=4
1+
// build-pass
2+
// compile-flags: -Zmir-opt-level=3 --crate-type=lib
23

3-
pub fn bar<T>(s: &'static mut ())
4+
#![feature(trivial_bounds)]
5+
#![allow(trivial_bounds)]
6+
7+
trait Foo {
8+
fn test(self);
9+
}
10+
fn baz<T>()
411
where
5-
&'static mut (): Clone, //~ ERROR the trait bound
12+
&'static str: Foo,
613
{
7-
<&'static mut () as Clone>::clone(&s);
14+
"Foo".test()
815
}
9-
10-
fn main() {}

src/test/ui/trait-bounds/issue-93008.stderr

-12
This file was deleted.
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// check-pass
2+
3+
fn main() {
4+
println!("{:?}", {
5+
type T = ();
6+
7+
pub fn cloneit(it: &'_ mut T) -> (&'_ mut T, &'_ mut T)
8+
where
9+
for<'any> &'any mut T: Clone,
10+
{
11+
(it.clone(), it)
12+
}
13+
});
14+
}
+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// check-pass
2+
3+
trait Identity<Q> {
4+
type T;
5+
}
6+
7+
impl<Q, T> Identity<Q> for T {
8+
type T = T;
9+
}
10+
11+
trait Holds {
12+
type Q;
13+
}
14+
15+
16+
struct S;
17+
struct X(S);
18+
19+
struct XHelper;
20+
21+
impl Holds for X {
22+
type Q = XHelper;
23+
}
24+
25+
impl<Q> Clone for X where <S as Identity<Q>>::T: Clone, X: Holds<Q = Q> {
26+
fn clone(&self) -> Self {
27+
Self(self.0.clone())
28+
}
29+
}
30+
31+
fn main() {}

0 commit comments

Comments
 (0)