@@ -183,8 +183,18 @@ impl ReprOptions {
183183
184184 /// Returns the discriminant type, given these `repr` options.
185185 /// This must only be called on enums!
186- pub fn discr_type ( & self ) -> IntegerType {
187- self . int . unwrap_or ( IntegerType :: Pointer ( true ) )
186+ ///
187+ /// This is the "typeck type" of the discriminant, which is effectively the maximum size:
188+ /// discriminant values will be wrapped to fit (with a lint). Layout can later decide to use a
189+ /// smaller type (which it will do depending on the actual discriminant values, also enforcing
190+ /// `c_enum_min_size` along the way) and that will work just fine, it just induces casts when
191+ /// getting/setting the discriminant.
192+ pub fn discr_type ( & self , cx : & impl HasDataLayout ) -> IntegerType {
193+ self . int . unwrap_or ( if self . c ( ) {
194+ IntegerType :: Fixed ( cx. data_layout ( ) . c_enum_max_size , true )
195+ } else {
196+ IntegerType :: Pointer ( true )
197+ } )
188198 }
189199
190200 /// Returns `true` if this `#[repr()]` should inhabit "smart enum
@@ -274,6 +284,8 @@ pub struct TargetDataLayout {
274284 /// Note: This isn't in LLVM's data layout string, it is `short_enum`
275285 /// so the only valid spec for LLVM is c_int::BITS or 8
276286 pub c_enum_min_size : Integer ,
287+ /// Maximum size of #[repr(C)] enums (defaults to c_longlong::BITS, which is always 64).
288+ pub c_enum_max_size : Integer ,
277289}
278290
279291impl Default for TargetDataLayout {
@@ -307,6 +319,10 @@ impl Default for TargetDataLayout {
307319 address_space_info : vec ! [ ] ,
308320 instruction_address_space : AddressSpace :: ZERO ,
309321 c_enum_min_size : Integer :: I32 ,
322+ // C23 allows enums to have any integer type. The largest integer type in the standard
323+ // is `long long`, which is always 64bits (judging from our own definition in
324+ // `library/core/src/ffi/primitives.rs`).
325+ c_enum_max_size : Integer :: I64 ,
310326 }
311327 }
312328}
@@ -327,7 +343,7 @@ impl TargetDataLayout {
327343 /// [llvm data layout string](https://llvm.org/docs/LangRef.html#data-layout)
328344 ///
329345 /// This function doesn't fill `c_enum_min_size` and it will always be `I32` since it can not be
330- /// determined from llvm string.
346+ /// determined from llvm string. Likewise, it does not fill in `c_enum_max_size`.
331347 pub fn parse_from_llvm_datalayout_string < ' a > (
332348 input : & ' a str ,
333349 default_address_space : AddressSpace ,
0 commit comments