about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_ast/ast.rs37
-rw-r--r--src/librustc_ast_passes/ast_validation.rs18
-rw-r--r--src/librustc_typeck/astconv.rs28
-rw-r--r--src/test/ui/const-generics/argument_order.rs7
-rw-r--r--src/test/ui/const-generics/argument_order.stderr29
-rw-r--r--src/test/ui/const-generics/const-arg-type-arg-misordered.rs2
-rw-r--r--src/test/ui/const-generics/const-arg-type-arg-misordered.stderr14
-rw-r--r--src/test/ui/const-generics/const-param-before-other-params.rs4
-rw-r--r--src/test/ui/const-generics/const-param-before-other-params.stderr10
-rw-r--r--src/test/ui/const-generics/defaults/complex-unord-param.rs20
-rw-r--r--src/test/ui/const-generics/defaults/intermixed-lifetime.rs12
-rw-r--r--src/test/ui/const-generics/defaults/intermixed-lifetime.stderr14
-rw-r--r--src/test/ui/const-generics/defaults/needs-feature.min.stderr8
-rw-r--r--src/test/ui/const-generics/defaults/needs-feature.none.stderr18
-rw-r--r--src/test/ui/const-generics/defaults/needs-feature.rs17
-rw-r--r--src/test/ui/const-generics/defaults/simple-defaults.rs15
-rw-r--r--src/test/ui/const-generics/type-after-const-ok.rs10
-rw-r--r--src/test/ui/issues/issue-59508-1.stderr2
18 files changed, 190 insertions, 75 deletions
diff --git a/src/librustc_ast/ast.rs b/src/librustc_ast/ast.rs
index 83a9de84ed8..a0541158bc2 100644
--- a/src/librustc_ast/ast.rs
+++ b/src/librustc_ast/ast.rs
@@ -35,6 +35,7 @@ use rustc_span::source_map::{respan, Spanned};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 
+use std::cmp::Ordering;
 use std::convert::TryFrom;
 use std::fmt;
 use std::iter;
@@ -309,19 +310,49 @@ pub type GenericBounds = Vec<GenericBound>;
 /// Specifies the enforced ordering for generic parameters. In the future,
 /// if we wanted to relax this order, we could override `PartialEq` and
 /// `PartialOrd`, to allow the kinds to be unordered.
-#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
+#[derive(Hash, Clone, Copy)]
 pub enum ParamKindOrd {
     Lifetime,
     Type,
-    Const,
+    // `unordered` is only `true` if `sess.has_features().const_generics`
+    // is active. Specifically, if it's only `min_const_generics`, it will still require
+    // ordering consts after types.
+    Const { unordered: bool },
+}
+
+impl Ord for ParamKindOrd {
+    fn cmp(&self, other: &Self) -> Ordering {
+        use ParamKindOrd::*;
+        let to_int = |v| match v {
+            Lifetime => 0,
+            Type | Const { unordered: true } => 1,
+            // technically both consts should be ordered equally,
+            // but only one is ever encountered at a time, so this is
+            // fine.
+            Const { unordered: false } => 2,
+        };
+
+        to_int(*self).cmp(&to_int(*other))
+    }
+}
+impl PartialOrd for ParamKindOrd {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+impl PartialEq for ParamKindOrd {
+    fn eq(&self, other: &Self) -> bool {
+        self.cmp(other) == Ordering::Equal
+    }
 }
+impl Eq for ParamKindOrd {}
 
 impl fmt::Display for ParamKindOrd {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
             ParamKindOrd::Lifetime => "lifetime".fmt(f),
             ParamKindOrd::Type => "type".fmt(f),
-            ParamKindOrd::Const => "const".fmt(f),
+            ParamKindOrd::Const { .. } => "const".fmt(f),
         }
     }
 }
diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs
index 45a026d4b53..244377dfa1d 100644
--- a/src/librustc_ast_passes/ast_validation.rs
+++ b/src/librustc_ast_passes/ast_validation.rs
@@ -773,13 +773,13 @@ fn validate_generic_param_order<'a>(
         err.span_suggestion(
             span,
             &format!(
-                "reorder the parameters: lifetimes, then types{}",
-                if sess.features_untracked().const_generics
-                    || sess.features_untracked().min_const_generics
-                {
-                    ", then consts"
+                "reorder the parameters: lifetimes{}",
+                if sess.features_untracked().const_generics {
+                    ", then consts and types"
+                } else if sess.features_untracked().min_const_generics {
+                    ", then consts, then types"
                 } else {
-                    ""
+                    ", then types"
                 },
             ),
             ordered_params.clone(),
@@ -1156,7 +1156,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident),
                     GenericParamKind::Const { ref ty, kw_span: _ } => {
                         let ty = pprust::ty_to_string(ty);
-                        (ParamKindOrd::Const, Some(format!("const {}: {}", param.ident, ty)))
+                        let unordered = self.session.features_untracked().const_generics;
+                        (
+                            ParamKindOrd::Const { unordered },
+                            Some(format!("const {}: {}", param.ident, ty)),
+                        )
                     }
                 };
                 (kind, Some(&*param.bounds), param.ident.span, ident)
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 79d2f104a52..2be100ae336 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -489,10 +489,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             kind,
         );
 
+        let unordered = sess.features_untracked().const_generics;
         let kind_ord = match kind {
             "lifetime" => ParamKindOrd::Lifetime,
             "type" => ParamKindOrd::Type,
-            "constant" => ParamKindOrd::Const,
+            "constant" => ParamKindOrd::Const { unordered },
             // It's more concise to match on the string representation, though it means
             // the match is non-exhaustive.
             _ => bug!("invalid generic parameter kind {}", kind),
@@ -500,17 +501,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         let arg_ord = match arg {
             GenericArg::Lifetime(_) => ParamKindOrd::Lifetime,
             GenericArg::Type(_) => ParamKindOrd::Type,
-            GenericArg::Const(_) => ParamKindOrd::Const,
+            GenericArg::Const(_) => ParamKindOrd::Const { unordered },
         };
 
-        // This note will be true as long as generic parameters are strictly ordered by their kind.
-        let (first, last) =
-            if kind_ord < arg_ord { (kind, arg.descr()) } else { (arg.descr(), kind) };
-        err.note(&format!("{} arguments must be provided before {} arguments", first, last));
-
-        if let Some(help) = help {
-            err.help(help);
+        // This note is only true when generic parameters are strictly ordered by their kind.
+        if kind_ord.cmp(&arg_ord) != core::cmp::Ordering::Equal {
+            let (first, last) =
+                if kind_ord < arg_ord { (kind, arg.descr()) } else { (arg.descr(), kind) };
+            err.note(&format!("{} arguments must be provided before {} arguments", first, last));
+            if let Some(help) = help {
+                err.help(help);
+            }
         }
+
         err.emit();
     }
 
@@ -672,7 +675,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                                                         ParamKindOrd::Type
                                                     }
                                                     GenericParamDefKind::Const => {
-                                                        ParamKindOrd::Const
+                                                        ParamKindOrd::Const {
+                                                            unordered: tcx
+                                                                .sess
+                                                                .features_untracked()
+                                                                .const_generics,
+                                                        }
                                                     }
                                                 },
                                                 param,
diff --git a/src/test/ui/const-generics/argument_order.rs b/src/test/ui/const-generics/argument_order.rs
index 1d1adf39434..9e071e674e7 100644
--- a/src/test/ui/const-generics/argument_order.rs
+++ b/src/test/ui/const-generics/argument_order.rs
@@ -1,14 +1,13 @@
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+#![allow(incomplete_features)]
 
