Skip to content

Commit ec41e6d

Browse files
committed
Add a wrapper type for raw enum values returned by LLVM
1 parent b114040 commit ec41e6d

File tree

1 file changed

+25
-0
lines changed
  • compiler/rustc_codegen_llvm/src/llvm

1 file changed

+25
-0
lines changed

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

+25
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#![allow(non_camel_case_types)]
22
#![allow(non_upper_case_globals)]
33

4+
use std::fmt::Debug;
45
use std::marker::PhantomData;
56

67
use libc::{c_char, c_int, c_uint, c_ulonglong, c_void, size_t};
@@ -19,6 +20,30 @@ pub type Bool = c_uint;
1920
pub const True: Bool = 1 as Bool;
2021
pub 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

Comments
 (0)