@@ -183,8 +183,22 @@ impl ReprOptions {
183
183
184
184
/// Returns the discriminant type, given these `repr` options.
185
185
/// 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 (
194
+ if self . c ( )
195
+ && let Some ( max_size) = cx. data_layout ( ) . c_enum_max_size
196
+ {
197
+ IntegerType :: Fixed ( max_size, true )
198
+ } else {
199
+ IntegerType :: Pointer ( true )
200
+ } ,
201
+ )
188
202
}
189
203
190
204
/// Returns `true` if this `#[repr()]` should inhabit "smart enum
@@ -274,6 +288,8 @@ pub struct TargetDataLayout {
274
288
/// Note: This isn't in LLVM's data layout string, it is `short_enum`
275
289
/// so the only valid spec for LLVM is c_int::BITS or 8
276
290
pub c_enum_min_size : Integer ,
291
+ /// Maximum size of #[repr(C)] enums (defaults to pointer size).
292
+ pub c_enum_max_size : Option < Integer > ,
277
293
}
278
294
279
295
impl Default for TargetDataLayout {
@@ -307,6 +323,7 @@ impl Default for TargetDataLayout {
307
323
address_space_info : vec ! [ ] ,
308
324
instruction_address_space : AddressSpace :: ZERO ,
309
325
c_enum_min_size : Integer :: I32 ,
326
+ c_enum_max_size : None ,
310
327
}
311
328
}
312
329
}
@@ -327,7 +344,7 @@ impl TargetDataLayout {
327
344
/// [llvm data layout string](https://llvm.org/docs/LangRef.html#data-layout)
328
345
///
329
346
/// 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.
347
+ /// determined from llvm string. Likewise, it does not fill in `c_enum_max_size`.
331
348
pub fn parse_from_llvm_datalayout_string < ' a > (
332
349
input : & ' a str ,
333
350
default_address_space : AddressSpace ,
0 commit comments