about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_typeck/src/check/wfcheck.rs53
-rw-r--r--src/test/ui/const-generics/defaults/complex-generic-default-expr.min.stderr4
-rw-r--r--src/test/ui/const-generics/defaults/complex-generic-default-expr.rs8
-rw-r--r--src/test/ui/const-generics/defaults/const-param-as-default-value.rs14
-rw-r--r--src/test/ui/const-generics/defaults/const-param-in-ty-defaults.rs18
-rw-r--r--src/test/ui/const-generics/defaults/default-param-wf-concrete.rs5
-rw-r--r--src/test/ui/const-generics/defaults/default-param-wf-concrete.stderr9
-rw-r--r--src/test/ui/const-generics/defaults/pretty-printing-ast.rs1
8 files changed, 94 insertions, 18 deletions
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index 887cc42a1dd..26871d6f028 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -728,20 +728,36 @@ fn check_where_clauses<'tcx, 'fcx>(
     //
     // Here, the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold.
     for param in &generics.params {
-        if let GenericParamDefKind::Type { .. } = param.kind {
-            if is_our_default(&param) {
-                let ty = fcx.tcx.type_of(param.def_id);
-                // Ignore dependent defaults -- that is, where the default of one type
-                // parameter includes another (e.g., `<T, U = T>`). In those cases, we can't
-                // be sure if it will error or not as user might always specify the other.
-                if !ty.needs_subst() {
+        match param.kind {
+            GenericParamDefKind::Type { .. } => {
+                if is_our_default(&param) {
+                    let ty = fcx.tcx.type_of(param.def_id);
+                    // Ignore dependent defaults -- that is, where the default of one type
+                    // parameter includes another (e.g., `<T, U = T>`). In those cases, we can't
+                    // be sure if it will error or not as user might always specify the other.
+                    if !ty.needs_subst() {
+                        fcx.register_wf_obligation(
+                            ty.into(),
+                            fcx.tcx.def_span(param.def_id),
+                            ObligationCauseCode::MiscObligation,
+                        );
+                    }
+                }
+            }
+            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) {
+                    let default_ct = tcx.const_param_default(param.def_id);
                     fcx.register_wf_obligation(
-                        ty.into(),
+                        default_ct.into(),
                         fcx.tcx.def_span(param.def_id),
                         ObligationCauseCode::MiscObligation,
                     );
                 }
             }
+            // Doesn't have defaults.
+            GenericParamDefKind::Lifetime => {}
         }
     }
 
@@ -774,14 +790,25 @@ fn check_where_clauses<'tcx, 'fcx>(
                 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);
-                    // Const params currently have to be concrete.
-                    assert!(!default_ct.needs_subst());
-                    default_ct.into()
-                } else {
-                    fcx.tcx.mk_param_from_def(param)
+                    // ... and it's not a dependent default, ...
+                    if !default_ct.needs_subst() {
+                        // ... then substitute it with the default.
+                        return default_ct.into();
+                    }
                 }
+
+                fcx.tcx.mk_param_from_def(param)
             }
         }
     });
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 d50a0a61d49..7d51e9aa0f3 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:10:47
    |
 LL | struct Foo<const N: usize, const M: usize = { N + 1 }>;
    |                                               ^ cannot perform const operation using `N`
@@ -8,7 +8,7 @@ LL | struct Foo<const N: usize, const M: usize = { N + 1 }>;
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/complex-generic-default-expr.rs:9:62
+  --> $DIR/complex-generic-default-expr.rs:13:62
    |
 LL | struct Bar<T, const TYPE_SIZE: usize = { std::mem::size_of::<T>() }>(T);
    |                                                              ^ cannot perform const operation using `T`
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 1c25fda8d30..a1c04b5e7c3 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,4 +1,8 @@
-// revisions: full min
+// revisions: min
+// FIXME(const_generics): add the `full` revision,
+// currently causes an ICE as we don't supply substs to
+// anon consts in the parameter listing, as that would
+// cause that anon const to reference itself.
 #![cfg_attr(full, feature(const_generics))]
 #![feature(const_generics_defaults)]
 #![allow(incomplete_features)]
