about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-12-30 11:31:04 +0000
committerbors <bors@rust-lang.org>2019-12-30 11:31:04 +0000
commit0fb43801368ae8b5931583f813071120bed55c35 (patch)
tree9d06b775314efd38d0553123d3a1086be0600c56 /src
parent580ac0b4f1c6f9cf76f6edafdaf9806437770aff (diff)
parent5ca3a1bed185d6f7ad914dda6c73590f54d2515d (diff)
downloadrust-0fb43801368ae8b5931583f813071120bed55c35.tar.gz
rust-0fb43801368ae8b5931583f813071120bed55c35.zip
Auto merge of #67667 - wesleywiser:speed_up_trivially_valid_constants, r=oli-obk
Resolve long compile times when evaluating always valid constants

This extends the existing logic which skips validating every integer or
floating point number type to also skip validating empty structs because
they are also trivially valid.

Fixes #67539

r? @oli-obk
cc @RalfJung @spastorino
Diffstat (limited to 'src')
-rw-r--r--src/librustc_mir/interpret/validity.rs15
-rw-r--r--src/test/ui/consts/const-eval/validate_uninhabited_zsts.rs24
-rw-r--r--src/test/ui/consts/const-eval/validate_uninhabited_zsts.stderr52
-rw-r--r--src/test/ui/consts/huge-values.rs11
4 files changed, 99 insertions, 3 deletions
diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs
index df8cb5d692b..448a2765fd3 100644
--- a/src/librustc_mir/interpret/validity.rs
+++ b/src/librustc_mir/interpret/validity.rs
@@ -580,10 +580,19 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
             }
             ty::Array(tys, ..) | ty::Slice(tys)
                 if {
-                    // This optimization applies only for integer and floating point types
-                    // (i.e., types that can hold arbitrary bytes).
+                    // This optimization applies for types that can hold arbitrary bytes (such as
+                    // integer and floating point types) or for structs or tuples with no fields.
+                    // FIXME(wesleywiser) This logic could be extended further to arbitrary structs
+                    // or tuples made up of integer/floating point types or inhabited ZSTs with no
+                    // padding.
                     match tys.kind {
                         ty::Int(..) | ty::Uint(..) | ty::Float(..) => true,
+                        ty::Tuple(tys) if tys.len() == 0 => true,
+                        ty::Adt(adt_def, _)
+                            if adt_def.is_struct() && adt_def.all_fields().next().is_none() =>
+                        {
+                            true
+                        }
                         _ => false,
                     }
                 } =>
@@ -609,7 +618,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
                 // Size is not 0, get a pointer.
                 let ptr = self.ecx.force_ptr(mplace.ptr)?;
 
-                // This is the optimization: we just check the entire range at once.
+                // Optimization: we just check the entire range at once.
                 // NOTE: Keep this in sync with the handling of integer and float
                 // types above, in `visit_primitive`.
                 // In run-time mode, we accept pointers in here.  This is actually more
diff --git a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.rs b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.rs
new file mode 100644
index 00000000000..f18e00fd633
--- /dev/null
+++ b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.rs
@@ -0,0 +1,24 @@
+#![feature(const_fn)]
+#![feature(const_transmute)]
+
+const fn foo() -> ! {
+    unsafe { std::mem::transmute(()) }
+    //~^ WARN any use of this value will cause an error [const_err]
+    //~| WARN the type `!` does not permit zero-initialization [invalid_value]
+}
+
+#[derive(Clone, Copy)]
+enum Empty { }
+
+#[warn(const_err)]
+const FOO: [Empty; 3] = [foo(); 3];
+
+#[warn(const_err)]
+const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
+//~^ ERROR it is undefined behavior to use this value
+//~| WARN the type `Empty` does not permit zero-initialization
+
+fn main() {
+    FOO;
+    BAR;
+}
diff --git a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.stderr b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.stderr
new file mode 100644
index 00000000000..bde7f2536fa
--- /dev/null
+++ b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.stderr
@@ -0,0 +1,52 @@
+warning: any use of this value will cause an error
+  --> $DIR/validate_uninhabited_zsts.rs:5:14
+   |
+LL |     unsafe { std::mem::transmute(()) }
+   |              ^^^^^^^^^^^^^^^^^^^^^^^
+   |              |
+   |              entering unreachable code
+   |              inside call to `foo` at $DIR/validate_uninhabited_zsts.rs:14:26
+...
+LL | const FOO: [Empty; 3] = [foo(); 3];
+   | -----------------------------------
+   |
+note: lint level defined here
+  --> $DIR/validate_uninhabited_zsts.rs:13:8
+   |
+LL | #[warn(const_err)]
+   |        ^^^^^^^^^
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/validate_uninhabited_zsts.rs:17:1
+   |
+LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+
+warning: the type `!` does not permit zero-initialization
+  --> $DIR/validate_uninhabited_zsts.rs:5:14
+   |
+LL |     unsafe { std::mem::transmute(()) }
+   |              ^^^^^^^^^^^^^^^^^^^^^^^
+   |              |
+   |              this code causes undefined behavior when executed
+   |              help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+   |
+   = note: `#[warn(invalid_value)]` on by default
+   = note: The never type (`!`) has no valid value
+
+warning: the type `Empty` does not permit zero-initialization
+  --> $DIR/validate_uninhabited_zsts.rs:17:35
+   |
+LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^
+   |                                   |
+   |                                   this code causes undefined behavior when executed
+   |                                   help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+   |
+   = note: 0-variant enums have no valid value
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/huge-values.rs b/src/test/ui/consts/huge-values.rs
new file mode 100644
index 00000000000..ab09922d761
--- /dev/null
+++ b/src/test/ui/consts/huge-values.rs
@@ -0,0 +1,11 @@
+// build-pass
+// ignore-32bit
+
+#[derive(Clone, Copy)]
+struct Foo;
+
+fn main() {
+    let _ = [(); 4_000_000_000];
+    let _ = [0u8; 4_000_000_000];
+    let _ = [Foo; 4_000_000_000];
+}