Skip to content

Commit

Permalink
Rollup merge of rust-lang#78324 - RalfJung:uninhabited-statics, r=oli…
Browse files Browse the repository at this point in the history
…-obk

ensure that statics are inhabited

Fixes rust-lang#74840

r? @oli-obk
  • Loading branch information
Dylan-DPC committed Oct 25, 2020
2 parents 93b4abf + 3bd5cc9 commit da10bd8
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 6 deletions.
30 changes: 30 additions & 0 deletions compiler/rustc_session/src/lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2647,6 +2647,35 @@ declare_lint! {
};
}

declare_lint! {
/// The `uninhabited_static` lint detects uninhbaited statics.
///
/// ### Example
///
/// ```rust
/// enum Void {}
/// extern {
/// static EXTERN: Void;
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Statics with an uninhabited type can never be initialized, so they are impossible to define.
/// However, this can be side-stepped with an `extern static`, leading to problems later in the
/// compiler which assumes that there are no initialized uninhabited places (such as locals or
/// statics). This was accientally allowed, but is being phased out.
pub UNINHABITED_STATIC,
Warn,
"uninhabited static",
@future_incompatible = FutureIncompatibleInfo {
reference: "issue #74840 <https://github.com/rust-lang/rust/issues/74840>",
edition: None,
};
}

declare_tool_lint! {
pub rustc::INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
Deny,
Expand Down Expand Up @@ -2732,6 +2761,7 @@ declare_lint_pass! {
CENUM_IMPL_DROP_CAST,
CONST_EVALUATABLE_UNCHECKED,
INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
UNINHABITED_STATIC,
]
}

Expand Down
51 changes: 45 additions & 6 deletions compiler/rustc_typeck/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::util::{Discr, IntTypeExt, Representability};
use rustc_middle::ty::{self, RegionKind, ToPredicate, Ty, TyCtxt};
use rustc_middle::ty::{self, ParamEnv, RegionKind, ToPredicate, Ty, TyCtxt};
use rustc_session::config::EntryFnType;
use rustc_session::lint::builtin::UNINHABITED_STATIC;
use rustc_span::symbol::sym;
use rustc_span::{self, MultiSpan, Span};
use rustc_target::spec::abi::Abi;
Expand Down Expand Up @@ -338,7 +339,7 @@ pub(super) fn check_struct(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) {
check_packed(tcx, span, def);
}

