11#![ allow( non_camel_case_types) ]
22#![ allow( non_upper_case_globals) ]
33
4+ use std:: fmt:: Debug ;
45use std:: marker:: PhantomData ;
56
67use libc:: { c_char, c_int, c_uint, c_ulonglong, c_void, size_t} ;
@@ -19,6 +20,30 @@ pub type Bool = c_uint;
1920pub const True : Bool = 1 as Bool ;
2021pub const False : Bool = 0 as Bool ;
2122
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+
2247#[ derive( Copy , Clone , PartialEq ) ]
2348#[ repr( C ) ]
2449#[ allow( dead_code) ] // Variants constructed by C++.
0 commit comments