about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDylan DPC <99973273+Dylan-DPC@users.noreply.github.com>2023-02-21 14:19:58 +0530
committerGitHub <noreply@github.com>2023-02-21 14:19:58 +0530
commit4dea3a295f99f166472ddec78ed9d590900436ff (patch)
tree34b05afe9d34eaa2e63798f6a1bd4d3491b2cffc
parentf715e430aac0de131e2ad21804013ea405722a66 (diff)
parent0610df931449375a80bdd7ae03c2fd3116291c82 (diff)
downloadrust-4dea3a295f99f166472ddec78ed9d590900436ff.tar.gz
rust-4dea3a295f99f166472ddec78ed9d590900436ff.zip
Rollup merge of #108000 - y21:no-zero-init-for-uninhabited, r=jackh726
lint: don't suggest MaybeUninit::assume_init for uninhabited types

Creating a zeroed uninhabited type such as `!` or an empty enum with `mem::zeroed()` (or transmuting `()` to `!`) currently triggers this lint:
```rs
warning: the type `!` does not permit zero-initialization
 --> test.rs:5:23
  |
5 |         let _val: ! = mem::zeroed();
  |                       ^^^^^^^^^^^^^
  |                       |
  |                       this code causes undefined behavior when executed
  |                       help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
  |
  = note: the `!` type has no valid value
```
The `MaybeUninit` suggestion in the help message seems confusing/useless for uninhabited types, as such a type cannot be fully initialized in the first place (as the note implies).
This PR limits this help message to inhabited types which can be initialized
-rw-r--r--compiler/rustc_lint/src/builtin.rs8
-rw-r--r--compiler/rustc_lint/src/lints.rs13
-rw-r--r--tests/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr10
-rw-r--r--tests/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr10
-rw-r--r--tests/ui/lint/invalid_value.stderr40
-rw-r--r--tests/ui/statics/uninhabited-static.stderr10
6 files changed, 32 insertions, 59 deletions
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 11fb1f80a11..726042479e9 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -2635,7 +2635,13 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
                 cx.emit_spanned_lint(
                     INVALID_VALUE,
                     expr.span,
-                    BuiltinUnpermittedTypeInit { msg, ty: conjured_ty, label: expr.span, sub },
+                    BuiltinUnpermittedTypeInit {
+                        msg,
+                        ty: conjured_ty,
+                        label: expr.span,
+                        sub,
+                        tcx: cx.tcx,
+                    },
                 );
             }
         }
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 94a43ab0c46..aa6e230dc6d 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -8,7 +8,9 @@ use rustc_errors::{
 };
 use rustc_hir::def_id::DefId;
 use rustc_macros::{LintDiagnostic, Subdiagnostic};
-use rustc_middle::ty::{PolyExistentialTraitRef, Predicate, Ty, TyCtxt};
+use rustc_middle::ty::{
+    inhabitedness::InhabitedPredicate, PolyExistentialTraitRef, Predicate, Ty, TyCtxt,
+};
 use rustc_session::parse::ParseSess;
 use rustc_span::{edition::Edition, sym, symbol::Ident, Span, Symbol};
 
@@ -419,6 +421,7 @@ pub struct BuiltinUnpermittedTypeInit<'a> {
     pub ty: Ty<'a>,
     pub label: Span,
     pub sub: BuiltinUnpermittedTypeInitSub,
+    pub tcx: TyCtxt<'a>,
 }
 
 impl<'a> DecorateLint<'a, ()> for BuiltinUnpermittedTypeInit<'_> {
@@ -428,7 +431,13 @@ impl<'a> DecorateLint<'a, ()> for BuiltinUnpermittedTypeInit<'_> {
     ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> {
         diag.set_arg("ty", self.ty);
         diag.span_label(self.label, fluent::lint_builtin_unpermitted_type_init_label);
-        diag.span_label(self.label, fluent::lint_builtin_unpermitted_type_init_label_suggestion);
+        if let InhabitedPredicate::True = self.ty.inhabited_predicate(self.tcx) {
+            // Only suggest late `MaybeUninit::assume_init` initialization if the type is inhabited.
+            diag.span_label(
+                self.label,
+                fluent::lint_builtin_unpermitted_type_init_label_suggestion,
+            );
+        }
         self.sub.add_to_diagnostic(diag);
         diag
     }
diff --git a/tests/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr b/tests/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr
index 9710bf476ec..69fb1a59d4f 100644
--- a/tests/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr
+++ b/tests/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr
@@ -2,10 +2,7 @@ warning: the type `!` does not permit zero-initialization
   --> $DIR/validate_uninhabited_zsts.rs:4: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
+   |              ^^^^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
    |
    = note: the `!` type has no valid value
    = note: `#[warn(invalid_value)]` on by default
