From 4a53b115181a16d681dc05b312bbc913b7f836ac Mon Sep 17 00:00:00 2001
From: lcnr <rust@lcnr.de>
Date: Thu, 8 Jul 2021 22:57:10 +0200
Subject: [PATCH] only check cg defaults wf once instantiated

---
 compiler/rustc_typeck/src/check/wfcheck.rs    | 26 ++++++++-----------
 compiler/rustc_typeck/src/collect.rs          | 10 +++++++
 .../unused-complex-default-expr.rs            |  6 +++++
 .../complex-generic-default-expr.full.stderr  | 18 -------------
 .../complex-generic-default-expr.min.stderr   |  2 +-
 .../defaults/complex-generic-default-expr.rs  |  7 +++--
 6 files changed, 31 insertions(+), 38 deletions(-)
 create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/unused-complex-default-expr.rs
 delete mode 100644 src/test/ui/const-generics/defaults/complex-generic-default-expr.full.stderr

diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index 0e063c86f2f4e..4838d70a83186 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -738,15 +738,19 @@ fn check_where_clauses<'tcx, 'fcx>(
                 }
             }
             GenericParamDefKind::Const { .. } => {
-                // FIXME(const_generics_defaults): Figure out if this
-                // is the behavior we want, see the comment further below.
                 if is_our_default(&param) {
+                    // FIXME(const_generics_defaults): This
+                    // is incorrect when dealing with unused substs, for example
+                    // for `struct Foo<const N: usize, const M: usize = { 1 - 2 }>`
+                    // we should eagerly error.
                     let default_ct = tcx.const_param_default(param.def_id);
-                    fcx.register_wf_obligation(
-                        default_ct.into(),
-                        tcx.def_span(param.def_id),
-                        ObligationCauseCode::MiscObligation,
-                    );
+                    if !default_ct.needs_subst() {
+                        fcx.register_wf_obligation(
+                            default_ct.into(),
+                            tcx.def_span(param.def_id),
+                            ObligationCauseCode::MiscObligation,
+                        );
+                    }
                 }
             }
             // Doesn't have defaults.
@@ -783,14 +787,6 @@ fn check_where_clauses<'tcx, 'fcx>(
                 tcx.mk_param_from_def(param)
             }
             GenericParamDefKind::Const { .. } => {
-                // FIXME(const_generics_defaults): I(@lcnr) feel like always
-                // using the const parameter is the right choice here, even
-                // if it needs substs.
-                //
-                // Before stabilizing this we probably want to get some tests
-                // where this makes a difference and figure out what's the exact
-                // behavior we want here.
-
                 // If the param has a default, ...
                 if is_our_default(param) {
                     let default_ct = tcx.const_param_default(param.def_id);
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index b0e5453b7db92..583ba9392f062 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -2308,6 +2308,16 @@ fn const_evaluatable_predicates_of<'tcx>(
                 ));
             }
         }
+
+        fn visit_const_param_default(&mut self, _param: HirId, _ct: &'tcx hir::AnonConst) {
+            // Do not look into const param defaults,
+            // these get checked when they are actually instantiated.
+            //
+            // We do not want the following to error:
+            //
+            //     struct Foo<const N: usize, const M: usize = { N + 1 }>;
+            //     struct Bar<const N: usize>(Foo<N, 3>);
+        }
     }
 
     let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/unused-complex-default-expr.rs b/src/test/ui/const-generics/const_evaluatable_checked/unused-complex-default-expr.rs
new file mode 100644
index 0000000000000..21f14f58ab5af
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/unused-complex-default-expr.rs
@@ -0,0 +1,6 @@
+// check-pass
+#![feature(const_generics, const_evaluatable_checked, const_generics_defaults)]
+#![allow(incomplete_features)]
+struct Foo<const N: usize, const M: usize = { N + 1 }>;
+struct Bar<const N: usize>(Foo<N, 3>);
+fn main() {}
diff --git a/src/test/ui/const-generics/defaults/complex-generic-default-expr.full.stderr b/src/test/ui/const-generics/defaults/complex-generic-default-expr.full.stderr
deleted file mode 100644
index e0e2b6c69f280..0000000000000
--- a/src/test/ui/const-generics/defaults/complex-generic-default-expr.full.stderr
+++ /dev/null
@@ -1,18 +0,0 @@
-error: constant expression depends on a generic parameter
-  --> $DIR/complex-generic-default-expr.rs:6:34
-   |
-LL | struct Foo<const N: usize, const M: usize = { N + 1 }>;
-   |                                  ^
-   |
-   = note: this may fail depending on what value the parameter takes
-
-error: constant expression depends on a generic parameter
-  --> $DIR/complex-generic-default-expr.rs:10:21
-   |
-LL | struct Bar<T, const TYPE_SIZE: usize = { std::mem::size_of::<T>() }>(T);
-   |                     ^^^^^^^^^
-   |
-   = note: this may fail depending on what value the parameter takes
-
-error: aborting due to 2 previous errors
-
diff --git a/src/test/ui/const-generics/defaults/complex-generic-default-expr.min.stderr b/src/test/ui/const-generics/defaults/complex-generic-default-expr.min.stderr
index 58abd8db9f09f..44df2ac9f40fa 100644
--- a/src/test/ui/const-generics/defaults/complex-generic-default-expr.min.stderr
+++ b/src/test/ui/const-generics/defaults/complex-generic-default-expr.min.stderr
@@ -1,5 +1,5 @@
 error: generic parameters may not be used in const operations
-  --> $DIR/complex-generic-default-expr.rs:6:47
+  --> $DIR/complex-generic-default-expr.rs:7:47
    |
 LL | struct Foo<const N: usize, const M: usize = { N + 1 }>;
    |                                               ^ cannot perform const operation using `N`
diff --git a/src/test/ui/const-generics/defaults/complex-generic-default-expr.rs b/src/test/ui/const-generics/defaults/complex-generic-default-expr.rs
index a7b712f7b4b86..d3558007977e4 100644
--- a/src/test/ui/const-generics/defaults/complex-generic-default-expr.rs
+++ b/src/test/ui/const-generics/defaults/complex-generic-default-expr.rs
@@ -1,14 +1,13 @@
 // revisions: full min
+//[full] check-pass
 #![cfg_attr(full, feature(const_generics))]
 #![feature(const_generics_defaults)]
 #![allow(incomplete_features)]
 
 struct Foo<const N: usize, const M: usize = { N + 1 }>;
-//[full]~^ ERROR constant expression depends on a generic parameter
-//[min]~^^ ERROR generic parameters may not be used in const operations
+//[min]~^ ERROR generic parameters may not be used in const operations
 
 struct Bar<T, const TYPE_SIZE: usize = { std::mem::size_of::<T>() }>(T);
-//[full]~^ ERROR constant expression depends on a generic parameter
-//[min]~^^ ERROR generic parameters may not be used in const operations
+//[min]~^ ERROR generic parameters may not be used in const operations
 
 fn main() {}