about summary refs log tree commit diff
diff options
context:
space:
mode:
authorErik Desjardins <erikdesjardins@users.noreply.github.com>2022-02-12 01:38:24 -0500
committerErik Desjardins <erikdesjardins@users.noreply.github.com>2022-02-26 16:42:33 -0500
commit5979b681e6f7cfd760f45440624f8bc1759d2071 (patch)
tree89cd8370981a2d7492b8f0a0c1c662aa7945c9d4
parent8604ef0878b42c1b89e87d42382319dceef5f01f (diff)
downloadrust-5979b681e6f7cfd760f45440624f8bc1759d2071.tar.gz
rust-5979b681e6f7cfd760f45440624f8bc1759d2071.zip
Apply noundef attribute to all scalar types which do not permit raw init
Beyond `&`/`&mut`/`Box`, this covers `char`, discriminants, `NonZero*`, etc.
All such types currently cause a Miri error if left uninitialized,
and an `invalid_value` lint in cases like `mem::uninitialized::<char>()`

Note that this _does not_ change whether or not it is UB for `u64` (or
other integer types with no invalid values) to be undef.
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs5
-rw-r--r--src/test/codegen/abi-repr-ext.rs4
-rw-r--r--src/test/codegen/call-metadata.rs4
-rw-r--r--src/test/codegen/function-arguments.rs50
-rw-r--r--src/test/codegen/repr-transparent.rs4
5 files changed, 61 insertions, 6 deletions
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index b7b36c49459..c77047f8a2e 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -3053,6 +3053,11 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                 return;
             }
 
+            // Scalars which have invalid values cannot be undef.
+            if !scalar.is_always_valid(self) {
+                attrs.set(ArgAttribute::NoUndef);
+            }
+
             // Only pointer types handled below.
             if scalar.value != Pointer {
                 return;
diff --git a/src/test/codegen/abi-repr-ext.rs b/src/test/codegen/abi-repr-ext.rs
index 9dba1718acd..2b34eaf9417 100644
--- a/src/test/codegen/abi-repr-ext.rs
+++ b/src/test/codegen/abi-repr-ext.rs
@@ -1,3 +1,5 @@
+// compile-flags: -O
+
 #![crate_type="lib"]
 
 #[repr(i8)]
@@ -6,7 +8,7 @@ pub enum Type {
     Type2 = 1
 }
 
-// CHECK: define{{( dso_local)?}} signext i8 @test()
+// CHECK: define{{( dso_local)?}} noundef signext i8 @test()
 #[no_mangle]
 pub extern "C" fn test() -> Type {
     Type::Type1
diff --git a/src/test/codegen/call-metadata.rs b/src/test/codegen/call-metadata.rs
index 030a58441e3..1c30c08d3b2 100644
--- a/src/test/codegen/call-metadata.rs
+++ b/src/test/codegen/call-metadata.rs
@@ -1,12 +1,12 @@
 // Checks that range metadata gets emitted on calls to functions returning a
 // scalar value.
 
-// compile-flags: -C no-prepopulate-passes
+// compile-flags: -O -C no-prepopulate-passes
 
 #![crate_type = "lib"]
 
 pub fn test() {
-    // CHECK: call i8 @some_true(), !range [[R0:![0-9]+]]
+    // CHECK: call noundef i8 @some_true(), !range [[R0:![0-9]+]]
     // CHECK: [[R0]] = !{i8 0, i8 3}
     some_true();
 }
diff --git a/src/test/codegen/function-arguments.rs b/src/test/codegen/function-arguments.rs
index 17b54d86cb0..b1ccbdd934a 100644
--- a/src/test/codegen/function-arguments.rs
+++ b/src/test/codegen/function-arguments.rs
@@ -4,6 +4,7 @@
 #![feature(rustc_attrs)]
 
 use std::mem::MaybeUninit;
+use std::num::NonZeroU64;
 
 pub struct S {
   _field: [i32; 8],
@@ -13,6 +14,11 @@ pub struct UnsafeInner {
   _field: std::cell::UnsafeCell<i16>,
 }
 
+pub enum MyBool {
+  True,
+  False,
+}
+
 // CHECK: noundef zeroext i1 @boolean(i1 noundef zeroext %x)
 #[no_mangle]
 pub fn boolean(x: bool) -> bool {
@@ -25,6 +31,48 @@ pub fn maybeuninit_boolean(x: MaybeUninit<bool>) -> MaybeUninit<bool> {
   x
 }
 
+// CHECK: noundef zeroext i1 @enum_bool(i1 noundef zeroext %x)
+#[no_mangle]
+pub fn enum_bool(x: MyBool) -> MyBool {
+  x
+}
+
+// CHECK: i8 @maybeuninit_enum_bool(i8 %x)
+#[no_mangle]
+pub fn maybeuninit_enum_bool(x: MaybeUninit<MyBool>) -> MaybeUninit<MyBool> {
+  x
+}
+
+// CHECK: noundef i32 @char(i32 noundef %x)
+#[no_mangle]
+pub fn char(x: char) -> char {
+  x
+}
+
+// CHECK: i32 @maybeuninit_char(i32 %x)
+#[no_mangle]
+pub fn maybeuninit_char(x: MaybeUninit<char>) -> MaybeUninit<char> {
+  x
+}
+
+// CHECK: i64 @int(i64 %x)
+#[no_mangle]
+pub fn int(x: u64) -> u64 {
+  x
+}
+
+// CHECK: noundef i64 @nonzero_int(i64 noundef %x)
+#[no_mangle]
+pub fn nonzero_int(x: NonZeroU64) -> NonZeroU64 {
+  x
+}
+
+// CHECK: i64 @option_nonzero_int(i64 %x)
+#[no_mangle]
+pub fn option_nonzero_int(x: Option<NonZeroU64>) -> Option<NonZeroU64> {
+  x
+}
+
 // CHECK: @readonly_borrow(i32* noalias noundef readonly align 4 dereferenceable(4) %_1)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
@@ -156,7 +204,7 @@ pub fn return_slice(x: &[u16]) -> &[u16] {
   x
 }
 
-// CHECK: { i16, i16 } @enum_id_1(i16 %x.0, i16 %x.1)
+// CHECK: { i16, i16 } @enum_id_1(i16 noundef %x.0, i16 %x.1)
 #[no_mangle]
 pub fn enum_id_1(x: Option<Result<u16, u16>>) -> Option<Result<u16, u16>> {
   x
diff --git a/src/test/codegen/repr-transparent.rs b/src/test/codegen/repr-transparent.rs
index 7add522c158..53da573ae93 100644
--- a/src/test/codegen/repr-transparent.rs
+++ b/src/test/codegen/repr-transparent.rs
@@ -1,4 +1,4 @@
-// compile-flags: -C no-prepopulate-passes
+// compile-flags: -O -C no-prepopulate-passes
 
 // ignore-riscv64 riscv64 has an i128 type used with test_Vector
 // see codegen/riscv-abi for riscv functiona call tests
@@ -56,7 +56,7 @@ pub struct GenericPlusZst<T>(T, Zst2);
 #[repr(u8)]
 pub enum Bool { True, False, FileNotFound }
 
-// CHECK: define{{( dso_local)?}}{{( zeroext)?}} i8 @test_Gpz(i8{{( zeroext)?}} %_1)
+// CHECK: define{{( dso_local)?}} noundef{{( zeroext)?}} i8 @test_Gpz(i8 noundef{{( zeroext)?}} %_1)
 #[no_mangle]
 pub extern "C" fn test_Gpz(_: GenericPlusZst<Bool>) -> GenericPlusZst<Bool> { loop {} }