From 58b1a04b9edc19a2f44f780475ebace12a0ab435 Mon Sep 17 00:00:00 2001 From: julianknodt Date: Thu, 30 Jul 2020 00:40:50 -0700 Subject: [PATCH 1/9] Allow types to come after consts in AST validation --- src/librustc_ast_passes/ast_validation.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs index 0e98c047c2f..f4cb400892e 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -735,6 +735,7 @@ fn validate_generic_param_order<'a>( } let max_param = &mut max_param; match max_param { + Some(ParamKindOrd::Const) if ParamKindOrd::Type == kind => (), Some(max_param) if *max_param > kind => { let entry = out_of_order.entry(kind).or_insert((*max_param, vec![])); entry.1.push(span); From 18481cbec981f320abfb83df0e96fd127def7cd5 Mon Sep 17 00:00:00 2001 From: kadmin Date: Thu, 30 Jul 2020 18:39:53 +0000 Subject: [PATCH 2/9] Rm restriction on ord of default types w/ consts --- src/librustc_ast_passes/ast_validation.rs | 3 ++- src/test/ui/const-generics/argument_order.rs | 7 +++--- .../ui/const-generics/argument_order.stderr | 25 ++----------------- .../const-param-before-other-params.rs | 4 +-- .../const-param-before-other-params.stderr | 8 +----- .../ui/const-generics/defaults/right-order.rs | 11 ++++++++ 6 files changed, 20 insertions(+), 38 deletions(-) create mode 100644 src/test/ui/const-generics/defaults/right-order.rs diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs index f4cb400892e..893de1f60e8 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -735,7 +735,8 @@ fn validate_generic_param_order<'a>( } let max_param = &mut max_param; match max_param { - Some(ParamKindOrd::Const) if ParamKindOrd::Type == kind => (), + Some(ParamKindOrd::Const) if ParamKindOrd::Type == kind && + sess.features_untracked().const_generics => (), Some(max_param) if *max_param > kind => { let entry = out_of_order.entry(kind).or_insert((*max_param, vec![])); entry.1.push(span); 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 { //~ ERROR type parameters must be declared prior +struct Bad { arr: [u8; { N }], another: T, } struct AlsoBad { - //~^ 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..058cc346d1b 100644 --- a/src/test/ui/const-generics/argument_order.stderr +++ b/src/test/ui/const-generics/argument_order.stderr @@ -1,32 +1,11 @@ -error: type parameters must be declared prior to const parameters - --> $DIR/argument_order.rs:4:28 - | -LL | struct Bad { - | -----------------^- help: reorder the parameters: lifetimes, then types, then consts: `` - error: lifetime parameters must be declared prior to const parameters --> $DIR/argument_order.rs:9:32 | LL | struct AlsoBad { | -----------------^^-----^^-------------------- 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 { - | ---------------------^----------------------^- 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 for more information - 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>; | ^^^^^^^ @@ -34,6 +13,6 @@ 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>` -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-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(_: &'a ()) { //~^ ERROR lifetime parameters must be declared prior to const parameters } -fn foo(_: &T) { - //~^ ERROR type parameters must be declared prior to const parameters -} +fn foo(_: &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..5c1171aae60 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 @@ -4,11 +4,5 @@ error: lifetime parameters must be declared prior to const parameters LL | fn bar(_: &'a ()) { | --------------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'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(_: &T) { - | --------------^- help: reorder the parameters: lifetimes, then types, then consts: `` - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/const-generics/defaults/right-order.rs b/src/test/ui/const-generics/defaults/right-order.rs new file mode 100644 index 00000000000..f1b5c1f02c8 --- /dev/null +++ b/src/test/ui/const-generics/defaults/right-order.rs @@ -0,0 +1,11 @@ +// run-pass +// Verifies that having generic parameters after constants is permitted + +#![feature(const_generics)] +#![allow(incomplete_features)] + +struct A(T); + +fn main() { + let _: A<3> = A(0); +} From f8588284afbaa7dbe479320d0aeae063f0fd4868 Mon Sep 17 00:00:00 2001 From: kadmin Date: Thu, 30 Jul 2020 18:43:44 +0000 Subject: [PATCH 3/9] Added +1 test for only works w/ feat const gen Added this test to ensure that reordering the parameters only works with the feature const generics enabled. Fixed nits Also added another test to verify that intermixed lifetimes are forbidden --- src/librustc_ast_passes/ast_validation.rs | 7 +++++-- .../defaults/intermixed-lifetime.rs | 9 +++++++++ .../defaults/intermixed-lifetime.stderr | 8 ++++++++ .../const-generics/defaults/needs-feature.rs | 8 ++++++++ .../defaults/needs-feature.stderr | 18 ++++++++++++++++++ .../ui/const-generics/defaults/right-order.rs | 2 +- .../type-after-const-requires-default.rs | 10 ++++++++++ 7 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/const-generics/defaults/intermixed-lifetime.rs create mode 100644 src/test/ui/const-generics/defaults/intermixed-lifetime.stderr create mode 100644 src/test/ui/const-generics/defaults/needs-feature.rs create mode 100644 src/test/ui/const-generics/defaults/needs-feature.stderr create mode 100644 src/test/ui/const-generics/defaults/type-after-const-requires-default.rs diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs index 893de1f60e8..4ebf089c68b 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -735,8 +735,11 @@ fn validate_generic_param_order<'a>( } let max_param = &mut max_param; match max_param { - Some(ParamKindOrd::Const) if ParamKindOrd::Type == kind && - sess.features_untracked().const_generics => (), + Some(ParamKindOrd::Const) + if ParamKindOrd::Type == kind && sess.features_untracked().const_generics => + { + () + } Some(max_param) if *max_param > kind => { let entry = out_of_order.entry(kind).or_insert((*max_param, vec![])); entry.1.push(span); 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..ff052edcec7 --- /dev/null +++ b/src/test/ui/const-generics/defaults/intermixed-lifetime.rs @@ -0,0 +1,9 @@ +// Checks that lifetimes cannot be interspersed between consts and types. + +#![feature(const_generics)] +#![allow(incomplete_features)] + +struct Foo(&'a (), T); +//~^ Error lifetime parameters must be declared prior to const 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..0880581ec7f --- /dev/null +++ b/src/test/ui/const-generics/defaults/intermixed-lifetime.stderr @@ -0,0 +1,8 @@ +error: lifetime parameters must be declared prior to const parameters + --> $DIR/intermixed-lifetime.rs:6:28 + | +LL | struct Foo(&'a (), T); + | -----------------^^---------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, const N: usize>` + +error: aborting due to previous error + 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..ea38a4022ae --- /dev/null +++ b/src/test/ui/const-generics/defaults/needs-feature.rs @@ -0,0 +1,8 @@ +// Verifies that having generic parameters after constants is not permitted without the +// `const_generics` feature. + +struct A(T); +//~^ ERROR type parameters must be declared prior +//~| ERROR const generics are unstable + +fn main() {} diff --git a/src/test/ui/const-generics/defaults/needs-feature.stderr b/src/test/ui/const-generics/defaults/needs-feature.stderr new file mode 100644 index 00000000000..30604feab1b --- /dev/null +++ b/src/test/ui/const-generics/defaults/needs-feature.stderr @@ -0,0 +1,18 @@ +error: type parameters must be declared prior to const parameters + --> $DIR/needs-feature.rs:4:26 + | +LL | struct A(T); + | -----------------^----- help: reorder the parameters: lifetimes, then types: `` + +error[E0658]: const generics are unstable + --> $DIR/needs-feature.rs:4:16 + | +LL | struct A(T); + | ^ + | + = note: see issue #44580 for more information + = help: add `#![feature(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/right-order.rs b/src/test/ui/const-generics/defaults/right-order.rs index f1b5c1f02c8..fce3ab2e6a3 100644 --- a/src/test/ui/const-generics/defaults/right-order.rs +++ b/src/test/ui/const-generics/defaults/right-order.rs @@ -1,5 +1,5 @@ // run-pass -// Verifies that having generic parameters after constants is permitted +// Verifies that having generic parameters after constants is permitted. #![feature(const_generics)] #![allow(incomplete_features)] diff --git a/src/test/ui/const-generics/defaults/type-after-const-requires-default.rs b/src/test/ui/const-generics/defaults/type-after-const-requires-default.rs new file mode 100644 index 00000000000..fc977d6617c --- /dev/null +++ b/src/test/ui/const-generics/defaults/type-after-const-requires-default.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(T); + +fn main() {} From b8352eb2d19b08606fb407def7a378cc93b8f5de Mon Sep 17 00:00:00 2001 From: kadmin Date: Thu, 30 Jul 2020 20:53:32 +0000 Subject: [PATCH 4/9] Test lifetimes after types after consts forbidden Added more complex test and changed error message --- src/librustc_ast_passes/ast_validation.rs | 12 ++++---- .../ui/const-generics/argument_order.stderr | 2 +- .../const-param-before-other-params.stderr | 2 +- .../defaults/complex-unord-param.rs | 28 +++++++++++++++++++ .../defaults/intermixed-lifetime.rs | 3 ++ .../defaults/intermixed-lifetime.stderr | 10 +++++-- 6 files changed, 47 insertions(+), 10 deletions(-) create mode 100644 src/test/ui/const-generics/defaults/complex-unord-param.rs diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs index 4ebf089c68b..f348d9902b3 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -780,13 +780,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(), diff --git a/src/test/ui/const-generics/argument_order.stderr b/src/test/ui/const-generics/argument_order.stderr index 058cc346d1b..87dff170b2a 100644 --- a/src/test/ui/const-generics/argument_order.stderr +++ b/src/test/ui/const-generics/argument_order.stderr @@ -2,7 +2,7 @@ error: lifetime parameters must be declared prior to const parameters --> $DIR/argument_order.rs:9:32 | LL | struct AlsoBad { - | -----------------^^-----^^-------------------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T, U, const N: usize, const M: usize>` + | -----------------^^-----^^-------------------- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T, U, const N: usize, const M: usize>` error[E0747]: lifetime provided when a type was expected --> $DIR/argument_order.rs:16:23 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 5c1171aae60..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,7 +2,7 @@ error: lifetime parameters must be declared prior to const parameters --> $DIR/const-param-before-other-params.rs:4:21 | LL | fn bar(_: &'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: 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..8ee5604633e --- /dev/null +++ b/src/test/ui/const-generics/defaults/complex-unord-param.rs @@ -0,0 +1,28 @@ +// run-pass +// Checks a complicated usage of unordered params + +#![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>; +} + +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 index ff052edcec7..d53958c9573 100644 --- a/src/test/ui/const-generics/defaults/intermixed-lifetime.rs +++ b/src/test/ui/const-generics/defaults/intermixed-lifetime.rs @@ -6,4 +6,7 @@ struct Foo(&'a (), T); //~^ Error lifetime parameters must be declared prior to const parameters +struct Bar(&'a (), T); +//~^ Error lifetime parameters must be declared prior to const 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 index 0880581ec7f..d8450ba442d 100644 --- a/src/test/ui/const-generics/defaults/intermixed-lifetime.stderr +++ b/src/test/ui/const-generics/defaults/intermixed-lifetime.stderr @@ -2,7 +2,13 @@ error: lifetime parameters must be declared prior to const parameters --> $DIR/intermixed-lifetime.rs:6:28 | LL | struct Foo(&'a (), T); - | -----------------^^---------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, const N: usize>` + | -----------------^^---------- help: reorder the parameters: lifetimes, then consts and types: `<'a, T, const N: usize>` -error: aborting due to previous error +error: lifetime parameters must be declared prior to const parameters + --> $DIR/intermixed-lifetime.rs:9:37 + | +LL | struct Bar(&'a (), T); + | --------------------------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, T, const N: usize>` + +error: aborting due to 2 previous errors From 319c4f45e0d26430ebd6d7b8b03724c7a0306885 Mon Sep 17 00:00:00 2001 From: kadmin Date: Thu, 30 Jul 2020 22:11:54 +0000 Subject: [PATCH 5/9] Blessed old test where error message had changed Added minor fmt change to ast_validation --- src/librustc_ast_passes/ast_validation.rs | 5 +---- src/test/ui/issues/issue-59508-1.stderr | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs index f348d9902b3..bc249ada7e3 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -736,10 +736,7 @@ fn validate_generic_param_order<'a>( let max_param = &mut max_param; match max_param { Some(ParamKindOrd::Const) - if ParamKindOrd::Type == kind && sess.features_untracked().const_generics => - { - () - } + if ParamKindOrd::Type == kind && sess.features_untracked().const_generics => {} Some(max_param) if *max_param > kind => { let entry = out_of_order.entry(kind).or_insert((*max_param, vec![])); entry.1.push(span); 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() { - | ----^^--^^----- 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 From 1ae1a6332c27fd5f384d3877cb2c4b546dd86c37 Mon Sep 17 00:00:00 2001 From: kadmin Date: Wed, 5 Aug 2020 22:36:47 +0000 Subject: [PATCH 6/9] Add ParamKindOrd::ConstUnordered variant --- src/librustc_ast/ast.rs | 2 ++ src/librustc_ast_passes/ast_validation.rs | 3 +-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/librustc_ast/ast.rs b/src/librustc_ast/ast.rs index 3d262591747..95e01f07e01 100644 --- a/src/librustc_ast/ast.rs +++ b/src/librustc_ast/ast.rs @@ -314,6 +314,7 @@ pub enum ParamKindOrd { Lifetime, Type, Const, + ConstUnordered, } impl fmt::Display for ParamKindOrd { @@ -322,6 +323,7 @@ impl fmt::Display for ParamKindOrd { ParamKindOrd::Lifetime => "lifetime".fmt(f), ParamKindOrd::Type => "type".fmt(f), ParamKindOrd::Const => "const".fmt(f), + ParamKindOrd::ConstUnordered => "const".fmt(f), } } } diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs index bc249ada7e3..7179a59c0dd 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -735,8 +735,7 @@ fn validate_generic_param_order<'a>( } let max_param = &mut max_param; match max_param { - Some(ParamKindOrd::Const) - if ParamKindOrd::Type == kind && sess.features_untracked().const_generics => {} + Some(ParamKindOrd::ConstUnordered) if kind != ParamKindOrd::Lifetime => (), Some(max_param) if *max_param > kind => { let entry = out_of_order.entry(kind).or_insert((*max_param, vec![])); entry.1.push(span); From 4f461f5d1282ac58892b8985f1df7ea26df6613f Mon Sep 17 00:00:00 2001 From: kadmin Date: Thu, 6 Aug 2020 00:23:17 +0000 Subject: [PATCH 7/9] Switched to unordered field in ParamKindOrd Run fmt --- src/librustc_ast/ast.rs | 6 ++---- src/librustc_ast_passes/ast_validation.rs | 8 ++++++-- src/librustc_typeck/astconv.rs | 12 +++++++++--- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/librustc_ast/ast.rs b/src/librustc_ast/ast.rs index 95e01f07e01..5e8066dd960 100644 --- a/src/librustc_ast/ast.rs +++ b/src/librustc_ast/ast.rs @@ -313,8 +313,7 @@ pub type GenericBounds = Vec; pub enum ParamKindOrd { Lifetime, Type, - Const, - ConstUnordered, + Const { unordered: bool }, } impl fmt::Display for ParamKindOrd { @@ -322,8 +321,7 @@ impl fmt::Display for ParamKindOrd { match self { ParamKindOrd::Lifetime => "lifetime".fmt(f), ParamKindOrd::Type => "type".fmt(f), - ParamKindOrd::Const => "const".fmt(f), - ParamKindOrd::ConstUnordered => "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 7179a59c0dd..a229987da76 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -735,7 +735,7 @@ fn validate_generic_param_order<'a>( } let max_param = &mut max_param; match max_param { - Some(ParamKindOrd::ConstUnordered) if kind != ParamKindOrd::Lifetime => (), + Some(ParamKindOrd::Const { unordered: true }) if kind != ParamKindOrd::Lifetime => (), Some(max_param) if *max_param > kind => { let entry = out_of_order.entry(kind).or_insert((*max_param, vec![])); entry.1.push(span); @@ -1159,7 +1159,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..becabe9c3b9 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,7 +501,7 @@ 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. @@ -672,7 +673,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ParamKindOrd::Type } GenericParamDefKind::Const => { - ParamKindOrd::Const + ParamKindOrd::Const { + unordered: tcx + .sess + .features_untracked() + .const_generics, + } } }, param, From be0d6f1c0636b2c7c3c8df819d8c2066669c8024 Mon Sep 17 00:00:00 2001 From: kadmin Date: Thu, 6 Aug 2020 08:22:32 +0000 Subject: [PATCH 8/9] Change Ord impl for ParamKindOrd Updated tests and error msgs Update stderr from test Update w/ lcnr comments Change some tests around, and also updated Ord implementation for ParamKindOrd Update w/ nits from lcnr --- src/librustc_ast/ast.rs | 27 ++++++++++++++++++- src/librustc_ast_passes/ast_validation.rs | 1 - src/librustc_typeck/astconv.rs | 16 ++++++----- .../ui/const-generics/argument_order.stderr | 4 +-- .../const-arg-type-arg-misordered.rs | 2 +- .../const-arg-type-arg-misordered.stderr | 14 +--------- .../defaults/complex-unord-param.rs | 8 ------ .../defaults/intermixed-lifetime.rs | 2 +- .../defaults/intermixed-lifetime.stderr | 6 ++--- .../defaults/needs-feature.min.stderr | 8 ++++++ ...ature.stderr => needs-feature.none.stderr} | 8 +++--- .../const-generics/defaults/needs-feature.rs | 15 ++++++++--- .../ui/const-generics/defaults/right-order.rs | 11 -------- .../defaults/simple-defaults.rs | 15 +++++++++++ ...ires-default.rs => type-after-const-ok.rs} | 0 15 files changed, 82 insertions(+), 55 deletions(-) create mode 100644 src/test/ui/const-generics/defaults/needs-feature.min.stderr rename src/test/ui/const-generics/defaults/{needs-feature.stderr => needs-feature.none.stderr} (64%) delete mode 100644 src/test/ui/const-generics/defaults/right-order.rs create mode 100644 src/test/ui/const-generics/defaults/simple-defaults.rs rename src/test/ui/const-generics/{defaults/type-after-const-requires-default.rs => type-after-const-ok.rs} (100%) diff --git a/src/librustc_ast/ast.rs b/src/librustc_ast/ast.rs index 5e8066dd960..2f11596c22c 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,13 +310,37 @@ pub type GenericBounds = Vec; /// 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(PartialEq, Eq, Hash, Clone, Copy)] pub enum ParamKindOrd { Lifetime, Type, + // `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 { + Some(self.cmp(other)) + } +} + impl fmt::Display for ParamKindOrd { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs index a229987da76..83f64793833 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -735,7 +735,6 @@ fn validate_generic_param_order<'a>( } let max_param = &mut max_param; match max_param { - Some(ParamKindOrd::Const { unordered: true }) if kind != ParamKindOrd::Lifetime => (), Some(max_param) if *max_param > kind => { let entry = out_of_order.entry(kind).or_insert((*max_param, vec![])); entry.1.push(span); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index becabe9c3b9..2be100ae336 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -504,14 +504,16 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { 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(); } diff --git a/src/test/ui/const-generics/argument_order.stderr b/src/test/ui/const-generics/argument_order.stderr index 87dff170b2a..687e8589bf0 100644 --- a/src/test/ui/const-generics/argument_order.stderr +++ b/src/test/ui/const-generics/argument_order.stderr @@ -2,7 +2,7 @@ error: lifetime parameters must be declared prior to const parameters --> $DIR/argument_order.rs:9:32 | LL | struct AlsoBad { - | -----------------^^-----^^-------------------- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T, U, const N: usize, const M: usize>` + | -----------------^^-----^^-------------------- 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:16:23 @@ -11,7 +11,7 @@ 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, then types, then consts, then types: `<'a, 'b, N, T, M, U>` error: aborting due to 2 previous errors 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; 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 for more information - error[E0747]: constant provided when a type was expected --> $DIR/const-arg-type-arg-misordered.rs:6:35 | LL | fn foo() -> Array { | ^ - | - = note: type arguments must be provided before constant arguments - = help: reorder the arguments: types, then consts: `` -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/defaults/complex-unord-param.rs b/src/test/ui/const-generics/defaults/complex-unord-param.rs index 8ee5604633e..72967640a8e 100644 --- a/src/test/ui/const-generics/defaults/complex-unord-param.rs +++ b/src/test/ui/const-generics/defaults/complex-unord-param.rs @@ -5,14 +5,6 @@ #![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>; -} - struct NestedArrays<'a, const N: usize, A: 'a, const M: usize, T:'a =u32> { args: &'a [&'a [T; M]; N], specifier: A, diff --git a/src/test/ui/const-generics/defaults/intermixed-lifetime.rs b/src/test/ui/const-generics/defaults/intermixed-lifetime.rs index d53958c9573..ea3a8c14b98 100644 --- a/src/test/ui/const-generics/defaults/intermixed-lifetime.rs +++ b/src/test/ui/const-generics/defaults/intermixed-lifetime.rs @@ -7,6 +7,6 @@ struct Foo(&'a (), T); //~^ Error lifetime parameters must be declared prior to const parameters struct Bar(&'a (), T); -//~^ Error lifetime parameters must be declared prior to const parameters +//~^ 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 index d8450ba442d..0f6d7f1065a 100644 --- a/src/test/ui/const-generics/defaults/intermixed-lifetime.stderr +++ b/src/test/ui/const-generics/defaults/intermixed-lifetime.stderr @@ -2,13 +2,13 @@ error: lifetime parameters must be declared prior to const parameters --> $DIR/intermixed-lifetime.rs:6:28 | LL | struct Foo(&'a (), T); - | -----------------^^---------- help: reorder the parameters: lifetimes, then consts and types: `<'a, T, const N: usize>` + | -----------------^^---------- help: reorder the parameters: lifetimes, then consts and types: `<'a, const N: usize, T>` -error: lifetime parameters must be declared prior to const parameters +error: lifetime parameters must be declared prior to type parameters --> $DIR/intermixed-lifetime.rs:9:37 | LL | struct Bar(&'a (), T); - | --------------------------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, T, const N: usize>` + | --------------------------^^- 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(T); + | -----------------^----- help: reorder the parameters: lifetimes, then consts, then types: `` + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/defaults/needs-feature.stderr b/src/test/ui/const-generics/defaults/needs-feature.none.stderr similarity index 64% rename from src/test/ui/const-generics/defaults/needs-feature.stderr rename to src/test/ui/const-generics/defaults/needs-feature.none.stderr index 30604feab1b..3b6f63a8efe 100644 --- a/src/test/ui/const-generics/defaults/needs-feature.stderr +++ b/src/test/ui/const-generics/defaults/needs-feature.none.stderr @@ -1,17 +1,17 @@ error: type parameters must be declared prior to const parameters - --> $DIR/needs-feature.rs:4:26 + --> $DIR/needs-feature.rs:10:26 | LL | struct A(T); | -----------------^----- help: reorder the parameters: lifetimes, then types: `` error[E0658]: const generics are unstable - --> $DIR/needs-feature.rs:4:16 + --> $DIR/needs-feature.rs:10:16 | LL | struct A(T); | ^ | - = note: see issue #44580 for more information - = help: add `#![feature(const_generics)]` to the crate attributes to enable + = note: see issue #74878 for more information + = help: add `#![feature(min_const_generics)]` to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/defaults/needs-feature.rs b/src/test/ui/const-generics/defaults/needs-feature.rs index ea38a4022ae..ec02dbf407d 100644 --- a/src/test/ui/const-generics/defaults/needs-feature.rs +++ b/src/test/ui/const-generics/defaults/needs-feature.rs @@ -1,8 +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(T); -//~^ ERROR type parameters must be declared prior -//~| ERROR const generics are unstable +//[none]~^ ERROR type parameters must be declared prior +//[none]~| ERROR const generics are unstable +//[min]~^^^ ERROR type parameters must be declared prior -fn main() {} +fn main() { + let _: A<3> = A(0); +} diff --git a/src/test/ui/const-generics/defaults/right-order.rs b/src/test/ui/const-generics/defaults/right-order.rs deleted file mode 100644 index fce3ab2e6a3..00000000000 --- a/src/test/ui/const-generics/defaults/right-order.rs +++ /dev/null @@ -1,11 +0,0 @@ -// run-pass -// Verifies that having generic parameters after constants is permitted. - -#![feature(const_generics)] -#![allow(incomplete_features)] - -struct A(T); - -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/defaults/type-after-const-requires-default.rs b/src/test/ui/const-generics/type-after-const-ok.rs similarity index 100% rename from src/test/ui/const-generics/defaults/type-after-const-requires-default.rs rename to src/test/ui/const-generics/type-after-const-ok.rs From 64f643782245b25326c6e9a76bf78c798f1ae168 Mon Sep 17 00:00:00 2001 From: kadmin Date: Sun, 9 Aug 2020 07:50:56 +0000 Subject: [PATCH 9/9] Convert `Eq` impl to check Ord::Equal --- src/librustc_ast/ast.rs | 8 +++++++- src/test/ui/const-generics/argument_order.stderr | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/librustc_ast/ast.rs b/src/librustc_ast/ast.rs index 2f11596c22c..c56f0bd8420 100644 --- a/src/librustc_ast/ast.rs +++ b/src/librustc_ast/ast.rs @@ -310,7 +310,7 @@ pub type GenericBounds = Vec; /// 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, Hash, Clone, Copy)] +#[derive(Hash, Clone, Copy)] pub enum ParamKindOrd { Lifetime, Type, @@ -340,6 +340,12 @@ impl PartialOrd for ParamKindOrd { 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 { diff --git a/src/test/ui/const-generics/argument_order.stderr b/src/test/ui/const-generics/argument_order.stderr index 687e8589bf0..d6546a768d2 100644 --- a/src/test/ui/const-generics/argument_order.stderr +++ b/src/test/ui/const-generics/argument_order.stderr @@ -11,7 +11,7 @@ LL | let _: AlsoBad<7, 'static, u32, 'static, 17, u16>; | ^^^^^^^ | = note: lifetime arguments must be provided before type arguments - = help: reorder the arguments: lifetimes, then consts, then types, then consts, then types: `<'a, 'b, N, T, M, U>` + = help: reorder the arguments: lifetimes, then consts: `<'a, 'b, N, T, M, U>` error: aborting due to 2 previous errors