Skip to main content

charon_lib/ast/items/
fun_decl.rs

1use crate::ast::*;
2use derive_generic_visitor::{Drive, DriveMut, DriveTwo};
3use macros::EnumIsA;
4use macros::VariantName;
5use serde_state::DeserializeState;
6use serde_state::SerializeState;
7
8/// A function definition
9#[derive(Debug, Clone)]
10#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
11pub struct FunDecl {
12    pub def_id: FunDeclId,
13    /// The meta data associated with the declaration.
14    pub item_meta: ItemMeta,
15    pub generics: GenericParams,
16    /// The signature contains the inputs/output types and ABI details.
17    pub signature: Box<FunSig>,
18    /// The function kind: "regular" function, trait method declaration, etc.
19    pub src: FunSource,
20    /// The function body.
21    pub body: Body,
22}
23
24/// A function signature.
25#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
26#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
27pub struct FunSig {
28    /// Is the function unsafe or not
29    pub is_unsafe: bool,
30    /// The calling convention of this function.
31    pub abi: Abi,
32    /// Whether this is a C-variadic function (its last parameter is `...`).
33    pub is_variadic: bool,
34    pub inputs: Vec<Ty>,
35    pub output: Ty,
36}
37
38#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
39#[derive(VariantName, EnumIsA)]
40#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
41#[serde_state(stateless)]
42#[cfg_attr(feature = "charon_on_charon", charon::variants_prefix("Abi"))]
43pub enum Abi {
44    Rust,
45    C,
46    /// Rust's spelling for the ABI, e.g. "C-unwind" or "system".
47    Other(ustr::Ustr),
48}
49
50/// Where a given function came from.
51#[derive(Debug, Clone)]
52#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
53#[cfg_attr(feature = "charon_on_charon", charon::variants_suffix("Fun"))]
54pub enum FunSource {
55    /// A normal function.
56    Normal,
57    /// A synthetic function representing an ADT constructor.
58    AdtConstructor,
59    /// A default method in a trait declaration.
60    TraitDefault {
61        /// The trait declaration this item belongs to.
62        trait_ref: TraitDeclRef,
63        /// The method this corresponds to.
64        // TODO: also include method generics so we can recover a full `FnPtr::TraitMethod`
65        item_id: TraitMethodId,
66    },
67    /// A method in a trait implementation.
68    TraitImpl {
69        /// The trait implementation the method belongs to.
70        impl_ref: TraitImplRef,
71        /// The trait declaration that the impl block implements.
72        trait_ref: TraitDeclRef,
73        /// The method this corresponds to.
74        // TODO: also include method generics so we can recover a full `FnPtr::TraitMethod`
75        item_id: TraitMethodId,
76        /// True if the trait decl had a default implementation for this method and this item is a
77        /// copy of the default item.
78        reuses_default: bool,
79    },
80    /// Wraps a concrete implementation of a method into a function that takes `dyn Trait` as its
81    /// `Self` type. This shim casts the receiver to the known concrete type and calls the real
82    /// method.
83    VTableShim,
84    /// The initializer for a global.
85    GlobalInitializer(GlobalDeclRef),
86    /// A target-specific variant behind a `TargetDispatch` façade. The dispatcher is the function
87    /// with the `Body::TargetDispatch` body that dispatches to this function.
88    TargetDependent { dispatcher: FunDeclRef },
89}
90
91impl FunDecl {
92    /// Replace the generic parameters of this function with the ones given by the binder.
93    pub fn substitute_params(self, subst: Binder<GenericArgs>) -> Self {
94        let FunDecl {
95            def_id,
96            item_meta,
97            generics: _,
98            signature,
99            src,
100            body,
101        } = self;
102        let signature = signature.substitute(&subst.skip_binder);
103        let src = src.substitute(&subst.skip_binder);
104        let body = body.substitute(&subst.skip_binder);
105        FunDecl {
106            def_id,
107            item_meta,
108            generics: subst.params,
109            signature,
110            src,
111            body,
112        }
113    }
114
115    /// Whether this function is unsafe to call, because it is declared `unsafe` (safety.unsafe-call),
116    /// or because it is a safe `#[target_feature]` function (safety.unsafe-target-feature-call). This
117    /// may be overriden at the call site, if we can statically discharge the unsafety (see [`CallSafety`]).
118    pub fn is_unsafe_to_call(&self, _krate: &TranslatedCrate) -> bool {
119        self.signature.is_unsafe
120    }
121
122    /// Whether this function is unsafe to declare.
123    pub fn is_unsafe_to_declare(&self, _krate: &TranslatedCrate) -> bool {
124        // The initializer of a global is part of the global's declaration.
125        !matches!(self.src, FunSource::GlobalInitializer(_))
126            && self.item_meta.is_unsafe_to_declare()
127    }
128}
129
130impl Abi {
131    pub fn rust() -> Self {
132        Self::Rust
133    }
134
135    pub fn rust_name(&self) -> &str {
136        match self {
137            Self::Rust => "Rust",
138            Self::C => "C",
139            Self::Other(name) => name.as_str(),
140        }
141    }
142}