pub(super) fn check_union(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) {
fn check_union(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) {
let def_id = tcx.hir().local_def_id(id);
let def = tcx.adt_def(def_id);
def.destructor(tcx); // force the destructor to be evaluated
Expand All @@ -349,7 +350,7 @@ pub(super) fn check_union(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) {
}

/// Check that the fields of the `union` do not need dropping.
pub(super) fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> bool {
fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> bool {
let item_type = tcx.type_of(item_def_id);
if let ty::Adt(def, substs) = item_type.kind() {
assert!(def.is_union());
Expand Down Expand Up @@ -377,6 +378,36 @@ pub(super) fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: Local
true
}

/// Check that a `static` is inhabited.
fn check_static_inhabited<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) {
// Make sure statics are inhabited.
// Other parts of the compiler assume that there are no uninhabited places. In principle it
// would be enough to check this for `extern` statics, as statics with an initializer will
// have UB during initialization if they are uninhabited, but there also seems to be no good
// reason to allow any statics to be uninhabited.
let ty = tcx.type_of(def_id);
let layout = match tcx.layout_of(ParamEnv::reveal_all().and(ty)) {
Ok(l) => l,
Err(_) => {
// Generic statics are rejected, but we still reach this case.
tcx.sess.delay_span_bug(span, "generic static must be rejected");
return;
}
};
if layout.abi.is_uninhabited() {
tcx.struct_span_lint_hir(
UNINHABITED_STATIC,
tcx.hir().local_def_id_to_hir_id(def_id),
span,
|lint| {
lint.build("static of uninhabited type")
.note("uninhabited statics cannot be initialized, and any access would be an immediate error")
.emit();
},
);
}
}

/// Checks that an opaque type does not contain cycles and does not use `Self` or `T::Foo`
/// projections that would result in "inheriting lifetimes".
pub(super) fn check_opaque<'tcx>(
Expand Down Expand Up @@ -609,6 +640,7 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) {
let def_id = tcx.hir().local_def_id(it.hir_id);
tcx.ensure().typeck(def_id);
maybe_check_static_with_link_section(tcx, def_id, it.span);
check_static_inhabited(tcx, def_id, it.span);
}
hir::ItemKind::Const(..) => {
tcx.ensure().typeck(tcx.hir().local_def_id(it.hir_id));
Expand Down Expand Up @@ -691,7 +723,8 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) {
}
} else {
for item in m.items {
let generics = tcx.generics_of(tcx.hir().local_def_id(item.hir_id));
let def_id = tcx.hir().local_def_id(item.hir_id);
let generics = tcx.generics_of(def_id);
let own_counts = generics.own_counts();
if generics.params.len() - own_counts.lifetimes != 0 {
let (kinds, kinds_pl, egs) = match (own_counts.types, own_counts.consts) {
Expand Down Expand Up @@ -722,8 +755,14 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) {
.emit();
}

if let hir::ForeignItemKind::Fn(ref fn_decl, _, _) = item.kind {
require_c_abi_if_c_variadic(tcx, fn_decl, m.abi, item.span);
match item.kind {
hir::ForeignItemKind::Fn(ref fn_decl, _, _) => {
require_c_abi_if_c_variadic(tcx, fn_decl, m.abi, item.span);
}
hir::ForeignItemKind::Static(..) => {
check_static_inhabited(tcx, def_id, item.span);
}
_ => {}
}
}
}
Expand Down
17 changes: 17 additions & 0 deletions src/test/ui/statics/uninhabited-static.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#![feature(never_type)]
#![deny(uninhabited_static)]

enum Void {}
extern {
static VOID: Void; //~ ERROR static of uninhabited type
//~| WARN: previously accepted
static NEVER: !; //~ ERROR static of uninhabited type
//~| WARN: previously accepted
}

static VOID2: Void = unsafe { std::mem::transmute(()) }; //~ ERROR static of uninhabited type
//~| WARN: previously accepted
static NEVER2: Void = unsafe { std::mem::transmute(()) }; //~ ERROR static of uninhabited type
//~| WARN: previously accepted

fn main() {}
47 changes: 47 additions & 0 deletions src/test/ui/statics/uninhabited-static.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
error: static of uninhabited type
--> $DIR/uninhabited-static.rs:6:5
|
LL | static VOID: Void;
| ^^^^^^^^^^^^^^^^^^
|
note: the lint level is defined here
--> $DIR/uninhabited-static.rs:2:9
|
LL | #![deny(uninhabited_static)]
| ^^^^^^^^^^^^^^^^^^
= 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 #74840 <https://github.com/rust-lang/rust/issues/74840>
= note: uninhabited statics cannot be initialized, and any access would be an immediate error

error: static of uninhabited type
--> $DIR/uninhabited-static.rs:8:5
|
LL | static NEVER: !;
| ^^^^^^^^^^^^^^^^
|
= 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 #74840 <https://github.com/rust-lang/rust/issues/74840>
= note: uninhabited statics cannot be initialized, and any access would be an immediate error

error: static of uninhabited type
--> $DIR/uninhabited-static.rs:12:1
|
LL | static VOID2: Void = unsafe { std::mem::transmute(()) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= 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 #74840 <https://github.com/rust-lang/rust/issues/74840>
= note: uninhabited statics cannot be initialized, and any access would be an immediate error

error: static of uninhabited type
--> $DIR/uninhabited-static.rs:14:1
|
LL | static NEVER2: Void = unsafe { std::mem::transmute(()) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= 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 #74840 <https://github.com/rust-lang/rust/issues/74840>
= note: uninhabited statics cannot be initialized, and any access would be an immediate error

error: aborting due to 4 previous errors

0 comments on commit da10bd8

Please sign in to comment.