Coverage Report

Created: 2024-10-16 07:58

/rust/registry/src/index.crates.io-6f17d22bba15001f/inkwell-0.1.1/src/attributes.rs
Line
Count
Source (jump to first uncovered line)
1
//! `Attribute`s are optional modifiers to functions, function parameters, and return types.
2
3
use llvm_sys::core::{
4
    LLVMGetEnumAttributeKind, LLVMGetEnumAttributeKindForName, LLVMGetEnumAttributeValue, LLVMGetLastEnumAttributeKind,
5
    LLVMGetStringAttributeKind, LLVMGetStringAttributeValue, LLVMIsEnumAttribute, LLVMIsStringAttribute,
6
};
7
#[llvm_versions(12.0..=latest)]
8
use llvm_sys::core::{LLVMGetTypeAttributeValue, LLVMIsTypeAttribute};
9
use llvm_sys::prelude::LLVMAttributeRef;
10
11
use std::ffi::CStr;
12
13
#[llvm_versions(12.0..=latest)]
14
use crate::types::AnyTypeEnum;
15
16
// SubTypes: Attribute<Enum>, Attribute<String>
17
// REVIEW: Should Attributes have a 'ctx lifetime?
18
/// Functions, function parameters, and return types can have `Attribute`s to indicate
19
/// how they should be treated by optimizations and code generation.
20
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
21
pub struct Attribute {
22
    pub(crate) attribute: LLVMAttributeRef,
23
}
24
25
impl Attribute {
26
    /// Creates a new `Attribute` from a raw pointer.
27
1.03M
    pub unsafe fn new(attribute: LLVMAttributeRef) -> Self {
28
1.03M
        debug_assert!(!attribute.is_null());
29
30
1.03M
        Attribute { attribute }
31
1.03M
    }
32
33
    /// Acquires the underlying raw pointer belonging to this `Attribute` type.
34
0
    pub fn as_mut_ptr(&self) -> LLVMAttributeRef {
35
0
        self.attribute
36
0
    }
37
38
    /// Determines whether or not an `Attribute` is an enum. This method will
39
    /// likely be removed in the future in favor of `Attribute`s being generically
40
    /// defined.
41
    ///
42
    /// # Example
43
    ///
44
    /// ```no_run
45
    /// use inkwell::context::Context;
46
    ///
47
    /// let context = Context::create();
48
    /// let enum_attribute = context.create_enum_attribute(0, 10);
49
    ///
50
    /// assert!(enum_attribute.is_enum());
51
    /// ```
52
0
    pub fn is_enum(self) -> bool {
53
0
        unsafe { LLVMIsEnumAttribute(self.attribute) == 1 }
54
0
    }
55
56
    /// Determines whether or not an `Attribute` is a string. This method will
57
    /// likely be removed in the future in favor of `Attribute`s being generically
58
    /// defined.
59
    ///
60
    /// # Example
61
    ///
62
    /// ```no_run
63
    /// use inkwell::context::Context;
64
    ///
65
    /// let context = Context::create();
66
    /// let string_attribute = context.create_string_attribute("my_key_123", "my_val");
67
    ///
68
    /// assert!(string_attribute.is_string());
69
    /// ```
70
0
    pub fn is_string(self) -> bool {
71
0
        unsafe { LLVMIsStringAttribute(self.attribute) == 1 }
72
0
    }
73
74
    /// Determines whether or not an `Attribute` is a type attribute. This method will
75
    /// likely be removed in the future in favor of `Attribute`s being generically
76
    /// defined.
77
    ///
78
    /// # Example
79
    ///
80
    /// ```no_run
81
    /// use inkwell::context::Context;
82
    /// use inkwell::attributes::Attribute;
83
    ///
84
    /// let context = Context::create();
85
    /// let kind_id = Attribute::get_named_enum_kind_id("sret");
86
    /// let type_attribute = context.create_type_attribute(
87
    ///     kind_id,
88
    ///     context.i32_type().into(),
89
    /// );
90
    ///
91
    /// assert!(type_attribute.is_type());
92
    /// ```
93
    #[llvm_versions(12.0..=latest)]
94
0
    pub fn is_type(self) -> bool {
95
0
        unsafe { LLVMIsTypeAttribute(self.attribute) == 1 }
96
0
    }
97
98
    /// Gets the enum kind id associated with a builtin name.
99
    ///
100
    /// # Example
101
    ///
102
    /// ```no_run
103
    /// use inkwell::attributes::Attribute;
104
    ///
105
    /// // This kind id doesn't exist:
106
    /// assert_eq!(Attribute::get_named_enum_kind_id("foobar"), 0);
107
    ///
108
    /// // These are real kind ids:
109
    /// assert_eq!(Attribute::get_named_enum_kind_id("align"), 1);
110
    /// assert_eq!(Attribute::get_named_enum_kind_id("builtin"), 5);
111
    /// ```
112
1.02M
    pub fn get_named_enum_kind_id(name: &str) -> u32 {
113
1.02M
        unsafe { LLVMGetEnumAttributeKindForName(name.as_ptr() as *const ::libc::c_char, name.len()) }
114
1.02M
    }
115
116
    /// Gets the kind id associated with an enum `Attribute`.
117
    ///
118
    /// # Example
119
    ///
120
    /// ```no_run
121
    /// use inkwell::context::Context;
122
    ///
123
    /// let context = Context::create();
124
    /// let enum_attribute = context.create_enum_attribute(0, 10);
125
    ///
126
    /// assert_eq!(enum_attribute.get_enum_kind_id(), 0);
127
    /// ```
128
    #[llvm_versions(4.0..=11.0)]
129
    pub fn get_enum_kind_id(self) -> u32 {
130
        assert!(self.get_enum_kind_id_is_valid()); // FIXME: SubTypes
131
132
        unsafe { LLVMGetEnumAttributeKind(self.attribute) }
133
    }
134
135
    /// Gets the kind id associated with an enum `Attribute`.
136
    ///
137
    /// # Example
138
    ///
139
    /// ```no_run
140
    /// use inkwell::context::Context;
141
    ///
142
    /// let context = Context::create();
143
    /// let enum_attribute = context.create_enum_attribute(0, 10);
144
    ///
145
    /// assert_eq!(enum_attribute.get_enum_kind_id(), 0);
146
    /// ```
147
    ///
148
    /// This function also works for type `Attribute`s.
149
    ///
150
    /// ```no_run
151
    /// use inkwell::context::Context;
152
    /// use inkwell::attributes::Attribute;
153
    /// use inkwell::types::AnyType;
154
    ///
155
    /// let context = Context::create();
156
    /// let kind_id = Attribute::get_named_enum_kind_id("sret");
157
    /// let any_type = context.i32_type().as_any_type_enum();
158
    /// let type_attribute = context.create_type_attribute(
159
    ///     kind_id,
160
    ///     any_type,
161
    /// );
162
    ///
163
    /// assert_eq!(type_attribute.get_enum_kind_id(), kind_id);
164
    /// ```
165
    #[llvm_versions(12.0..=latest)]
166
0
    pub fn get_enum_kind_id(self) -> u32 {
167
0
        assert!(self.get_enum_kind_id_is_valid()); // FIXME: SubTypes
168
169
0
        unsafe { LLVMGetEnumAttributeKind(self.attribute) }
170
0
    }
171
172
    #[llvm_versions(4.0..=11.0)]
173
    fn get_enum_kind_id_is_valid(self) -> bool {
174
        self.is_enum()
175
    }
176
177
    #[llvm_versions(12.0..=latest)]
178
0
    fn get_enum_kind_id_is_valid(self) -> bool {
179
0
        self.is_enum() || self.is_type()
180
0
    }
181
182
    /// Gets the last enum kind id associated with builtin names.
183
    ///
184
    /// # Example
185
    ///
186
    /// ```no_run
187
    /// use inkwell::attributes::Attribute;
188
    ///
189
    /// assert_eq!(Attribute::get_last_enum_kind_id(), 56);
190
    /// ```
191
0
    pub fn get_last_enum_kind_id() -> u32 {
192
0
        unsafe { LLVMGetLastEnumAttributeKind() }
193
0
    }
194
195
    /// Gets the value associated with an enum `Attribute`.
196
    ///
197
    /// # Example
198
    ///
199
    /// ```no_run
200
    /// use inkwell::context::Context;
201
    ///
202
    /// let context = Context::create();
203
    /// let enum_attribute = context.create_enum_attribute(0, 10);
204
    ///
205
    /// assert_eq!(enum_attribute.get_enum_value(), 10);
206
    /// ```
207
0
    pub fn get_enum_value(self) -> u64 {
208
0
        assert!(self.is_enum()); // FIXME: SubTypes
209
210
0
        unsafe { LLVMGetEnumAttributeValue(self.attribute) }
211
0
    }
212
213
    /// Gets the string kind id associated with a string attribute.
214
    ///
215
    /// # Example
216
    ///
217
    /// ```no_run
218
    /// use inkwell::context::Context;
219
    ///
220
    /// let context = Context::create();
221
    /// let string_attribute = context.create_string_attribute("my_key", "my_val");
222
    ///
223
    /// assert_eq!(string_attribute.get_string_kind_id().to_str(), Ok("my_key"));
224
    /// ```
225
    // TODO: Check if null, return option
226
0
    pub fn get_string_kind_id(&self) -> &CStr {
227
0
        assert!(self.is_string()); // FIXME: SubTypes
228
229
0
        let mut length = 0;
230
0
        let cstr_ptr = unsafe { LLVMGetStringAttributeKind(self.attribute, &mut length) };
231
0
232
0
        unsafe { CStr::from_ptr(cstr_ptr) }
233
0
    }
234
235
    /// Gets the string value associated with a string attribute.
236
    ///
237
    /// # Example
238
    ///
239
    /// ```no_run
240
    /// use inkwell::context::Context;
241
    ///
242
    /// let context = Context::create();
243
    /// let string_attribute = context.create_string_attribute("my_key", "my_val");
244
    ///
245
    /// assert_eq!(string_attribute.get_string_value().to_str(), Ok("my_val"));
246
    /// ```
247
0
    pub fn get_string_value(&self) -> &CStr {
248
0
        assert!(self.is_string()); // FIXME: SubTypes
249
250
0
        let mut length = 0;
251
0
        let cstr_ptr = unsafe { LLVMGetStringAttributeValue(self.attribute, &mut length) };
252
0
253
0
        unsafe { CStr::from_ptr(cstr_ptr) }
254
0
    }
255
256
    /// Gets the type associated with a type attribute.
257
    ///
258
    /// # Example
259
    ///
260
    /// ```no_run
261
    /// use inkwell::context::Context;
262
    /// use inkwell::attributes::Attribute;
263
    /// use inkwell::types::AnyType;
264
    ///
265
    /// let context = Context::create();
266
    /// let kind_id = Attribute::get_named_enum_kind_id("sret");
267
    /// let any_type = context.i32_type().as_any_type_enum();
268
    /// let type_attribute = context.create_type_attribute(
269
    ///     kind_id,
270
    ///     any_type,
271
    /// );
272
    ///
273
    /// assert!(type_attribute.is_type());
274
    /// assert_eq!(type_attribute.get_type_value(), any_type);
275
    /// assert_ne!(type_attribute.get_type_value(), context.i64_type().as_any_type_enum());
276
    /// ```
277
    #[llvm_versions(12.0..=latest)]
278
0
    pub fn get_type_value(&self) -> AnyTypeEnum {
279
0
        assert!(self.is_type()); // FIXME: SubTypes
280
281
0
        unsafe { AnyTypeEnum::new(LLVMGetTypeAttributeValue(self.attribute)) }
282
0
    }
283
}
284
285
/// An `AttributeLoc` determines where on a function an attribute is assigned to.
286
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
287
pub enum AttributeLoc {
288
    /// Assign to the `FunctionValue`'s return type.
289
    Return,
290
    /// Assign to one of the `FunctionValue`'s params (0-indexed).
291
    Param(u32),
292
    /// Assign to the `FunctionValue` itself.
293
    Function,
294
}
295
296
impl AttributeLoc {
297
1.26M
    pub(crate) fn get_index(self) -> u32 {
298
1.26M
        match self {
299
0
            AttributeLoc::Return => 0,
300
819k
            AttributeLoc::Param(index) => {
301
819k
                assert!(
302
819k
                    index <= u32::max_value() - 2,
303
0
                    "Param index must be <= u32::max_value() - 2"
304
                );
305
306
819k
                index + 1
307
            },
308
446k
            AttributeLoc::Function => u32::max_value(),
309
        }
310
1.26M
    }
311
}