-struct Bad<const N: usize, T> { //~ ERROR type parameters must be declared prior
+struct Bad<const N: usize, T> {
     arr: [u8; { N }],
     another: T,
 }
 
 struct AlsoBad<const N: usize, 'a, T, 'b, const M: usize, U> {
-    //~^ ERROR type parameters must be declared prior
-    //~| ERROR lifetime parameters must be declared prior
+    //~^ ERROR lifetime parameters must be declared prior
     a: &'a T,
     b: &'b U,
 }
diff --git a/src/test/ui/const-generics/argument_order.stderr b/src/test/ui/const-generics/argument_order.stderr
index 19e895b8eb8..d6546a768d2 100644
--- a/src/test/ui/const-generics/argument_order.stderr
+++ b/src/test/ui/const-generics/argument_order.stderr
@@ -1,39 +1,18 @@
-error: type parameters must be declared prior to const parameters
-  --> $DIR/argument_order.rs:4:28
-   |
-LL | struct Bad<const N: usize, T> {
-   |           -----------------^- help: reorder the parameters: lifetimes, then types, then consts: `<T, const N: usize>`
-
 error: lifetime parameters must be declared prior to const parameters
   --> $DIR/argument_order.rs:9:32
    |
 LL | struct AlsoBad<const N: usize, 'a, T, 'b, const M: usize, U> {
-   |               -----------------^^-----^^-------------------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T, U, const N: usize, const M: usize>`
-
-error: type parameters must be declared prior to const parameters
-  --> $DIR/argument_order.rs:9:36
-   |
-LL | struct AlsoBad<const N: usize, 'a, T, 'b, const M: usize, U> {
-   |               ---------------------^----------------------^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T, U, const N: usize, const M: usize>`
-
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/argument_order.rs:1:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+   |               -----------------^^-----^^-------------------- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, const N: usize, T, const M: usize, U>`
 
 error[E0747]: lifetime provided when a type was expected
-  --> $DIR/argument_order.rs:17:23
+  --> $DIR/argument_order.rs:16:23
    |
 LL |     let _: AlsoBad<7, 'static, u32, 'static, 17, u16>;
    |                       ^^^^^^^
    |
    = note: lifetime arguments must be provided before type arguments
-   = help: reorder the arguments: lifetimes, then types, then consts: `<'a, 'b, T, U, N, M>`
+   = help: reorder the arguments: lifetimes, then consts: `<'a, 'b, N, T, M, U>`
 
-error: aborting due to 4 previous errors; 1 warning emitted
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0747`.
diff --git a/src/test/ui/const-generics/const-arg-type-arg-misordered.rs b/src/test/ui/const-generics/const-arg-type-arg-misordered.rs
index 9f989ee20a5..13ca56ad3e6 100644
--- a/src/test/ui/const-generics/const-arg-type-arg-misordered.rs
+++ b/src/test/ui/const-generics/const-arg-type-arg-misordered.rs
@@ -1,5 +1,5 @@
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+#![allow(incomplete_features)]
 
 type Array<T, const N: usize> = [T; N];
 
diff --git a/src/test/ui/const-generics/const-arg-type-arg-misordered.stderr b/src/test/ui/const-generics/const-arg-type-arg-misordered.stderr
index 4a6241de1b4..2e2bfed51fb 100644
--- a/src/test/ui/const-generics/const-arg-type-arg-misordered.stderr
+++ b/src/test/ui/const-generics/const-arg-type-arg-misordered.stderr
@@ -1,21 +1,9 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/const-arg-type-arg-misordered.rs:1:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
 error[E0747]: constant provided when a type was expected
   --> $DIR/const-arg-type-arg-misordered.rs:6:35
    |
 LL | fn foo<const N: usize>() -> Array<N, ()> {
    |                                   ^
-   |
-   = note: type arguments must be provided before constant arguments
-   = help: reorder the arguments: types, then consts: `<T, N>`
 
-error: aborting due to previous error; 1 warning emitted
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0747`.
diff --git a/src/test/ui/const-generics/const-param-before-other-params.rs b/src/test/ui/const-generics/const-param-before-other-params.rs
index 756e961ce91..0d787d9a67b 100644
--- a/src/test/ui/const-generics/const-param-before-other-params.rs
+++ b/src/test/ui/const-generics/const-param-before-other-params.rs
@@ -5,8 +5,6 @@ fn bar<const X: (), 'a>(_: &'a ()) {
     //~^ ERROR lifetime parameters must be declared prior to const parameters
 }
 
-fn foo<const X: (), T>(_: &T) {
-    //~^ ERROR type parameters must be declared prior to const parameters
-}
+fn foo<const X: (), T>(_: &T) {}
 
 fn main() {}
diff --git a/src/test/ui/const-generics/const-param-before-other-params.stderr b/src/test/ui/const-generics/const-param-before-other-params.stderr
index 9b18b8c79ed..1194dd30f61 100644
--- a/src/test/ui/const-generics/const-param-before-other-params.stderr
+++ b/src/test/ui/const-generics/const-param-before-other-params.stderr
@@ -2,13 +2,7 @@ error: lifetime parameters must be declared prior to const parameters
   --> $DIR/const-param-before-other-params.rs:4:21
    |
 LL | fn bar<const X: (), 'a>(_: &'a ()) {
-   |       --------------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, const X: ()>`
+   |       --------------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, const X: ()>`
 
-error: type parameters must be declared prior to const parameters
-  --> $DIR/const-param-before-other-params.rs:8:21
-   |
-LL | fn foo<const X: (), T>(_: &T) {
-   |       --------------^- help: reorder the parameters: lifetimes, then types, then consts: `<T, const X: ()>`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/defaults/complex-unord-param.rs b/src/test/ui/const-generics/defaults/complex-unord-param.rs
new file mode 100644
index 00000000000..72967640a8e
--- /dev/null
+++ b/src/test/ui/const-generics/defaults/complex-unord-param.rs
@@ -0,0 +1,20 @@
+// run-pass
+// Checks a complicated usage of unordered params
+
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+#![allow(dead_code)]
+
+struct NestedArrays<'a, const N: usize, A: 'a, const M: usize, T:'a =u32> {
+  args: &'a [&'a [T; M]; N],
+  specifier: A,
+}
+
+fn main() {
+  let array = [1, 2, 3];
+  let nest = [&array];
+  let _ = NestedArrays {
+    args: &nest,
+    specifier: true,
+  };
+}
diff --git a/src/test/ui/const-generics/defaults/intermixed-lifetime.rs b/src/test/ui/const-generics/defaults/intermixed-lifetime.rs
new file mode 100644
index 00000000000..ea3a8c14b98
--- /dev/null
+++ b/src/test/ui/const-generics/defaults/intermixed-lifetime.rs
@@ -0,0 +1,12 @@
+// Checks that lifetimes cannot be interspersed between consts and types.
+
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+struct Foo<const N: usize, 'a, T = u32>(&'a (), T);
+//~^ Error lifetime parameters must be declared prior to const parameters
+
+struct Bar<const N: usize, T = u32, 'a>(&'a (), T);
+//~^ Error lifetime parameters must be declared prior to type parameters
+
+fn main() {}
diff --git a/src/test/ui/const-generics/defaults/intermixed-lifetime.stderr b/src/test/ui/const-generics/defaults/intermixed-lifetime.stderr
new file mode 100644
index 00000000000..0f6d7f1065a
--- /dev/null
+++ b/src/test/ui/const-generics/defaults/intermixed-lifetime.stderr
@@ -0,0 +1,14 @@
+error: lifetime parameters must be declared prior to const parameters
+  --> $DIR/intermixed-lifetime.rs:6:28
+   |
+LL | struct Foo<const N: usize, 'a, T = u32>(&'a (), T);
+   |           -----------------^^---------- help: reorder the parameters: lifetimes, then consts and types: `<'a, const N: usize, T>`
+
+error: lifetime parameters must be declared prior to type parameters
+  --> $DIR/intermixed-lifetime.rs:9:37
+   |
+LL | struct Bar<const N: usize, T = u32, 'a>(&'a (), T);
+   |           --------------------------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, const N: usize, T>`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/const-generics/defaults/needs-feature.min.stderr b/src/test/ui/const-generics/defaults/needs-feature.min.stderr
new file mode 100644
index 00000000000..d57190ea3bb
--- /dev/null
+++ b/src/test/ui/const-generics/defaults/needs-feature.min.stderr
@@ -0,0 +1,8 @@
+error: type parameters must be declared prior to const parameters
+  --> $DIR/needs-feature.rs:10:26
+   |
+LL | struct A<const N: usize, T=u32>(T);
+   |         -----------------^----- help: reorder the parameters: lifetimes, then consts, then types: `<T, const N: usize>`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/defaults/needs-feature.none.stderr b/src/test/ui/const-generics/defaults/needs-feature.none.stderr
new file mode 100644
index 00000000000..3b6f63a8efe
--- /dev/null
+++ b/src/test/ui/const-generics/defaults/needs-feature.none.stderr
@@ -0,0 +1,18 @@
+error: type parameters must be declared prior to const parameters
+  --> $DIR/needs-feature.rs:10:26
+   |
+LL | struct A<const N: usize, T=u32>(T);
+   |         -----------------^----- help: reorder the parameters: lifetimes, then types: `<T, const N: usize>`
+
+error[E0658]: const generics are unstable
+  --> $DIR/needs-feature.rs:10:16
+   |
+LL | struct A<const N: usize, T=u32>(T);
+   |                ^
+   |
+   = note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
+   = help: add `#![feature(min_const_generics)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/const-generics/defaults/needs-feature.rs b/src/test/ui/const-generics/defaults/needs-feature.rs
new file mode 100644
index 00000000000..ec02dbf407d
--- /dev/null
+++ b/src/test/ui/const-generics/defaults/needs-feature.rs
@@ -0,0 +1,17 @@
+//[full] run-pass
+// Verifies that having generic parameters after constants is not permitted without the
+// `const_generics` feature.
+// revisions: none min full
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
+
+struct A<const N: usize, T=u32>(T);
+//[none]~^ ERROR type parameters must be declared prior
+//[none]~| ERROR const generics are unstable
+//[min]~^^^ ERROR type parameters must be declared prior
+
+fn main() {
+  let _: A<3> = A(0);
+}
diff --git a/src/test/ui/const-generics/defaults/simple-defaults.rs b/src/test/ui/const-generics/defaults/simple-defaults.rs
new file mode 100644
index 00000000000..b282dfd37cc
--- /dev/null
+++ b/src/test/ui/const-generics/defaults/simple-defaults.rs
@@ -0,0 +1,15 @@
+// run-pass
+// Checks some basic test cases for defaults.
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+#![allow(dead_code)]
+
+struct FixedOutput<'a, const N: usize, T=u32> {
+  out: &'a [T; N],
+}
+
+trait FixedOutputter {
+  fn out(&self) -> FixedOutput<'_, 10>;
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/type-after-const-ok.rs b/src/test/ui/const-generics/type-after-const-ok.rs
new file mode 100644
index 00000000000..fc977d6617c
--- /dev/null
+++ b/src/test/ui/const-generics/type-after-const-ok.rs
@@ -0,0 +1,10 @@
+// run-pass
+// Verifies that having generic parameters after constants is permitted
+
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+#[allow(dead_code)]
+struct A<const N: usize, T>(T);
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-59508-1.stderr b/src/test/ui/issues/issue-59508-1.stderr
index 85db20b13fb..5e97339f148 100644
--- a/src/test/ui/issues/issue-59508-1.stderr
+++ b/src/test/ui/issues/issue-59508-1.stderr
@@ -2,7 +2,7 @@ error: lifetime parameters must be declared prior to type parameters
   --> $DIR/issue-59508-1.rs:12:25
    |
 LL |     pub fn do_things<T, 'a, 'b: 'a>() {
-   |                     ----^^--^^----- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b: 'a, T>`
+   |                     ----^^--^^----- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b: 'a, T>`
 
 warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/issue-59508-1.rs:2:12