Skip to content

Commit 5c61cc7

Browse files
authored
Merge pull request rust-lang#261 from tarberd/feature_type_attributes
Add type attribute api.
2 parents 41857f9 + 05f0035 commit 5c61cc7

File tree

4 files changed

+129
-2
lines changed

4 files changed

+129
-2
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ llvm-sys-80 = { package = "llvm-sys", version = "80.3", optional = true }
101101
llvm-sys-90 = { package = "llvm-sys", version = "90.2", optional = true }
102102
llvm-sys-100 = { package = "llvm-sys", version = "100.2", optional = true }
103103
llvm-sys-110 = { package = "llvm-sys", version = "110.0", optional = true }
104-
llvm-sys-120 = { package = "llvm-sys", version = "120.0", optional = true }
104+
llvm-sys-120 = { package = "llvm-sys", version = "120.2", optional = true }
105105
once_cell = "1.4.1"
106106
parking_lot = "0.11"
107107
regex = "1"

src/attributes.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,14 @@
44
use llvm_sys::prelude::LLVMAttributeRef;
55
#[llvm_versions(3.9..=latest)]
66
use llvm_sys::core::{LLVMGetEnumAttributeKindForName, LLVMGetLastEnumAttributeKind, LLVMGetEnumAttributeKind, LLVMGetEnumAttributeValue, LLVMGetStringAttributeKind, LLVMGetStringAttributeValue, LLVMIsEnumAttribute, LLVMIsStringAttribute};
7+
#[llvm_versions(12.0..=latest)]
8+
use llvm_sys::core::{LLVMGetTypeAttributeValue, LLVMIsTypeAttribute};
79

810
#[llvm_versions(3.9..=latest)]
911
use std::ffi::CStr;
1012

13+
use crate::types::AnyTypeEnum;
14+
1115
// SubTypes: Attribute<Enum>, Attribute<String>
1216
/// Functions, function parameters, and return types can have `Attribute`s to indicate
1317
/// how they should be treated by optimizations and code generation.
@@ -67,6 +71,30 @@ impl Attribute {
6771
}
6872
}
6973

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+
pub fn is_type(self) -> bool {
95+
unsafe { LLVMIsTypeAttribute(self.attribute) == 1 }
96+
}
97+
7098
/// Gets the enum kind id associated with a builtin name.
7199
///
72100
/// # Example
@@ -191,6 +219,34 @@ impl Attribute {
191219
CStr::from_ptr(cstr_ptr)
192220
}
193221
}
222+
223+
/// Gets the type associated with a type attribute.
224+
///
225+
/// # Example
226+
///
227+
/// ```no_run
228+
/// use inkwell::context::Context;
229+
/// use inkwell::attributes::Attribute;
230+
/// use inkwell::types::AnyType;
231+
///
232+
/// let context = Context::create();
233+
/// let kind_id = Attribute::get_named_enum_kind_id("sret");
234+
/// let any_type = context.i32_type().as_any_type_enum();
235+
/// let type_attribute = context.create_type_attribute(
236+
/// kind_id,
237+
/// any_type,
238+
/// );
239+
///
240+
/// assert!(type_attribute.is_type());
241+
/// assert_eq!(type_attribute.get_type_value(), any_type);
242+
/// assert_ne!(type_attribute.get_type_value(), context.i64_type().as_any_type_enum());
243+
/// ```
244+
#[llvm_versions(12.0..=latest)]
245+
pub fn get_type_value(&self) -> AnyTypeEnum {
246+
assert!(self.is_type()); // FIXME: SubTypes
247+
248+
unsafe { AnyTypeEnum::new(LLVMGetTypeAttributeValue(self.attribute)) }
249+
}
194250
}
195251

196252
/// An `AttributeLoc` determines where on a function an attribute is assigned to.

