about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--clippy_lints/src/implicit_return.rs8
-rw-r--r--clippy_lints/src/missing_const_for_fn.rs7
-rw-r--r--clippy_lints/src/redundant_clone.rs10
-rw-r--r--clippy_lints/src/utils/mod.rs23
-rw-r--r--tests/ui/crashes/trivial_bounds.rs13
5 files changed, 56 insertions, 5 deletions
diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs
index b0d80aa0d53..d968a928c33 100644
--- a/clippy_lints/src/implicit_return.rs
+++ b/clippy_lints/src/implicit_return.rs
@@ -1,5 +1,5 @@
 use crate::utils::{
-    match_def_path,
+    fn_has_unsatisfiable_preds, match_def_path,
     paths::{BEGIN_PANIC, BEGIN_PANIC_FMT},
     snippet_opt, span_lint_and_then,
 };
@@ -133,6 +133,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImplicitReturn {
         _: HirId,
     ) {
         let def_id = cx.tcx.hir().body_owner_def_id(body.id());
+
+        // Building MIR for `fn`s with unsatisfiable preds results in ICE.
+        if fn_has_unsatisfiable_preds(cx, def_id) {
+            return;
+        }
+
         let mir = cx.tcx.optimized_mir(def_id);
 
         // checking return type through MIR, HIR is not able to determine inferred closure return types
diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs
index e829baa2268..a22d8b4cf9e 100644
--- a/clippy_lints/src/missing_const_for_fn.rs
+++ b/clippy_lints/src/missing_const_for_fn.rs
@@ -1,4 +1,4 @@
-use crate::utils::{has_drop, is_entrypoint_fn, span_lint, trait_ref_of_method};
+use crate::utils::{fn_has_unsatisfiable_preds, has_drop, is_entrypoint_fn, span_lint, trait_ref_of_method};
 use rustc::lint::in_external_macro;
 use rustc_hir as hir;
 use rustc_hir::intravisit::FnKind;
@@ -88,6 +88,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingConstForFn {
             return;
         }
 
+        // Building MIR for `fn`s with unsatisfiable preds results in ICE.
+        if fn_has_unsatisfiable_preds(cx, def_id) {
+            return;
+        }
+
         // Perform some preliminary checks that rule out constness on the Clippy side. This way we
         // can skip the actual const check and return early.
         match kind {
diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs
index ddb0c748434..103c063aef4 100644
--- a/clippy_lints/src/redundant_clone.rs
+++ b/clippy_lints/src/redundant_clone.rs
@@ -1,6 +1,6 @@
 use crate::utils::{
-    has_drop, is_copy, match_def_path, match_type, paths, snippet_opt, span_lint_hir, span_lint_hir_and_then,
-    walk_ptrs_ty_depth,
+    fn_has_unsatisfiable_preds, has_drop, is_copy, match_def_path, match_type, paths, snippet_opt, span_lint_hir,
+    span_lint_hir_and_then, walk_ptrs_ty_depth,
 };
 use if_chain::if_chain;
 use matches::matches;
@@ -79,6 +79,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for RedundantClone {
         _: HirId,
     ) {
         let def_id = cx.tcx.hir().body_owner_def_id(body.id());
+
+        // Building MIR for `fn`s with unsatisfiable preds results in ICE.
+        if fn_has_unsatisfiable_preds(cx, def_id) {
+            return;
+        }
+
         let mir = cx.tcx.optimized_mir(def_id);
         let mir_read_only = mir.unwrap_read_only();
 
diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs
index dc8775b43b1..a27245fd234 100644
--- a/clippy_lints/src/utils/mod.rs
+++ b/clippy_lints/src/utils/mod.rs
@@ -32,7 +32,7 @@ use rustc::ty::{
     self,
     layout::{self, IntegerExt},
     subst::GenericArg,
-    Binder, Ty, TyCtxt,
+    Binder, Ty, TyCtxt, TypeFoldable,
 };
 use rustc_ast::ast::{self, Attribute, LitKind};
 use rustc_attr as attr;
@@ -1377,6 +1377,27 @@ pub fn is_trait_impl_item(cx: &LateContext<'_, '_>, hir_id: HirId) -> bool {
     }
 }
 
+/// Check if it's even possible to satisfy the `where` clause for the item.
+///
+/// `trivial_bounds` feature allows functions with unsatisfiable bounds, for example:
+///
+/// ```rust
+/// fn foo() i32: Iterator {
+///     for _ in 2i32 {}
+/// }
+/// ```
+pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_, '_>, did: DefId) -> bool {
+    use rustc_infer::traits;
+    let predicates = cx
+        .tcx
+        .predicates_of(did)
+        .predicates
+        .iter()
+        .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None })
+        .collect();
+    !traits::normalize_and_test_predicates(cx.tcx, traits::elaborate_predicates(cx.tcx, predicates).collect())
+}
+
 #[cfg(test)]
 mod test {
     use super::{trim_multiline, without_block_comments};
diff --git a/tests/ui/crashes/trivial_bounds.rs b/tests/ui/crashes/trivial_bounds.rs
new file mode 100644
index 00000000000..2bb95c18a39
--- /dev/null
+++ b/tests/ui/crashes/trivial_bounds.rs
@@ -0,0 +1,13 @@
+// run-pass
+
+#![feature(trivial_bounds)]
+#![allow(unused, trivial_bounds)]
+
+fn test_trivial_bounds()
+where
+    i32: Iterator,
+{
+    for _ in 2i32 {}
+}
+
+fn main() {}