about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-08-10 15:19:46 +0000
committerbors <bors@rust-lang.org>2020-08-10 15:19:46 +0000
commit08324fe6f7ac24be4c8bfcab42b12ee447635c80 (patch)
treed499377d00aff85d051aebd59935a21fb8892e3c
parent4c336d46263999cce87de899220d7b92d11f1c85 (diff)
parent64f643782245b25326c6e9a76bf78c798f1ae168 (diff)
downloadrust-08324fe6f7ac24be4c8bfcab42b12ee447635c80.tar.gz
rust-08324fe6f7ac24be4c8bfcab42b12ee447635c80.zip
Auto merge of #74953 - JulianKnodt:master, r=lcnr
Remove restriction on type parameters preceding consts w/ feature const-generics

Removed the restriction on type parameters preceding const parameters when the feature const-generics is enabled.

Builds on #74676, which deals with unsorted generic parameters. This just lifts the check in lowering the AST to HIR that permits consts and types to be reordered with respect to each other. Lifetimes still must precede both

This change is not intended for min-const-generics, and is gated behind the `#![feature(const_generics)]`.

One thing is that it also permits type parameters without a default to come after consts, which I expected to not work, and was hoping to get more guidance on whether that should be permitted or how to prevent it otherwise.

I did not go through the RFC process for this pull request because there was prior work to get this feature added. In the previous PR that was cited, work was done to enable this change.

r? @lcnr
-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