src/context.rs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ use llvm_sys::core::{LLVMCreateEnumAttribute, LLVMCreateStringAttribute};
77
use llvm_sys::core::{LLVMConstInlineAsm};
88
#[llvm_versions(7.0..=latest)]
99
use llvm_sys::core::{LLVMGetInlineAsm};
10+
#[llvm_versions(12.0..=latest)]
11+
use llvm_sys::core::{LLVMCreateTypeAttribute};
1012
#[llvm_versions(7.0..=latest)]
1113
use crate::InlineAsmDialect;
1214
use llvm_sys::prelude::{LLVMContextRef, LLVMTypeRef, LLVMValueRef, LLVMDiagnosticInfoRef};
@@ -25,7 +27,7 @@ use crate::memory_buffer::MemoryBuffer;
2527
use crate::module::Module;
2628
use crate::support::{to_c_str, LLVMString};
2729
use crate::targets::TargetData;
28-
use crate::types::{BasicTypeEnum, FloatType, IntType, StructType, VoidType, AsTypeRef, FunctionType};
30+
use crate::types::{AnyTypeEnum, BasicTypeEnum, FloatType, IntType, StructType, VoidType, AsTypeRef, FunctionType};
2931
use crate::values::{AsValueRef, BasicMetadataValueEnum, BasicValueEnum, FunctionValue, StructValue, MetadataValue, VectorValue, PointerValue};
3032

3133
use std::marker::PhantomData;
@@ -905,6 +907,37 @@ impl Context {
905907
}
906908
}
907909

910+
/// Create an enum `Attribute` with an `AnyTypeEnum` attached to it.
911+
///
912+
/// # Example
913+
/// ```rust
914+
/// use inkwell::context::Context;
915+
/// use inkwell::attributes::Attribute;
916+
/// use inkwell::types::AnyType;
917+
///
918+
/// let context = Context::create();
919+
/// let kind_id = Attribute::get_named_enum_kind_id("sret");
920+
/// let any_type = context.i32_type().as_any_type_enum();
921+
/// let type_attribute = context.create_type_attribute(
922+
/// kind_id,
923+
/// any_type,
924+
/// );
925+
///
926+
/// assert!(type_attribute.is_type());
927+
/// assert_eq!(type_attribute.get_type_value(), any_type);
928+
/// assert_ne!(type_attribute.get_type_value(), context.i64_type().as_any_type_enum());
929+
/// ```
930+
#[llvm_versions(12.0..=latest)]
931+
pub fn create_type_attribute(&self, kind_id: u32, type_ref: AnyTypeEnum) -> Attribute {
932+
unsafe {
933+
Attribute::new(LLVMCreateTypeAttribute(
934+
self.context,
935+
kind_id,
936+
type_ref.as_type_ref(),
937+
))
938+
}
939+
}
940+
908941
/// Creates a const string which may be null terminated.
909942
///
910943
/// # Example

tests/all/test_attributes.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,44 @@ fn test_string_attributes() {
4040
assert_eq!(string_attribute.get_string_value().to_str(), Ok("my_val"));
4141
}
4242

43+
#[llvm_versions(12.0..=latest)]
44+
#[test]
45+
fn test_type_attribute() {
46+
use inkwell::types::{AnyType, BasicType};
47+
use inkwell::AddressSpace;
48+
49+
let context = Context::create();
50+
let kind_id = Attribute::get_named_enum_kind_id("sret");
51+
52+
let any_types = [
53+
context.i32_type().as_any_type_enum(),
54+
context.f32_type().as_any_type_enum(),
55+
context.void_type().as_any_type_enum(),
56+
context.i32_type().vec_type(1).as_any_type_enum(),
57+
context.i32_type().array_type(1).as_any_type_enum(),
58+
context.i32_type().fn_type(&[], false).as_any_type_enum(),
59+
context
60+
.i32_type()
61+
.ptr_type(AddressSpace::Local)
62+
.as_any_type_enum(),
63+
context
64+
.struct_type(&[context.i32_type().as_basic_type_enum()], false)
65+
.as_any_type_enum(),
66+
];
67+
68+
let different_type = context.i128_type().as_any_type_enum();
69+
assert!(!any_types.contains(&different_type));
70+
71+
for any_type in &any_types {
72+
let type_attribute = context.create_type_attribute(kind_id, *any_type);
73+
assert!(type_attribute.is_type());
74+
assert!(!type_attribute.is_enum());
75+
assert!(!type_attribute.is_string());
76+
assert_eq!(type_attribute.get_type_value(), *any_type);
77+
assert_ne!(type_attribute.get_type_value(), different_type);
78+
}
79+
}
80+
4381
#[test]
4482
fn test_attributes_on_function_values() {
4583
let context = Context::create();

0 commit comments

Comments
 (0)