about summary refs log tree commit diff
path: root/compiler/rustc_trait_selection/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-06-02 07:57:21 +0000
committerbors <bors@rust-lang.org>2023-06-02 07:57:21 +0000
commit8ebf04225d358efe77b822081cebef657f88d35b (patch)
tree807d30f8b7320a1278878c0a7358b358d9eeca66 /compiler/rustc_trait_selection/src
parent33c3d101280c8eb3cd8af421bfb56a8afcc3881d (diff)
parentebb7f642e46f2f95ab9c1c82e5a7640876bf2776 (diff)
Auto merge of #112198 - compiler-errors:rollup-o2xe4of, r=compiler-errors
Rollup of 7 pull requests

Successful merges:

 - #111670 (Require that const param tys implement `ConstParamTy`)
 - #111914 (CFI: Fix cfi with async: transform_ty: unexpected GeneratorWitness(Bi…)
 - #112030 (Migrate `item_trait_alias` to Askama)
 - #112150 (Support 128-bit atomics on all x86_64 Apple targets)
 - #112174 (Fix broken link)
 - #112190 (Improve comments on `TyCtxt` and `GlobalCtxt`.)
 - #112193 (Check tuple elements are `Sized` in `offset_of`)

Failed merges:

 - #112071 (Group rfcs tests)

r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'compiler/rustc_trait_selection/src')
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs110
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/misc.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/structural_match.rs70
5 files changed, 133 insertions, 57 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 1470dc452a1..01c74be7057 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -149,6 +149,12 @@ pub trait TypeErrCtxtExt<'tcx> {
         root_obligation: &PredicateObligation<'tcx>,
         error: &SelectionError<'tcx>,
     );
+
+    fn report_const_param_not_wf(
+        &self,
+        ty: Ty<'tcx>,
+        obligation: &PredicateObligation<'tcx>,
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
 }
 
 impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
@@ -641,6 +647,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         span = obligation.cause.span;
                     }
                 }
+
                 if let ObligationCauseCode::CompareImplItemObligation {
                     impl_item_def_id,
                     trait_item_def_id,
@@ -657,6 +664,13 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                     return;
                 }
 
+                // Report a const-param specific error
+                if let ObligationCauseCode::ConstParam(ty) = *obligation.cause.code().peel_derives()
+                {
+                    self.report_const_param_not_wf(ty, &obligation).emit();
+                    return;
+                }
+
                 let bound_predicate = obligation.predicate.kind();
                 match bound_predicate.skip_binder() {
                     ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => {
@@ -1163,6 +1177,102 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         self.point_at_returns_when_relevant(&mut err, &obligation);
         err.emit();
     }
+
+    fn report_const_param_not_wf(
+        &self,
+        ty: Ty<'tcx>,
+        obligation: &PredicateObligation<'tcx>,
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+        let span = obligation.cause.span;
+
+        let mut diag = match ty.kind() {
+            _ if ty.has_param() => {
+                span_bug!(span, "const param tys cannot mention other generic parameters");
+            }
+            ty::Float(_) => {
+                struct_span_err!(
+                    self.tcx.sess,
+                    span,
+                    E0741,
+                    "`{ty}` is forbidden as the type of a const generic parameter",
+                )
+            }
+            ty::FnPtr(_) => {
+                struct_span_err!(
+                    self.tcx.sess,
+                    span,
+                    E0741,
+                    "using function pointers as const generic parameters is forbidden",
+                )
+            }
+            ty::RawPtr(_) => {
+                struct_span_err!(
+                    self.tcx.sess,
+                    span,
+                    E0741,
+                    "using raw pointers as const generic parameters is forbidden",
+                )
+            }
+            ty::Adt(def, _) => {
+                // We should probably see if we're *allowed* to derive `ConstParamTy` on the type...
+                let mut diag = struct_span_err!(
+                    self.tcx.sess,
+                    span,
+                    E0741,
+                    "`{ty}` must implement `ConstParamTy` to be used as the type of a const generic parameter",
+                );
+                // Only suggest derive if this isn't a derived obligation,
+                // and the struct is local.
+                if let Some(span) = self.tcx.hir().span_if_local(def.did())
+                    && obligation.cause.code().parent().is_none()
+                {
+                    if ty.is_structural_eq_shallow(self.tcx) {
+                        diag.span_suggestion(
+                            span,
+                            "add `#[derive(ConstParamTy)]` to the struct",
+                            "#[derive(ConstParamTy)]\n",
+                            Applicability::MachineApplicable,
+                        );
+                    } else {
+                        // FIXME(adt_const_params): We should check there's not already an
+                        // overlapping `Eq`/`PartialEq` impl.
+                        diag.span_suggestion(
+                            span,
+                            "add `#[derive(ConstParamTy, PartialEq, Eq)]` to the struct",
+                            "#[derive(ConstParamTy, PartialEq, Eq)]\n",
+                            Applicability::MachineApplicable,
+                        );
+                    }
+                }
+                diag
+            }
+            _ => {
+                struct_span_err!(
+                    self.tcx.sess,
+                    span,
+                    E0741,
+                    "`{ty}` can't be used as a const parameter type",
+                )
+            }
+        };
+
+        let mut code = obligation.cause.code();
+        let mut pred = obligation.predicate.to_opt_poly_trait_pred();
+        while let Some((next_code, next_pred)) = code.parent() {
+            if let Some(pred) = pred {
+                let pred = self.instantiate_binder_with_placeholders(pred);
+                diag.note(format!(
+                    "`{}` must implement `{}`, but it does not",
+                    pred.self_ty(),
+                    pred.print_modifiers_and_trait_path()
+                ));
+            }
+            code = next_code;
+            pred = next_pred;
+        }
+
+        diag
+    }
 }
 
 trait InferCtxtPrivExt<'tcx> {
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index b5b8c7fe3ac..204d6fd043b 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -2655,7 +2655,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             | ObligationCauseCode::BinOp { .. }
             | ObligationCauseCode::AscribeUserTypeProvePredicate(..)
             | ObligationCauseCode::RustCall
