about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_typeck/src/check/wfcheck.rs36
-rw-r--r--compiler/rustc_typeck/src/lib.rs1
-rw-r--r--src/test/ui/issues/issue-17904-2.stderr1
-rw-r--r--src/test/ui/issues/issue-37534.stderr1
-rw-r--r--src/test/ui/variance/variance-unused-type-param.rs9
-rw-r--r--src/test/ui/variance/variance-unused-type-param.stderr26
6 files changed, 67 insertions, 7 deletions
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index 4ab654560ea..a42ed9eab64 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -31,6 +31,7 @@ use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode,
 
 use std::convert::TryInto;
 use std::iter;
+use std::lazy::Lazy;
 use std::ops::ControlFlow;
 
 /// Helper type of a temporary returned by `.for_item(...)`.
@@ -1720,8 +1721,29 @@ fn check_variances_for_type_defn<'tcx>(
 
     identify_constrained_generic_params(tcx, ty_predicates, None, &mut constrained_parameters);
 
+    // Lazily calculated because it is only needed in case of an error.
+    let explicitly_bounded_params = Lazy::new(|| {
+        let icx = crate::collect::ItemCtxt::new(tcx, item.def_id.to_def_id());
+        hir_generics
+            .where_clause
+            .predicates
+            .iter()
+            .filter_map(|predicate| match predicate {
+                hir::WherePredicate::BoundPredicate(predicate) => {
+                    match icx.to_ty(predicate.bounded_ty).kind() {
+                        ty::Param(data) => Some(Parameter(data.index)),
+                        _ => None,
+                    }
+                }
+                _ => None,
+            })
+            .collect::<FxHashSet<_>>()
+    });
+
     for (index, _) in variances.iter().enumerate() {
-        if constrained_parameters.contains(&Parameter(index as u32)) {
+        let parameter = Parameter(index as u32);
+
+        if constrained_parameters.contains(&parameter) {
             continue;
         }
 
@@ -1730,13 +1752,19 @@ fn check_variances_for_type_defn<'tcx>(
         match param.name {
             hir::ParamName::Error => {}
             _ => {
-                report_bivariance(tcx, param);
+                let has_explicit_bounds =
+                    !param.bounds.is_empty() || explicitly_bounded_params.contains(&parameter);
+                report_bivariance(tcx, param, has_explicit_bounds);
             }
         }
     }
 }
 
-fn report_bivariance(tcx: TyCtxt<'_>, param: &rustc_hir::GenericParam<'_>) -> ErrorReported {
+fn report_bivariance(
+    tcx: TyCtxt<'_>,
+    param: &rustc_hir::GenericParam<'_>,
+    has_explicit_bounds: bool,
+) -> ErrorReported {
     let span = param.span;
     let param_name = param.name.ident().name;
     let mut err = error_392(tcx, span, param_name);
@@ -1754,7 +1782,7 @@ fn report_bivariance(tcx: TyCtxt<'_>, param: &rustc_hir::GenericParam<'_>) -> Er
     };
     err.help(&msg);
 
-    if matches!(param.kind, rustc_hir::GenericParamKind::Type { .. }) {
+    if matches!(param.kind, hir::GenericParamKind::Type { .. }) && !has_explicit_bounds {
         err.help(&format!(
             "if you intended `{0}` to be a const parameter, use `const {0}: usize` instead",
             param_name
diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs
index 40904c1dfd6..f0289fd505a 100644
--- a/compiler/rustc_typeck/src/lib.rs
+++ b/compiler/rustc_typeck/src/lib.rs
@@ -68,6 +68,7 @@ This API is completely unstable and subject to change.
 #![feature(slice_partition_dedup)]
 #![feature(control_flow_enum)]
 #![feature(hash_drain_filter)]
+#![feature(once_cell)]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
 
diff --git a/src/test/ui/issues/issue-17904-2.stderr b/src/test/ui/issues/issue-17904-2.stderr
index 259e029113d..62b7b79538c 100644
--- a/src/test/ui/issues/issue-17904-2.stderr
+++ b/src/test/ui/issues/issue-17904-2.stderr
@@ -5,7 +5,6 @@ LL | struct Foo<T> where T: Copy;
    |            ^ unused parameter
    |
    = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
-   = help: if you intended `T` to be a const parameter, use `const T: usize` instead
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-37534.stderr b/src/test/ui/issues/issue-37534.stderr
index 82bb51028c9..895479986f1 100644
--- a/src/test/ui/issues/issue-37534.stderr
+++ b/src/test/ui/issues/issue-37534.stderr
@@ -22,7 +22,6 @@ LL | struct Foo<T: ?Hash> { }
    |            ^ unused parameter
    |
    = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
-   = help: if you intended `T` to be a const parameter, use `const T: usize` instead
 
 error: aborting due to 2 previous errors; 1 warning emitted
 
diff --git a/src/test/ui/variance/variance-unused-type-param.rs b/src/test/ui/variance/variance-unused-type-param.rs
index 1e0e403ebce..d1114064364 100644
--- a/src/test/ui/variance/variance-unused-type-param.rs
+++ b/src/test/ui/variance/variance-unused-type-param.rs
@@ -16,4 +16,13 @@ enum ListCell<T> {
     Nil
 }
 
+struct WithBounds<T: Sized> {}
+//~^ ERROR parameter `T` is never used
+
+struct WithWhereBounds<T> where T: Sized {}
+//~^ ERROR parameter `T` is never used
+
+struct WithOutlivesBounds<T: 'static> {}
+//~^ ERROR parameter `T` is never used
+
 fn main() {}
diff --git a/src/test/ui/variance/variance-unused-type-param.stderr b/src/test/ui/variance/variance-unused-type-param.stderr
index 270233c0c97..e612da118f0 100644
--- a/src/test/ui/variance/variance-unused-type-param.stderr
+++ b/src/test/ui/variance/variance-unused-type-param.stderr
@@ -25,6 +25,30 @@ LL | enum ListCell<T> {
    = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
    = help: if you intended `T` to be a const parameter, use `const T: usize` instead
 
-error: aborting due to 3 previous errors
+error[E0392]: parameter `T` is never used
+  --> $DIR/variance-unused-type-param.rs:19:19
+   |
+LL | struct WithBounds<T: Sized> {}
+   |                   ^ unused parameter
+   |
+   = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+
+error[E0392]: parameter `T` is never used
+  --> $DIR/variance-unused-type-param.rs:22:24
+   |
+LL | struct WithWhereBounds<T> where T: Sized {}
+   |                        ^ unused parameter
+   |
+   = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+
+error[E0392]: parameter `T` is never used
+  --> $DIR/variance-unused-type-param.rs:25:27
+   |
+LL | struct WithOutlivesBounds<T: 'static> {}
+   |                           ^ unused parameter
+   |
+   = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0392`.