flowistry_pdg::rustc::mir

Struct LocalDecl

Source
pub struct LocalDecl<'tcx> {
    pub mutability: Mutability,
    pub local_info: ClearCrossCrate<Box<LocalInfo<'tcx>>>,
    pub ty: Ty<'tcx>,
    pub user_ty: Option<Box<UserTypeProjections>>,
    pub source_info: SourceInfo,
}
Expand description

A MIR local.

This can be a binding declared by the user, a temporary inserted by the compiler, a function argument, or the return place.

Fields§

§mutability: Mutability

Whether this is a mutable binding (i.e., let x or let mut x).

Temporaries and the return place are always mutable.

§local_info: ClearCrossCrate<Box<LocalInfo<'tcx>>>§ty: Ty<'tcx>

The type of this local.

§user_ty: Option<Box<UserTypeProjections>>

If the user manually ascribed a type to this variable, e.g., via let x: T, then we carry that type here. The MIR borrow checker needs this information since it can affect region inference.

§source_info: SourceInfo

The syntactic (i.e., not visibility) source scope the local is defined in. If the local was defined in a let-statement, this is within the let-statement, rather than outside of it.

This is needed because the visibility source scope of locals within a let-statement is weird.

The reason is that we want the local to be within the let-statement for lint purposes, but we want the local to be after the let-statement for names-in-scope purposes.

That’s it, if we have a let-statement like the one in this function:

fn foo(x: &str) {
    #[allow(unused_mut)]
    let mut x: u32 = { // <- one unused mut
        let mut y: u32 = x.parse().unwrap();
        y + 2
    };
    drop(x);
}

Then, from a lint point of view, the declaration of x: u32 (and y: u32) are within the #[allow(unused_mut)] scope - the lint scopes are the same as the AST/HIR nesting.

However, from a name lookup point of view, the scopes look more like as if the let-statements were match expressions:

fn foo(x: &str) {
    match {
        match x.parse::<u32>().unwrap() {
            y => y + 2
        }
    } {
        x => drop(x)
    };
}

We care about the name-lookup scopes for debuginfo - if the debuginfo instruction pointer is at the call to x.parse(), we want x to refer to x: &str, but if it is at the call to drop(x), we want it to refer to x: u32.

To allow both uses to work, we need to have more than a single scope for a local. We have the source_info.scope represent the “syntactic” lint scope (with a variable being under its let block) while the var_debug_info.source_info.scope represents the “local variable” scope (where the “rest” of a block is under all prior let-statements).

The end result looks like this:

ROOT SCOPE
 │{ argument x: &str }
 │
 │ │{ #[allow(unused_mut)] } // This is actually split into 2 scopes
 │ │                         // in practice because I'm lazy.
 │ │
 │ │← x.source_info.scope
 │ │← `x.parse().unwrap()`
 │ │
 │ │ │← y.source_info.scope
 │ │
 │ │ │{ let y: u32 }
 │ │ │
 │ │ │← y.var_debug_info.source_info.scope
 │ │ │← `y + 2`
 │
 │ │{ let x: u32 }
 │ │← x.var_debug_info.source_info.scope
 │ │← `drop(x)` // This accesses `x: u32`.

Auto Trait Implementations§

§

impl<'tcx> Freeze for LocalDecl<'tcx>

§

impl<'tcx> !RefUnwindSafe for LocalDecl<'tcx>

§

impl<'tcx> Send for LocalDecl<'tcx>

§

impl<'tcx> Sync for LocalDecl<'tcx>

§

impl<'tcx> Unpin for LocalDecl<'tcx>

§

impl<'tcx> !UnwindSafe for LocalDecl<'tcx>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dst: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dst. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.