1
Fork 0

safe transmute: use Assume struct to provide analysis options

This was left as a TODO in #92268, and brings the trait more in
line with what was defined in MCP411.

`Assume::visibility` has been renamed to `Assume::safety`, as
library safety is what's actually being assumed; visibility is
just the mechanism by which it is currently checked (this may
change).

ref: https://github.com/rust-lang/compiler-team/issues/411
ref: https://github.com/rust-lang/rust/issues/99571
This commit is contained in:
Jack Wrenn 2022-08-18 19:39:14 +00:00
parent e0dc8d7801
commit f46fffc276
77 changed files with 1321 additions and 721 deletions

View file

@ -26,8 +26,8 @@ pub(crate) mod maybe_transmutable;
pub struct Assume {
pub alignment: bool,
pub lifetimes: bool,
pub safety: bool,
pub validity: bool,
pub visibility: bool,
}
/// The type encodes answers to the question: "Are these types transmutable?"
@ -69,11 +69,17 @@ pub enum Reason {
#[cfg(feature = "rustc")]
mod rustc {
use super::*;
use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::InferCtxt;
use rustc_macros::{TypeFoldable, TypeVisitable};
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::Binder;
use rustc_middle::ty::Const;
use rustc_middle::ty::ParamEnv;
use rustc_middle::ty::Ty;
use rustc_middle::ty::TyCtxt;
/// The source and destination types of a transmutation.
#[derive(TypeFoldable, TypeVisitable, Debug, Clone, Copy)]
@ -113,6 +119,57 @@ mod rustc {
.answer()
}
}
impl Assume {
/// Constructs an `Assume` from a given const-`Assume`.
pub fn from_const<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
c: Const<'tcx>,
) -> Self {
use rustc_middle::ty::DestructuredConst;
use rustc_middle::ty::TypeVisitable;
use rustc_span::symbol::sym;
let c = c.eval(tcx, param_env);
if let Some(err) = c.error_reported() {
return Self { alignment: true, lifetimes: true, safety: true, validity: true };
}
let adt_def = c.ty().ty_adt_def().expect("The given `Const` must be an ADT.");
assert_eq!(
tcx.require_lang_item(LangItem::TransmuteOpts, None),
adt_def.did(),
"The given `Const` was not marked with the `{}` lang item.",
LangItem::TransmuteOpts.name(),
);
let DestructuredConst { variant, fields } = tcx.destructure_const(c);
let variant_idx = variant.expect("The given `Const` must be an ADT.");
let variant = adt_def.variant(variant_idx);
let get_field = |name| {
let (field_idx, _) = variant
.fields
.iter()
.enumerate()
.find(|(_, field_def)| name == field_def.name)
.expect(&format!("There were no fields named `{name}`."));
fields[field_idx].try_eval_bool(tcx, param_env).expect(&format!(
"The field named `{name}` lang item could not be evaluated to a bool."
))
};
Self {
alignment: get_field(sym::alignment),
lifetimes: get_field(sym::lifetimes),
safety: get_field(sym::safety),
validity: get_field(sym::validity),
}
}
}
}
#[cfg(feature = "rustc")]