blob: 5e9e625f4c74657a6dcfcd802ea2b31adc250ed8 [file] [log] [blame]
use rustc_macros::{Decodable, Encodable, HashStable};
use crate::ty::{Ty, TyCtxt, TypingEnv};
/// Summarizes how a parameter (a return place or an argument) is used inside a MIR body.
#[derive(Clone, Copy, PartialEq, Debug, Decodable, Encodable, HashStable)]
pub struct UsageSummary(u8);
bitflags::bitflags! {
impl UsageSummary: u8 {
/// This parameter is dropped when it `needs_drop`.
const DROP = 1 << 0;
/// There is a shared borrow to this parameter.
/// It allows for mutation unless parameter is `Freeze`.
const SHARED_BORROW = 1 << 1;
/// This parameter is mutated (excluding through a drop or a shared borrow).
const MUTATE = 1 << 2;
/// This parameter is captured (excluding through a drop).
const CAPTURE = 1 << 3;
}
}
/// Parameter attributes that can only be determined by examining the body of a function instead
/// of just its signature.
///
/// These can be useful for optimization purposes when a function is directly called. We compute
/// them and store them into the crate metadata so that downstream crates can make use of them.
///
/// Right now, we have `readonly` and `captures(none)`, but `no_alias` might be useful in the
/// future.
#[derive(Clone, Copy, PartialEq, Debug, Decodable, Encodable, HashStable)]
pub struct DeducedParamAttrs {
pub usage: UsageSummary,
}
impl DeducedParamAttrs {
/// Returns true if no attributes have been deduced.
#[inline]
pub fn is_default(self) -> bool {
self.usage.contains(UsageSummary::MUTATE | UsageSummary::CAPTURE)
}
/// For parameters passed indirectly, returns true if pointer is never written through.
pub fn read_only<'tcx>(
&self,
tcx: TyCtxt<'tcx>,
typing_env: TypingEnv<'tcx>,
ty: Ty<'tcx>,
) -> bool {
// Only if all checks pass is this truly read-only.
if self.usage.contains(UsageSummary::MUTATE) {
return false;
}
if self.usage.contains(UsageSummary::DROP) && ty.needs_drop(tcx, typing_env) {
return false;
}
if self.usage.contains(UsageSummary::SHARED_BORROW) && !ty.is_freeze(tcx, typing_env) {
return false;
}
true
}
/// For parameters passed indirectly, returns true if pointer is not captured, i.e., its
/// address is not captured, and pointer is used neither for reads nor writes after function
/// returns.
pub fn captures_none<'tcx>(
&self,
tcx: TyCtxt<'tcx>,
typing_env: TypingEnv<'tcx>,
ty: Ty<'tcx>,
) -> bool {
if self.usage.contains(UsageSummary::CAPTURE) {
return false;
}
if self.usage.contains(UsageSummary::DROP) && ty.needs_drop(tcx, typing_env) {
return false;
}
true
}
}