]> git.lizzy.rs Git - rust.git/commitdiff
min_const_generics: allow ty param in repeat expr
authorBastian Kauschke <bastian_kauschke@hotmail.de>
Thu, 22 Oct 2020 08:32:41 +0000 (10:32 +0200)
committerBastian Kauschke <bastian_kauschke@hotmail.de>
Thu, 22 Oct 2020 08:43:28 +0000 (10:43 +0200)
compiler/rustc_resolve/src/late.rs
src/test/ui/const-generics/issues/issue-62504.min.stderr
src/test/ui/const-generics/issues/issue-62504.rs
src/test/ui/const-generics/issues/issue-67739.min.stderr
src/test/ui/const-generics/issues/issue-67739.rs
src/test/ui/const-generics/min_const_generics/complex-expression.rs
src/test/ui/const-generics/min_const_generics/complex-expression.stderr
src/test/ui/const-generics/min_const_generics/const-evaluatable-unchecked.rs [new file with mode: 0644]
src/test/ui/const-generics/min_const_generics/const-evaluatable-unchecked.stderr [new file with mode: 0644]

index 7517ab66170a2943943d7fc0aa815f52337efc34..d323aebe59798cc04de848bf7307bed502dbdef3 100644 (file)
@@ -57,6 +57,12 @@ enum PatternSource {
     FnParam,
 }
 
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+enum IsRepeatExpr {
+    No,
+    Yes,
+}
+
 impl PatternSource {
     fn descr(self) -> &'static str {
         match self {
@@ -437,10 +443,8 @@ fn visit_block(&mut self, block: &'ast Block) {
         self.resolve_block(block);
     }
     fn visit_anon_const(&mut self, constant: &'ast AnonConst) {
-        debug!("visit_anon_const {:?}", constant);
-        self.with_constant_rib(constant.value.is_potential_trivial_const_param(), |this| {
-            visit::walk_anon_const(this, constant);
-        });
+        // We deal with repeat expressions explicitly in `resolve_expr`.
+        self.resolve_anon_const(constant, IsRepeatExpr::No);
     }
     fn visit_expr(&mut self, expr: &'ast Expr) {
         self.resolve_expr(expr, None);
@@ -647,7 +651,11 @@ fn visit_generic_arg(&mut self, arg: &'ast GenericArg) {
                         if !check_ns(TypeNS) && check_ns(ValueNS) {
                             // This must be equivalent to `visit_anon_const`, but we cannot call it
                             // directly due to visitor lifetimes so we have to copy-paste some code.
-                            self.with_constant_rib(true, |this| {
+                            //
+                            // Note that we might not be inside of an repeat expression here,
+                            // but considering that `IsRepeatExpr` is only relevant for
+                            // non-trivial constants this is doesn't matter.
+                            self.with_constant_rib(IsRepeatExpr::No, true, |this| {
                                 this.smart_resolve_path(
                                     ty.id,
                                     qself.as_ref(),
@@ -980,9 +988,11 @@ fn resolve_item(&mut self, item: &'ast Item) {
                                             //
                                             // Type parameters can already be used and as associated consts are
                                             // not used as part of the type system, this is far less surprising.
-                                            this.with_constant_rib(true, |this| {
-                                                this.visit_expr(expr)
-                                            });
+                                            this.with_constant_rib(
+                                                IsRepeatExpr::No,
+                                                true,
+                                                |this| this.visit_expr(expr),
+                                            );
                                         }
                                     }
                                     AssocItemKind::Fn(_, _, generics, _) => {
@@ -1023,7 +1033,9 @@ fn resolve_item(&mut self, item: &'ast Item) {
                 self.with_item_rib(HasGenericParams::No, |this| {
                     this.visit_ty(ty);
                     if let Some(expr) = expr {
-                        this.with_constant_rib(expr.is_potential_trivial_const_param(), |this| {
+                        // We already forbid generic params because of the above item rib,
+                        // so it doesn't matter whether this is a trivial constant.
+                        this.with_constant_rib(IsRepeatExpr::No, true, |this| {
                             this.visit_expr(expr)
                         });
                     }
@@ -1122,12 +1134,29 @@ fn with_item_rib(&mut self, has_generic_params: HasGenericParams, f: impl FnOnce
         self.with_rib(ValueNS, kind, |this| this.with_rib(TypeNS, kind, f))
     }
 
-    fn with_constant_rib(&mut self, trivial: bool, f: impl FnOnce(&mut Self)) {
-        debug!("with_constant_rib");
-        self.with_rib(ValueNS, ConstantItemRibKind(trivial), |this| {
-            this.with_rib(TypeNS, ConstantItemRibKind(trivial), |this| {
-                this.with_label_rib(ConstantItemRibKind(trivial), f);
-            })
+    // HACK(min_const_generics,const_evaluatable_unchecked): We
+    // want to keep allowing `[0; std::mem::size_of::<*mut T>()]`
+    // with a future compat lint for now. We do this by adding an
+    // additional special case for repeat expressions.
+    //
+    // Note that we intentionally still forbid `[0; N + 1]` during
+    // name resolution so that we don't extend the future
+    // compat lint to new cases.
+    fn with_constant_rib(
+        &mut self,
+        is_repeat: IsRepeatExpr,
+        is_trivial: bool,
+        f: impl FnOnce(&mut Self),
+    ) {
+        debug!("with_constant_rib: is_repeat={:?} is_trivial={}", is_repeat, is_trivial);
+        self.with_rib(ValueNS, ConstantItemRibKind(is_trivial), |this| {
+            this.with_rib(
+                TypeNS,
+                ConstantItemRibKind(is_repeat == IsRepeatExpr::Yes || is_trivial),
+                |this| {
+                    this.with_label_rib(ConstantItemRibKind(is_trivial), f);
+                },
+            )
         });
     }
 
@@ -1272,9 +1301,17 @@ fn resolve_implementation(
                                             //
                                             // Type parameters can already be used and as associated consts are
                                             // not used as part of the type system, this is far less surprising.
-                                            this.with_constant_rib(true, |this| {
-                                                visit::walk_assoc_item(this, item, AssocCtxt::Impl)
-                                            });
+                                            this.with_constant_rib(
+                                                IsRepeatExpr::No,
+                                                true,
+                                                |this| {
+                                                    visit::walk_assoc_item(
+                                                        this,
+                                                        item,
+                                                        AssocCtxt::Impl,
+                                                    )
+                                                },
+                                            );
                                         }
                                         AssocItemKind::Fn(_, _, generics, _) => {
                                             // We also need a new scope for the impl item type parameters.
@@ -2199,6 +2236,17 @@ fn resolve_block(&mut self, block: &'ast Block) {
         debug!("(resolving block) leaving block");
     }
 
+    fn resolve_anon_const(&mut self, constant: &'ast AnonConst, is_repeat: IsRepeatExpr) {
+        debug!("resolve_anon_const {:?} is_repeat: {:?}", constant, is_repeat);
+        self.with_constant_rib(
+            is_repeat,
+            constant.value.is_potential_trivial_const_param(),
+            |this| {
+                visit::walk_anon_const(this, constant);
+            },
+        );
+    }
+
     fn resolve_expr(&mut self, expr: &'ast Expr, parent: Option<&'ast Expr>) {
         // First, record candidate traits for this expression if it could
         // result in the invocation of a method call.
@@ -2322,6 +2370,10 @@ fn resolve_expr(&mut self, expr: &'ast Expr, parent: Option<&'ast Expr>) {
             ExprKind::Async(..) | ExprKind::Closure(..) => {
                 self.with_label_rib(ClosureOrAsyncRibKind, |this| visit::walk_expr(this, expr));
             }
+            ExprKind::Repeat(ref elem, ref ct) => {
+                self.visit_expr(elem);
+                self.resolve_anon_const(ct, IsRepeatExpr::Yes);
+            }
             _ => {
                 visit::walk_expr(self, expr);
             }
index 8f794312834b244b9088e1f95b3a833d70fea403..865eaf749326764fd36b94e16d68d45600451d99 100644 (file)
@@ -1,14 +1,20 @@
-error: generic `Self` types are currently not permitted in anonymous constants
+error[E0308]: mismatched types
+  --> $DIR/issue-62504.rs:19:21
+   |
+LL |         ArrayHolder([0; Self::SIZE])
+   |                     ^^^^^^^^^^^^^^^ expected `X`, found `Self::SIZE`
+   |
+   = note: expected array `[u32; X]`
+              found array `[u32; _]`
+
+error: constant expression depends on a generic parameter
   --> $DIR/issue-62504.rs:19:25
    |
 LL |         ArrayHolder([0; Self::SIZE])
    |                         ^^^^^^^^^^
    |
-note: not a concrete type
-  --> $DIR/issue-62504.rs:17:22
-   |
-LL | impl<const X: usize> ArrayHolder<X> {
-   |                      ^^^^^^^^^^^^^^
+   = note: this may fail depending on what value the parameter takes
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0308`.
index 015f170f00d1ce8ec797bf39c2dae9c69f1fbec8..5630962ff53767ca8ff9b156640b464fbb9c5b90 100644 (file)
@@ -17,8 +17,8 @@ impl<const X: usize> HasSize for ArrayHolder<X> {
 impl<const X: usize> ArrayHolder<X> {
     pub const fn new() -> Self {
         ArrayHolder([0; Self::SIZE])
-        //[full]~^ ERROR constant expression depends on a generic parameter
-        //[min]~^^ ERROR generic `Self` types are currently
+        //~^ ERROR constant expression depends on a generic parameter
+        //[min]~| ERROR mismatched types
     }
 }
 
index 35d97c4624811c79f461306eecdab42dd1f0fea9..27a56b8eb02b2a0692f28bf6042155c77320600f 100644 (file)
@@ -1,10 +1,10 @@
-error: generic parameters may not be used in const operations
-  --> $DIR/issue-67739.rs:12:30
+error: constant expression depends on a generic parameter
+  --> $DIR/issue-67739.rs:12:15
    |
 LL |         [0u8; mem::size_of::<Self::Associated>()];
-   |                              ^^^^^^^^^^^^^^^^ cannot perform const operation using `Self`
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: type parameters may not be used in const expressions
+   = note: this may fail depending on what value the parameter takes
 
 error: aborting due to previous error
 
index 21d13de22ebfc7ac279cb0bb0ac4bcb84414eb98..0f5860f22fdd34310f6132bda694682531ac76fe 100644 (file)
@@ -10,8 +10,7 @@ pub trait Trait {
 
     fn associated_size(&self) -> usize {
         [0u8; mem::size_of::<Self::Associated>()];
-        //[full]~^ ERROR constant expression depends on a generic parameter
-        //[min]~^^ ERROR generic parameters may not be used in const operations
+        //~^ ERROR constant expression depends on a generic parameter
         0
     }
 }
index 8257ffbf4915b3d5cb731a7f4a6c96514febfa90..686ce98fcdff3f88f4a2a50a4ef7ee5e947067e4 100644 (file)
@@ -1,5 +1,7 @@
 #![feature(min_const_generics)]
 
+use std::mem::size_of;
+
 fn test<const N: usize>() {}
 
 fn ok<const M: usize>() -> [u8; M] {
@@ -22,6 +24,24 @@ fn break3<const N: usize>() {
     //~^ ERROR generic parameters may not be used in const operations
 }
 
+struct BreakTy0<T>(T, [u8; { size_of::<*mut T>() }]);
+//~^ ERROR generic parameters may not be used in const operations
+
+struct BreakTy1<T>(T, [u8; { { size_of::<*mut T>() } }]);
+//~^ ERROR generic parameters may not be used in const operations
+
+fn break_ty2<T>() {
+    let _: [u8; size_of::<*mut T>() + 1];
+    //~^ ERROR generic parameters may not be used in const operations
+}
+
+fn break_ty3<T>() {
+    let _ = [0; size_of::<*mut T>() + 1];
+    //~^ WARN cannot use constants which depend on generic parameters in types
+    //~| WARN this was previously accepted by the compiler but is being phased out
+}
+
+
 trait Foo {
     const ASSOC: usize;
 }
index 73768ac03a4b107d40aab45adbefe8c27782c925..a8de987e1675ed2f2939c0a71a17f29c188be6e6 100644 (file)
@@ -1,5 +1,5 @@
 error: generic parameters may not be used in const operations
-  --> $DIR/complex-expression.rs:9:38
+  --> $DIR/complex-expression.rs:11:38
    |
 LL | struct Break0<const N: usize>([u8; { N + 1 }]);
    |                                      ^ cannot perform const operation using `N`
@@ -7,7 +7,7 @@ LL | struct Break0<const N: usize>([u8; { N + 1 }]);
    = help: const parameters may only be used as standalone arguments, i.e. `N`
 
 error: generic parameters may not be used in const operations
-  --> $DIR/complex-expression.rs:12:40
+  --> $DIR/complex-expression.rs:14:40
    |
 LL | struct Break1<const N: usize>([u8; { { N } }]);
    |                                        ^ cannot perform const operation using `N`
@@ -15,7 +15,7 @@ LL | struct Break1<const N: usize>([u8; { { 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/complex-expression.rs:16:17
+  --> $DIR/complex-expression.rs:18:17
    |
 LL |     let _: [u8; N + 1];
    |                 ^ cannot perform const operation using `N`
@@ -23,12 +23,46 @@ LL |     let _: [u8; N + 1];
    = help: const parameters may only be used as standalone arguments, i.e. `N`
 
 error: generic parameters may not be used in const operations
-  --> $DIR/complex-expression.rs:21:17
+  --> $DIR/complex-expression.rs:23:17
    |
 LL |     let _ = [0; N + 1];
    |                 ^ cannot perform const operation using `N`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `N`
 
-error: aborting due to 4 previous errors
+error: generic parameters may not be used in const operations
+  --> $DIR/complex-expression.rs:27:45
+   |
+LL | struct BreakTy0<T>(T, [u8; { size_of::<*mut T>() }]);
+   |                                             ^ cannot perform const operation using `T`
+   |
+   = note: type parameters may not be used in const expressions
+
+error: generic parameters may not be used in const operations
+  --> $DIR/complex-expression.rs:30:47
+   |
+LL | struct BreakTy1<T>(T, [u8; { { size_of::<*mut T>() } }]);
+   |                                               ^ cannot perform const operation using `T`
+   |
+   = note: type parameters may not be used in const expressions
+
+error: generic parameters may not be used in const operations
+  --> $DIR/complex-expression.rs:34:32
+   |
+LL |     let _: [u8; size_of::<*mut T>() + 1];
+   |                                ^ cannot perform const operation using `T`
+   |
+   = note: type parameters may not be used in const expressions
+
+warning: cannot use constants which depend on generic parameters in types
+  --> $DIR/complex-expression.rs:39:17
+   |
+LL |     let _ = [0; size_of::<*mut T>() + 1];
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(const_evaluatable_unchecked)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #76200 <https://github.com/rust-lang/rust/issues/76200>
+
+error: aborting due to 7 previous errors; 1 warning emitted
 
diff --git a/src/test/ui/const-generics/min_const_generics/const-evaluatable-unchecked.rs b/src/test/ui/const-generics/min_const_generics/const-evaluatable-unchecked.rs
new file mode 100644 (file)
index 0000000..4e99a09
--- /dev/null
@@ -0,0 +1,22 @@
+// check-pass
+#![allow(dead_code)]
+
+fn foo<T>() {
+    [0; std::mem::size_of::<*mut T>()];
+    //~^ WARN cannot use constants which depend on generic parameters in types
+    //~| WARN this was previously accepted by the compiler but is being phased out
+}
+
+struct Foo<T>(T);
+
+impl<T> Foo<T> {
+    const ASSOC: usize = 4;
+
+    fn test() {
+        [0; Self::ASSOC];
+        //~^ WARN cannot use constants which depend on generic parameters in types
+        //~| WARN this was previously accepted by the compiler but is being phased out
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/min_const_generics/const-evaluatable-unchecked.stderr b/src/test/ui/const-generics/min_const_generics/const-evaluatable-unchecked.stderr
new file mode 100644 (file)
index 0000000..f493f0d
--- /dev/null
@@ -0,0 +1,21 @@
+warning: cannot use constants which depend on generic parameters in types
+  --> $DIR/const-evaluatable-unchecked.rs:5:9
+   |
+LL |     [0; std::mem::size_of::<*mut T>()];
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(const_evaluatable_unchecked)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #76200 <https://github.com/rust-lang/rust/issues/76200>
+
+warning: cannot use constants which depend on generic parameters in types
+  --> $DIR/const-evaluatable-unchecked.rs:16:13
+   |
+LL |         [0; Self::ASSOC];
+   |             ^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #76200 <https://github.com/rust-lang/rust/issues/76200>
+
+warning: 2 warnings emitted
+