From efcbf1b00bb8997f1e1ee0740640f67fbe32c615 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 18 Nov 2020 12:49:39 +0000 Subject: [PATCH 1/2] Permit standalone generic parameters as const generic arguments in macros --- compiler/rustc_parse/src/parser/diagnostics.rs | 10 +++++++--- compiler/rustc_parse/src/parser/path.rs | 8 ++++++++ .../const-generics/macro_rules-braces.full.stderr | 13 +------------ .../ui/const-generics/macro_rules-braces.min.stderr | 13 +------------ src/test/ui/const-generics/macro_rules-braces.rs | 2 +- 5 files changed, 18 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index cd3b8db2303b3..350a372a684cc 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1808,9 +1808,13 @@ impl<'a> Parser<'a> { return Ok(false); // Don't continue. } - /// Handle a generic const argument that had not been enclosed in braces, and suggest enclosing - /// it braces. In this situation, unlike in `handle_ambiguous_unbraced_const_arg`, this is - /// almost certainly a const argument, so we always offer a suggestion. + /// Attempt to parse a generic const argument that has not been enclosed in braces. + /// There are a limited number of expressions that are permitted without being encoded + /// in braces: + /// - Literals. + /// - Single-segment paths (i.e. standalone generic const parameters). + /// All other expressions that can be parsed will emit an error suggesting the expression be + /// wrapped in braces. pub fn handle_unambiguous_unbraced_const_arg(&mut self) -> PResult<'a, P> { let start = self.token.span; let expr = self.parse_expr_res(Restrictions::CONST_EXPR, None).map_err(|mut err| { diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 79e737490386c..d64fd59b0a657 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -489,6 +489,7 @@ impl<'a> Parser<'a> { /// - An expression surrounded in `{}`. /// - A literal. /// - A numeric literal prefixed by `-`. + /// - A single-segment path. pub(super) fn expr_is_valid_const_arg(&self, expr: &P) -> bool { match &expr.kind { ast::ExprKind::Block(_, _) | ast::ExprKind::Lit(_) => true, @@ -496,6 +497,13 @@ impl<'a> Parser<'a> { ast::ExprKind::Lit(_) => true, _ => false, }, + // We can only resolve single-segment paths at the moment, because multi-segment paths + // require type-checking: see `visit_generic_arg` in `src/librustc_resolve/late.rs`. + ast::ExprKind::Path(None, path) + if path.segments.len() == 1 && path.segments[0].args.is_none() => + { + true + } _ => false, } } diff --git a/src/test/ui/const-generics/macro_rules-braces.full.stderr b/src/test/ui/const-generics/macro_rules-braces.full.stderr index e5b67f61a25b7..273766b0b0e71 100644 --- a/src/test/ui/const-generics/macro_rules-braces.full.stderr +++ b/src/test/ui/const-generics/macro_rules-braces.full.stderr @@ -1,14 +1,3 @@ -error: expressions must be enclosed in braces to be used as const generic arguments - --> $DIR/macro_rules-braces.rs:34:17 - | -LL | let _: baz!(N); - | ^ - | -help: enclose the `const` expression in braces - | -LL | let _: baz!({ N }); - | ^ ^ - error: expressions must be enclosed in braces to be used as const generic arguments --> $DIR/macro_rules-braces.rs:54:17 | @@ -68,5 +57,5 @@ LL | let _: biz!({ N }); = note: this may fail depending on what value the parameter takes = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors diff --git a/src/test/ui/const-generics/macro_rules-braces.min.stderr b/src/test/ui/const-generics/macro_rules-braces.min.stderr index a4ef732017dd5..10c2a596ca562 100644 --- a/src/test/ui/const-generics/macro_rules-braces.min.stderr +++ b/src/test/ui/const-generics/macro_rules-braces.min.stderr @@ -1,14 +1,3 @@ -error: expressions must be enclosed in braces to be used as const generic arguments - --> $DIR/macro_rules-braces.rs:34:17 - | -LL | let _: baz!(N); - | ^ - | -help: enclose the `const` expression in braces - | -LL | let _: baz!({ N }); - | ^ ^ - error: expressions must be enclosed in braces to be used as const generic arguments --> $DIR/macro_rules-braces.rs:54:17 | @@ -52,5 +41,5 @@ LL | let _: biz!({ N }); | = help: const parameters may only be used as standalone arguments, i.e. `N` -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors diff --git a/src/test/ui/const-generics/macro_rules-braces.rs b/src/test/ui/const-generics/macro_rules-braces.rs index bc67d464f11bb..bc2eca81b6182 100644 --- a/src/test/ui/const-generics/macro_rules-braces.rs +++ b/src/test/ui/const-generics/macro_rules-braces.rs @@ -31,7 +31,7 @@ fn test() { let _: foo!({{ N }}); //[min]~ ERROR generic parameters may not let _: bar!(N); let _: bar!({ N }); //[min]~ ERROR generic parameters may not - let _: baz!(N); //~ ERROR expressions must be enclosed in braces + let _: baz!(N); let _: baz!({ N }); let _: baz!({{ N }}); //[min]~ ERROR generic parameters may not let _: biz!(N); From 85bc9538920850e5bd7c1023c9ffbf5e8e69be6a Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 18 Nov 2020 12:55:35 +0000 Subject: [PATCH 2/2] Add tests for multi-segment paths in const generic arguments --- .../macro_rules-braces.full.stderr | 23 ++++++++++++++----- .../macro_rules-braces.min.stderr | 23 ++++++++++++++----- .../ui/const-generics/macro_rules-braces.rs | 15 ++++++++++++ 3 files changed, 49 insertions(+), 12 deletions(-) diff --git a/src/test/ui/const-generics/macro_rules-braces.full.stderr b/src/test/ui/const-generics/macro_rules-braces.full.stderr index 273766b0b0e71..3c9d4c9b4700f 100644 --- a/src/test/ui/const-generics/macro_rules-braces.full.stderr +++ b/src/test/ui/const-generics/macro_rules-braces.full.stderr @@ -1,5 +1,16 @@ error: expressions must be enclosed in braces to be used as const generic arguments - --> $DIR/macro_rules-braces.rs:54:17 + --> $DIR/macro_rules-braces.rs:49:17 + | +LL | let _: baz!(m::P); + | ^^^^ + | +help: enclose the `const` expression in braces + | +LL | let _: baz!({ m::P }); + | ^ ^ + +error: expressions must be enclosed in braces to be used as const generic arguments + --> $DIR/macro_rules-braces.rs:69:17 | LL | let _: baz!(10 + 7); | ^^^^^^ @@ -10,7 +21,7 @@ LL | let _: baz!({ 10 + 7 }); | ^ ^ error: constant expression depends on a generic parameter - --> $DIR/macro_rules-braces.rs:10:13 + --> $DIR/macro_rules-braces.rs:16:13 | LL | [u8; $x] | ^^^^^^^^ @@ -22,7 +33,7 @@ LL | let _: foo!({{ N }}); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: constant expression depends on a generic parameter - --> $DIR/macro_rules-braces.rs:15:13 + --> $DIR/macro_rules-braces.rs:21:13 | LL | [u8; { $x }] | ^^^^^^^^^^^^ @@ -34,7 +45,7 @@ LL | let _: bar!({ N }); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: constant expression depends on a generic parameter - --> $DIR/macro_rules-braces.rs:20:13 + --> $DIR/macro_rules-braces.rs:26:13 | LL | Foo<$x> | ^^^^^^^ @@ -46,7 +57,7 @@ LL | let _: baz!({{ N }}); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: constant expression depends on a generic parameter - --> $DIR/macro_rules-braces.rs:25:13 + --> $DIR/macro_rules-braces.rs:31:13 | LL | Foo<{ $x }> | ^^^^^^^^^^^ @@ -57,5 +68,5 @@ LL | let _: biz!({ N }); = note: this may fail depending on what value the parameter takes = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors diff --git a/src/test/ui/const-generics/macro_rules-braces.min.stderr b/src/test/ui/const-generics/macro_rules-braces.min.stderr index 10c2a596ca562..c6425edc10f15 100644 --- a/src/test/ui/const-generics/macro_rules-braces.min.stderr +++ b/src/test/ui/const-generics/macro_rules-braces.min.stderr @@ -1,5 +1,16 @@ error: expressions must be enclosed in braces to be used as const generic arguments - --> $DIR/macro_rules-braces.rs:54:17 + --> $DIR/macro_rules-braces.rs:49:17 + | +LL | let _: baz!(m::P); + | ^^^^ + | +help: enclose the `const` expression in braces + | +LL | let _: baz!({ m::P }); + | ^ ^ + +error: expressions must be enclosed in braces to be used as const generic arguments + --> $DIR/macro_rules-braces.rs:69:17 | LL | let _: baz!(10 + 7); | ^^^^^^ @@ -10,7 +21,7 @@ LL | let _: baz!({ 10 + 7 }); | ^ ^ error: generic parameters may not be used in const operations - --> $DIR/macro_rules-braces.rs:31:20 + --> $DIR/macro_rules-braces.rs:37:20 | LL | let _: foo!({{ N }}); | ^ cannot perform const operation using `N` @@ -18,7 +29,7 @@ LL | let _: foo!({{ N }}); = help: const parameters may only be used as standalone arguments, i.e. `N` error: generic parameters may not be used in const operations - --> $DIR/macro_rules-braces.rs:33:19 + --> $DIR/macro_rules-braces.rs:41:19 | LL | let _: bar!({ N }); | ^ cannot perform const operation using `N` @@ -26,7 +37,7 @@ LL | let _: bar!({ N }); = help: const parameters may only be used as standalone arguments, i.e. `N` error: generic parameters may not be used in const operations - --> $DIR/macro_rules-braces.rs:36:20 + --> $DIR/macro_rules-braces.rs:46:20 | LL | let _: baz!({{ N }}); | ^ cannot perform const operation using `N` @@ -34,12 +45,12 @@ LL | let _: baz!({{ N }}); = help: const parameters may only be used as standalone arguments, i.e. `N` error: generic parameters may not be used in const operations - --> $DIR/macro_rules-braces.rs:38:19 + --> $DIR/macro_rules-braces.rs:51:19 | LL | let _: biz!({ N }); | ^ cannot perform const operation using `N` | = help: const parameters may only be used as standalone arguments, i.e. `N` -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors diff --git a/src/test/ui/const-generics/macro_rules-braces.rs b/src/test/ui/const-generics/macro_rules-braces.rs index bc2eca81b6182..c6b43bec243f4 100644 --- a/src/test/ui/const-generics/macro_rules-braces.rs +++ b/src/test/ui/const-generics/macro_rules-braces.rs @@ -3,6 +3,12 @@ #![cfg_attr(full, feature(const_generics))] #![cfg_attr(min, feature(min_const_generics))] +mod m { + pub const P: usize = 0; +} + +const Q: usize = 0; + fn test() { struct Foo; macro_rules! foo { @@ -29,13 +35,22 @@ fn test() { let _: foo!(N); let _: foo!({ N }); let _: foo!({{ N }}); //[min]~ ERROR generic parameters may not + let _: foo!(Q); + let _: foo!(m::P); let _: bar!(N); let _: bar!({ N }); //[min]~ ERROR generic parameters may not + let _: bar!(Q); + let _: bar!(m::P); let _: baz!(N); let _: baz!({ N }); let _: baz!({{ N }}); //[min]~ ERROR generic parameters may not + let _: baz!(Q); + let _: baz!({ m::P }); + let _: baz!(m::P); //~ ERROR expressions must be enclosed in braces let _: biz!(N); let _: biz!({ N }); //[min]~ ERROR generic parameters may not + let _: biz!(Q); + let _: biz!(m::P); let _: foo!(3); let _: foo!({ 3 }); let _: foo!({{ 3 }});