-            | ObligationCauseCode::DropImpl => {}
+            | ObligationCauseCode::DropImpl
+            | ObligationCauseCode::ConstParam(_) => {}
             ObligationCauseCode::SliceOrArrayElem => {
                 err.note("slice and array elements must have `Sized` type");
             }
diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs
index 2210ef975e6..e9cfd63e2ed 100644
--- a/compiler/rustc_trait_selection/src/traits/misc.rs
+++ b/compiler/rustc_trait_selection/src/traits/misc.rs
@@ -100,7 +100,8 @@ pub fn type_allowed_to_implement_const_param_ty<'tcx>(
         | ty::Str
         | ty::Array(..)
         | ty::Slice(_)
-        | ty::Ref(.., hir::Mutability::Not) => return Ok(()),
+        | ty::Ref(.., hir::Mutability::Not)
+        | ty::Tuple(_) => return Ok(()),
 
         &ty::Adt(adt, substs) => (adt, substs),
 
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index f7389bda159..c2f94cb6385 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -62,9 +62,7 @@ pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind;
 pub use self::specialize::{
     specialization_graph, translate_substs, translate_substs_with_cause, OverlapError,
 };
-pub use self::structural_match::{
-    search_for_adt_const_param_violation, search_for_structural_match_violation,
-};
+pub use self::structural_match::search_for_structural_match_violation;
 pub use self::structural_normalize::StructurallyNormalizeExt;
 pub use self::util::elaborate;
 pub use self::util::{expand_trait_aliases, TraitAliasExpander};
diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs
index e38ae9381c1..420f8c5dceb 100644
--- a/compiler/rustc_trait_selection/src/traits/structural_match.rs
+++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs
@@ -34,24 +34,7 @@ pub fn search_for_structural_match_violation<'tcx>(
     tcx: TyCtxt<'tcx>,
     ty: Ty<'tcx>,
 ) -> Option<Ty<'tcx>> {
-    ty.visit_with(&mut Search { tcx, span, seen: FxHashSet::default(), adt_const_param: false })
-        .break_value()
-}
-
-/// This method traverses the structure of `ty`, trying to find any
-/// types that are not allowed to be used in a const generic.
-///
-/// This is either because the type does not implement `StructuralEq`
-/// and `StructuralPartialEq`, or because the type is intentionally
-/// not supported in const generics (such as floats and raw pointers,
-/// which are allowed in match blocks).
-pub fn search_for_adt_const_param_violation<'tcx>(
-    span: Span,
-    tcx: TyCtxt<'tcx>,
-    ty: Ty<'tcx>,
-) -> Option<Ty<'tcx>> {
-    ty.visit_with(&mut Search { tcx, span, seen: FxHashSet::default(), adt_const_param: true })
-        .break_value()
+    ty.visit_with(&mut Search { tcx, span, seen: FxHashSet::default() }).break_value()
 }
 
 /// This implements the traversal over the structure of a given type to try to
@@ -65,11 +48,6 @@ struct Search<'tcx> {
     /// Tracks ADTs previously encountered during search, so that
     /// we will not recur on them again.
     seen: FxHashSet<hir::def_id::DefId>,
-
-    // Additionally deny things that have been allowed in patterns,
-    // but are not allowed in adt const params, such as floats and
-    // fn ptrs.
-    adt_const_param: bool,
 }
 
 impl<'tcx> Search<'tcx> {
@@ -124,41 +102,29 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Search<'tcx> {
             }
 
             ty::FnPtr(..) => {
-                if !self.adt_const_param {
-                    return ControlFlow::Continue(());
-                } else {
-                    return ControlFlow::Break(ty);
-                }
+                return ControlFlow::Continue(());
             }
 
             ty::RawPtr(..) => {
-                if !self.adt_const_param {
-                    // structural-match ignores substructure of
-                    // `*const _`/`*mut _`, so skip `super_visit_with`.
-                    //
-                    // For example, if you have:
-                    // ```
-                    // struct NonStructural;
-                    // #[derive(PartialEq, Eq)]
-                    // struct T(*const NonStructural);
-                    // const C: T = T(std::ptr::null());
-                    // ```
-                    //
-                    // Even though `NonStructural` does not implement `PartialEq`,
-                    // structural equality on `T` does not recur into the raw
-                    // pointer. Therefore, one can still use `C` in a pattern.
-                    return ControlFlow::Continue(());
-                } else {
-                    return ControlFlow::Break(ty);
-                }
+                // structural-match ignores substructure of
+                // `*const _`/`*mut _`, so skip `super_visit_with`.
+                //
+                // For example, if you have:
+                // ```
+                // struct NonStructural;
+                // #[derive(PartialEq, Eq)]
+                // struct T(*const NonStructural);
+                // const C: T = T(std::ptr::null());
+                // ```
+                //
+                // Even though `NonStructural` does not implement `PartialEq`,
+                // structural equality on `T` does not recur into the raw
+                // pointer. Therefore, one can still use `C` in a pattern.
+                return ControlFlow::Continue(());
             }
 
             ty::Float(_) => {
-                if !self.adt_const_param {
-                    return ControlFlow::Continue(());
-                } else {
-                    return ControlFlow::Break(ty);
-                }
+                return ControlFlow::Continue(());
             }
 
             ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => {