1
Fork 0

Auto merge of #100726 - jswrenn:transmute, r=oli-obk

safe transmute: use `Assume` struct to provide analysis options

This task was left as a TODO in #92268; resolving it brings [`BikeshedIntrinsicFrom`](https://doc.rust-lang.org/nightly/core/mem/trait.BikeshedIntrinsicFrom.html) more in line with the API defined in [MCP411](https://github.com/rust-lang/compiler-team/issues/411).

**Before:**
```rust
pub unsafe trait BikeshedIntrinsicFrom<
    Src,
    Context,
    const ASSUME_ALIGNMENT: bool,
    const ASSUME_LIFETIMES: bool,
    const ASSUME_VALIDITY: bool,
    const ASSUME_VISIBILITY: bool,
> where
    Src: ?Sized,
{}
```
**After:**
```rust
pub unsafe trait BikeshedIntrinsicFrom<Src, Context, const ASSUME: Assume = { Assume::NOTHING }>
where
    Src: ?Sized,
{}
```

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

r? `@oli-obk`

---

Related:
- https://github.com/rust-lang/compiler-team/issues/411
- https://github.com/rust-lang/rust/issues/99571
This commit is contained in:
bors 2022-09-04 07:55:44 +00:00
commit 8521a8c92d
79 changed files with 1320 additions and 735 deletions

View file

@ -6,11 +6,7 @@
#[macro_use]
extern crate tracing;
#[cfg(feature = "rustc")]
pub(crate) use rustc_data_structures::fx::{FxHashMap as Map, FxHashSet as Set};
#[cfg(not(feature = "rustc"))]
pub(crate) use std::collections::{HashMap as Map, HashSet as Set};
pub(crate) use rustc_data_structures::fx::{FxIndexMap as Map, FxIndexSet as Set};
pub(crate) mod layout;
pub(crate) mod maybe_transmutable;
@ -19,8 +15,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?"
@ -62,11 +58,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)]
@ -106,6 +108,54 @@ 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::ScalarInt;
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 variant = adt_def.non_enum_variant();
let fields = c.to_valtree().unwrap_branch();
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].unwrap_leaf() == ScalarInt::TRUE
};
Self {
alignment: get_field(sym::alignment),
lifetimes: get_field(sym::lifetimes),
safety: get_field(sym::safety),
validity: get_field(sym::validity),
}
}
}
}
#[cfg(feature = "rustc")]