From a3d9355bef01aaefb9b6f3fb53b88cd4ce156453 Mon Sep 17 00:00:00 2001 From: Shotaro Yamada Date: Tue, 10 Mar 2020 13:17:15 +0900 Subject: [PATCH 1/2] Fix ICE with trivial_bounds feature --- clippy_lints/src/implicit_return.rs | 8 +++++++- clippy_lints/src/missing_const_for_fn.rs | 7 ++++++- clippy_lints/src/redundant_clone.rs | 10 ++++++++-- clippy_lints/src/utils/mod.rs | 23 ++++++++++++++++++++++- tests/ui/crashes/trivial_bounds.rs | 13 +++++++++++++ 5 files changed, 56 insertions(+), 5 deletions(-) create mode 100644 tests/ui/crashes/trivial_bounds.rs 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() {} From 227ef60a2b2fd3d78eb39d4361efc224be38cbb6 Mon Sep 17 00:00:00 2001 From: Shotaro Yamada Date: Tue, 10 Mar 2020 13:27:33 +0900 Subject: [PATCH 2/2] Fix doc --- clippy_lints/src/utils/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index a27245fd234..9f7cf400765 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -1381,8 +1381,8 @@ pub fn is_trait_impl_item(cx: &LateContext<'_, '_>, hir_id: HirId) -> bool { /// /// `trivial_bounds` feature allows functions with unsatisfiable bounds, for example: /// -/// ```rust -/// fn foo() i32: Iterator { +/// ```ignore +/// fn foo() where i32: Iterator { /// for _ in 2i32 {} /// } /// ```