@@ -8,6 +12,6 @@ struct Foo<const N: usize, const M: usize = { N + 1 }>;
 
 struct Bar<T, const TYPE_SIZE: usize = { std::mem::size_of::<T>() }>(T);
 //[min]~^ ERROR generic parameters may not be used in const operations
-//[full]~^^ ERROR the size for values of type `T` cannot be known at compilation time 
+//[full]~^^ ERROR the size for values of type `T` cannot be known at compilation time
 
 fn main() {}
diff --git a/src/test/ui/const-generics/defaults/const-param-as-default-value.rs b/src/test/ui/const-generics/defaults/const-param-as-default-value.rs
new file mode 100644
index 00000000000..d9cab34327e
--- /dev/null
+++ b/src/test/ui/const-generics/defaults/const-param-as-default-value.rs
@@ -0,0 +1,14 @@
+// run-pass
+#![feature(const_generics_defaults)]
+#![allow(incomplete_features)]
+struct Foo<const N: usize, const M: usize = N>([u8; N], [u8; M]);
+
+fn foo<const N: usize>() -> Foo<N> {
+    let x = [0; N];
+    Foo(x, x)
+}
+
+fn main() {
+    let val = foo::<13>();
+    assert_eq!(val.0, val.1);
+}
diff --git a/src/test/ui/const-generics/defaults/const-param-in-ty-defaults.rs b/src/test/ui/const-generics/defaults/const-param-in-ty-defaults.rs
new file mode 100644
index 00000000000..e3d78fe2ee0
--- /dev/null
+++ b/src/test/ui/const-generics/defaults/const-param-in-ty-defaults.rs
@@ -0,0 +1,18 @@
+// run-pass
+#![feature(const_generics_defaults)]
+#![allow(incomplete_features)]
+// FIXME(const_generics_defaults): while we can allow this,
+// we probably won't easily allow this with more complex const operations.
+//
+// So we have to make a conscious decision here when stabilizing a relaxed parameter ordering.
+struct Foo<const N: usize, T = [u8; N]>(T);
+
+impl<const N: usize> Foo<N> {
+    fn new() -> Self {
+        Foo([0; N])
+    }
+}
+
+fn main() {
+    assert_eq!(Foo::new().0, [0; 10]);
+}
diff --git a/src/test/ui/const-generics/defaults/default-param-wf-concrete.rs b/src/test/ui/const-generics/defaults/default-param-wf-concrete.rs
new file mode 100644
index 00000000000..4bb56c6a1c0
--- /dev/null
+++ b/src/test/ui/const-generics/defaults/default-param-wf-concrete.rs
@@ -0,0 +1,5 @@
+#![feature(const_generics_defaults)]
+#![allow(incomplete_features)]
+struct Foo<const N: u8 = { 255 + 1 }>;
+//~^ ERROR evaluation of constant value failed
+fn main() {}
diff --git a/src/test/ui/const-generics/defaults/default-param-wf-concrete.stderr b/src/test/ui/const-generics/defaults/default-param-wf-concrete.stderr
new file mode 100644
index 00000000000..8464ea98bf6
--- /dev/null
+++ b/src/test/ui/const-generics/defaults/default-param-wf-concrete.stderr
@@ -0,0 +1,9 @@
+error[E0080]: evaluation of constant value failed
+  --> $DIR/default-param-wf-concrete.rs:3:28
+   |
+LL | struct Foo<const N: u8 = { 255 + 1 }>;
+   |                            ^^^^^^^ attempt to compute `u8::MAX + 1_u8`, which would overflow
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/const-generics/defaults/pretty-printing-ast.rs b/src/test/ui/const-generics/defaults/pretty-printing-ast.rs
index 12a92a10476..7a57950dfc9 100644
--- a/src/test/ui/const-generics/defaults/pretty-printing-ast.rs
+++ b/src/test/ui/const-generics/defaults/pretty-printing-ast.rs
@@ -11,4 +11,3 @@ trait Foo<const KIND: bool = true> {}
 fn foo<const SIZE: usize = 5>() {}
 
 struct Range<const FROM: usize = 0, const LEN: usize = 0, const TO: usize = FROM>;
-