1
1
#![ allow( non_camel_case_types) ]
2
2
#![ allow( non_upper_case_globals) ]
3
3
4
+ use std:: fmt:: Debug ;
4
5
use std:: marker:: PhantomData ;
5
6
6
7
use libc:: { c_char, c_int, c_uint, c_ulonglong, c_void, size_t} ;
@@ -19,6 +20,30 @@ pub type Bool = c_uint;
19
20
pub const True : Bool = 1 as Bool ;
20
21
pub const False : Bool = 0 as Bool ;
21
22
23
+ /// Wrapper for a raw enum value returned from LLVM's C APIs.
24
+ ///
25
+ /// For C enums returned by LLVM, it's risky to use a Rust enum as the return
26
+ /// type, because it would be UB if a later version of LLVM adds a new enum
27
+ /// value and returns it. Instead, return this raw wrapper, then convert to the
28
+ /// Rust-side enum explicitly.
29
+ #[ repr( transparent) ]
30
+ pub struct RawEnum < T > {
31
+ value : u32 ,
32
+ /// We don't own or consume a `T`, but we can produce one.
33
+ _rust_side_type : PhantomData < fn ( ) -> T > ,
34
+ }
35
+
36
+ impl < T : TryFrom < u32 > > RawEnum < T > {
37
+ #[ track_caller]
38
+ pub ( crate ) fn to_rust ( self ) -> T
39
+ where
40
+ T :: Error : Debug ,
41
+ {
42
+ // If this fails, the Rust-side enum is out of sync with LLVM's enum.
43
+ T :: try_from ( self . value ) . expect ( "enum value returned by LLVM should be known" )
44
+ }
45
+ }
46
+
22
47
#[ derive( Copy , Clone , PartialEq ) ]
23
48
#[ repr( C ) ]
24
49
#[ allow( dead_code) ] // Variants constructed by C++.
0 commit comments