@@ -40,10 +37,7 @@ warning: the type `empty::Empty` does not permit zero-initialization
   --> $DIR/validate_uninhabited_zsts.rs:21:42
    |
 LL | const BAR: [empty::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
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
    |
 note: in this struct field
   --> $DIR/validate_uninhabited_zsts.rs:16:22
diff --git a/tests/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr b/tests/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr
index 9710bf476ec..69fb1a59d4f 100644
--- a/tests/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr
+++ b/tests/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr
@@ -2,10 +2,7 @@ warning: the type `!` does not permit zero-initialization
   --> $DIR/validate_uninhabited_zsts.rs:4: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
+   |              ^^^^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
    |
    = note: the `!` type has no valid value
    = note: `#[warn(invalid_value)]` on by default
@@ -40,10 +37,7 @@ warning: the type `empty::Empty` does not permit zero-initialization
   --> $DIR/validate_uninhabited_zsts.rs:21:42
    |
 LL | const BAR: [empty::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
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
    |
 note: in this struct field
   --> $DIR/validate_uninhabited_zsts.rs:16:22
diff --git a/tests/ui/lint/invalid_value.stderr b/tests/ui/lint/invalid_value.stderr
index 48fd4169da7..57531b0968f 100644
--- a/tests/ui/lint/invalid_value.stderr
+++ b/tests/ui/lint/invalid_value.stderr
@@ -61,10 +61,7 @@ error: the type `!` does not permit zero-initialization
   --> $DIR/invalid_value.rs:65:23
    |
 LL |         let _val: ! = mem::zeroed();
-   |                       ^^^^^^^^^^^^^
-   |                       |
-   |                       this code causes undefined behavior when executed
-   |                       help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+   |                       ^^^^^^^^^^^^^ this code causes undefined behavior when executed
    |
    = note: the `!` type has no valid value
 
@@ -72,10 +69,7 @@ error: the type `!` does not permit being left uninitialized
   --> $DIR/invalid_value.rs:66:23
    |
 LL |         let _val: ! = mem::uninitialized();
-   |                       ^^^^^^^^^^^^^^^^^^^^
-   |                       |
-   |                       this code causes undefined behavior when executed
-   |                       help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+   |                       ^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
    |
    = note: the `!` type has no valid value
 
@@ -83,10 +77,7 @@ error: the type `(i32, !)` does not permit zero-initialization
   --> $DIR/invalid_value.rs:68:30
    |
 LL |         let _val: (i32, !) = mem::zeroed();
-   |                              ^^^^^^^^^^^^^
-   |                              |
-   |                              this code causes undefined behavior when executed
-   |                              help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+   |                              ^^^^^^^^^^^^^ this code causes undefined behavior when executed
    |
    = note: the `!` type has no valid value
 
@@ -94,10 +85,7 @@ error: the type `(i32, !)` does not permit being left uninitialized
   --> $DIR/invalid_value.rs:69:30
    |
 LL |         let _val: (i32, !) = mem::uninitialized();
-   |                              ^^^^^^^^^^^^^^^^^^^^
-   |                              |
-   |                              this code causes undefined behavior when executed
-   |                              help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+   |                              ^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
    |
    = note: integers must be initialized
 
@@ -105,10 +93,7 @@ error: the type `Void` does not permit zero-initialization
   --> $DIR/invalid_value.rs:71:26
    |
 LL |         let _val: Void = mem::zeroed();
-   |                          ^^^^^^^^^^^^^
-   |                          |
-   |                          this code causes undefined behavior when executed
-   |                          help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+   |                          ^^^^^^^^^^^^^ this code causes undefined behavior when executed
    |
 note: enums with no inhabited variants have no valid value
   --> $DIR/invalid_value.rs:12:1
@@ -120,10 +105,7 @@ error: the type `Void` does not permit being left uninitialized
   --> $DIR/invalid_value.rs:72:26
    |
 LL |         let _val: Void = mem::uninitialized();
-   |                          ^^^^^^^^^^^^^^^^^^^^
-   |                          |
-   |                          this code causes undefined behavior when executed
-   |                          help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+   |                          ^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
    |
 note: enums with no inhabited variants have no valid value
   --> $DIR/invalid_value.rs:12:1
@@ -405,10 +387,7 @@ error: the type `TwoUninhabited` does not permit zero-initialization
   --> $DIR/invalid_value.rs:104:36
    |
 LL |         let _val: TwoUninhabited = mem::zeroed();
-   |                                    ^^^^^^^^^^^^^
-   |                                    |
-   |                                    this code causes undefined behavior when executed
-   |                                    help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+   |                                    ^^^^^^^^^^^^^ this code causes undefined behavior when executed
    |
 note: enums with no inhabited variants have no valid value
   --> $DIR/invalid_value.rs:42:1
@@ -420,10 +399,7 @@ error: the type `TwoUninhabited` does not permit being left uninitialized
   --> $DIR/invalid_value.rs:105:36
    |
 LL |         let _val: TwoUninhabited = mem::uninitialized();
-   |                                    ^^^^^^^^^^^^^^^^^^^^
-   |                                    |
-   |                                    this code causes undefined behavior when executed
-   |                                    help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+   |                                    ^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
    |
 note: enums with no inhabited variants have no valid value
   --> $DIR/invalid_value.rs:42:1
diff --git a/tests/ui/statics/uninhabited-static.stderr b/tests/ui/statics/uninhabited-static.stderr
index ef794bb36ac..437053a4476 100644
--- a/tests/ui/statics/uninhabited-static.stderr
+++ b/tests/ui/statics/uninhabited-static.stderr
@@ -53,10 +53,7 @@ warning: the type `Void` does not permit zero-initialization
   --> $DIR/uninhabited-static.rs:12:31
    |
 LL | static VOID2: Void = 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
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
    |
 note: enums with no inhabited variants have no valid value
   --> $DIR/uninhabited-static.rs:4:1
@@ -75,10 +72,7 @@ warning: the type `Void` does not permit zero-initialization
   --> $DIR/uninhabited-static.rs:16:32
    |
 LL | static NEVER2: Void = 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
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
    |
 note: enums with no inhabited variants have no valid value
   --> $DIR/uninhabited-static.rs:4:1