@@ -6,7 +6,7 @@ use aster;
66use ir:: annotations:: FieldAccessorKind ;
77use ir:: comp:: { CompInfo , CompKind , Field , Method } ;
88use ir:: context:: BindgenContext ;
9- use ir:: enum_ty:: Enum ;
9+ use ir:: enum_ty:: { Enum , EnumVariant , EnumVariantValue } ;
1010use ir:: function:: { Function , FunctionSig } ;
1111use ir:: int:: IntKind ;
1212use ir:: item:: { Item , ItemCanonicalName , ItemCanonicalPath , ItemId } ;
@@ -1224,17 +1224,127 @@ impl MethodCodegen for Method {
12241224 }
12251225}
12261226
1227+ /// A helper type to construct enums, either bitfield ones or rust-style ones.
1228+ enum EnumBuilder < ' a > {
1229+ Rust ( aster:: item:: ItemEnumBuilder < aster:: invoke:: Identity > ) ,
1230+ Bitfield {
1231+ canonical_name : & ' a str ,
1232+ aster : P < ast:: Item > ,
1233+ } ,
1234+ }
1235+
1236+ impl < ' a > EnumBuilder < ' a > {
1237+ /// Create a new enum given an item builder, a canonical name, a name for
1238+ /// the representation, and whether it should be represented as a rust enum.
1239+ fn new ( aster : aster:: item:: ItemBuilder < aster:: invoke:: Identity > ,
1240+ name : & ' a str ,
1241+ repr_name : & str ,
1242+ is_rust : bool )
1243+ -> Self {
1244+ if is_rust {
1245+ EnumBuilder :: Rust ( aster. enum_ ( name) )
1246+ } else {
1247+ EnumBuilder :: Bitfield {
1248+ canonical_name : name,
1249+ aster : aster. tuple_struct ( name)
1250+ . field ( )
1251+ . pub_ ( )
1252+ . ty ( )
1253+ . id ( repr_name)
1254+ . build ( ) ,
1255+ }
1256+ }
1257+ }
1258+
1259+ /// Add a variant to this enum.
1260+ fn with_variant ( self ,
1261+ ctx : & BindgenContext ,
1262+ variant : & EnumVariant ,
1263+ mangling_prefix : Option < & String > ,
1264+ rust_ty : P < ast:: Ty > ,
1265+ result : & mut CodegenResult )
1266+ -> Self {
1267+ let variant_name = ctx. rust_mangle ( variant. name ( ) ) ;
1268+ let expr = aster:: AstBuilder :: new ( ) . expr ( ) ;
1269+ let expr = match variant. val ( ) {
1270+ EnumVariantValue :: Signed ( v) => expr. int ( v) ,
1271+ EnumVariantValue :: Unsigned ( v) => expr. uint ( v) ,
1272+ } ;
1273+
1274+ match self {
1275+ EnumBuilder :: Rust ( b) => {
1276+ EnumBuilder :: Rust ( b. with_variant_ ( ast:: Variant_ {
1277+ name : ctx. rust_ident ( & * variant_name) ,
1278+ attrs : vec ! [ ] ,
1279+ data : ast:: VariantData :: Unit ( ast:: DUMMY_NODE_ID ) ,
1280+ disr_expr : Some ( expr) ,
1281+ } ) )
1282+ }
1283+ EnumBuilder :: Bitfield { canonical_name, .. } => {
1284+ let constant_name = match mangling_prefix {
1285+ Some ( prefix) => {
1286+ Cow :: Owned ( format ! ( "{}_{}" , prefix, variant_name) )
1287+ }
1288+ None => variant_name,
1289+ } ;
1290+
1291+ let constant = aster:: AstBuilder :: new ( )
1292+ . item ( )
1293+ . pub_ ( )
1294+ . const_ ( & * constant_name)
1295+ . expr ( )
1296+ . call ( )
1297+ . id ( canonical_name)
1298+ . arg ( )
1299+ . build ( expr)
1300+ . build ( )
1301+ . build ( rust_ty) ;
1302+ result. push ( constant) ;
1303+ self
1304+ }
1305+ }
1306+ }
1307+
1308+ fn build ( self ,
1309+ ctx : & BindgenContext ,
1310+ rust_ty : P < ast:: Ty > ,
1311+ result : & mut CodegenResult )
1312+ -> P < ast:: Item > {
1313+ match self {
1314+ EnumBuilder :: Rust ( b) => b. build ( ) ,
1315+ EnumBuilder :: Bitfield { canonical_name, aster } => {
1316+ let rust_ty_name = ctx. rust_ident_raw ( canonical_name) ;
1317+ let prefix = ctx. trait_prefix ( ) ;
1318+
1319+ let impl_ = quote_item ! ( ctx. ext_cx( ) ,
1320+ impl :: $prefix:: ops:: BitOr <$rust_ty> for $rust_ty {
1321+ type Output = Self ;
1322+
1323+ #[ inline]
1324+ fn bitor( self , other: Self ) -> Self {
1325+ $rust_ty_name( self . 0 | other. 0 )
1326+ }
1327+ }
1328+ )
1329+ . unwrap ( ) ;
1330+
1331+ result. push ( impl_) ;
1332+ aster
1333+ }
1334+ }
1335+ }
1336+ }
1337+
12271338impl CodeGenerator for Enum {
12281339 type Extra = Item ;
12291340
12301341 fn codegen ( & self ,
12311342 ctx : & BindgenContext ,
12321343 result : & mut CodegenResult ,
12331344 item : & Item ) {
1234- use ir:: enum_ty:: EnumVariantValue ;
1235-
12361345 let name = item. canonical_name ( ctx) ;
1237- let layout = item. expect_type ( ) . layout ( ctx) ;
1346+ let enum_ty = item. expect_type ( ) ;
1347+ let layout = enum_ty. layout ( ctx) ;
12381348
12391349 let repr = self . repr ( ) . map ( |repr| ctx. resolve_type ( repr) ) ;
12401350 let repr = match repr {
@@ -1270,10 +1380,24 @@ impl CodeGenerator for Enum {
12701380
12711381 let mut builder = aster:: AstBuilder :: new ( ) . item ( ) . pub_ ( ) ;
12721382
1383+ let is_bitfield = {
1384+ ctx. options ( ) . bitfield_enums . matches ( & name) ||
1385+ ( enum_ty. name ( ) . is_none ( ) &&
1386+ self . variants ( )
1387+ . iter ( )
1388+ . any ( |v| ctx. options ( ) . bitfield_enums . matches ( & v. name ( ) ) ) )
1389+ } ;
1390+
1391+ let is_rust_enum = !is_bitfield;
1392+
12731393 // FIXME: Rust forbids repr with empty enums. Remove this condition when
12741394 // this is allowed.
1275- if !self . variants ( ) . is_empty ( ) {
1276- builder = builder. with_attr ( attributes:: repr ( repr_name) ) ;
1395+ if is_rust_enum {
1396+ if !self . variants ( ) . is_empty ( ) {
1397+ builder = builder. with_attr ( attributes:: repr ( repr_name) ) ;
1398+ }
1399+ } else {
1400+ builder = builder. with_attr ( attributes:: repr ( "C" ) ) ;
12771401 }
12781402
12791403 if let Some ( comment) = item. comment ( ) {
@@ -1289,8 +1413,6 @@ impl CodeGenerator for Enum {
12891413
12901414 builder = builder. with_attr ( derives) ;
12911415
1292- let mut builder = builder. enum_ ( & name) ;
1293-
12941416 fn add_constant ( enum_ : & Type ,
12951417 // Only to avoid recomputing every time.
12961418 enum_canonical_name : & str ,
@@ -1318,52 +1440,64 @@ impl CodeGenerator for Enum {
13181440 result. push ( constant) ;
13191441 }
13201442
1321- // Used to mangle the constants we generate in the unnamed-enum case.
1322- let mut parent_canonical_name = None ;
1443+ let mut builder =
1444+ EnumBuilder :: new ( builder , & name , repr_name , is_rust_enum ) ;
13231445
13241446 // A map where we keep a value -> variant relation.
13251447 let mut seen_values = HashMap :: < _ , String > :: new ( ) ;
1326- let enum_ty = item. expect_type ( ) ;
13271448 let enum_rust_ty = item. to_rust_ty ( ctx) ;
1449+ let is_toplevel = item. is_toplevel ( ctx) ;
1450+
1451+ // Used to mangle the constants we generate in the unnamed-enum case.
1452+ let parent_canonical_name = if is_toplevel {
1453+ None
1454+ } else {
1455+ Some ( item. parent_id ( ) . canonical_name ( ctx) )
1456+ } ;
1457+
1458+ let constant_mangling_prefix = if enum_ty. name ( ) . is_none ( ) {
1459+ parent_canonical_name. as_ref ( ) . map ( |n| & * n)
1460+ } else {
1461+ Some ( & name)
1462+ } ;
1463+
13281464 for variant in self . variants ( ) . iter ( ) {
13291465 match seen_values. entry ( variant. val ( ) ) {
13301466 Entry :: Occupied ( ref entry) => {
1331- let existing_variant_name = entry. get ( ) ;
1332- let variant_name = ctx. rust_mangle ( variant. name ( ) ) ;
1333- add_constant ( enum_ty,
1334- & name,
1335- & * variant_name,
1336- existing_variant_name,
1337- enum_rust_ty. clone ( ) ,
1338- result) ;
1467+ if is_rust_enum {
1468+ let existing_variant_name = entry. get ( ) ;
1469+ let variant_name = ctx. rust_mangle ( variant. name ( ) ) ;
1470+ add_constant ( enum_ty,
1471+ & name,
1472+ & * variant_name,
1473+ existing_variant_name,
1474+ enum_rust_ty. clone ( ) ,
1475+ result) ;
1476+ } else {
1477+ builder = builder. with_variant ( ctx,
1478+ variant,
1479+ constant_mangling_prefix,
1480+ enum_rust_ty. clone ( ) ,
1481+ result) ;
1482+ }
13391483 }
13401484 Entry :: Vacant ( entry) => {
1341- let expr = aster:: AstBuilder :: new ( ) . expr ( ) ;
1342- let expr = match variant. val ( ) {
1343- EnumVariantValue :: Signed ( val) => expr. int ( val) ,
1344- EnumVariantValue :: Unsigned ( val) => expr. uint ( val) ,
1345- } ;
1485+ builder = builder. with_variant ( ctx,
1486+ variant,
1487+ constant_mangling_prefix,
1488+ enum_rust_ty. clone ( ) ,
1489+ result) ;
1490+
13461491 let variant_name = ctx. rust_mangle ( variant. name ( ) ) ;
1347- builder = builder. with_variant_ ( ast:: Variant_ {
1348- name : ctx. rust_ident ( & * variant_name) ,
1349- attrs : vec ! [ ] ,
1350- data : ast:: VariantData :: Unit ( ast:: DUMMY_NODE_ID ) ,
1351- disr_expr : Some ( expr) ,
1352- } ) ;
13531492
13541493 // If it's an unnamed enum, we also generate a constant so
13551494 // it can be properly accessed.
1356- if enum_ty. name ( ) . is_none ( ) {
1495+ if is_rust_enum && enum_ty. name ( ) . is_none ( ) {
13571496 // NB: if we want to do this for other kind of nested
13581497 // enums we can probably mangle the name.
1359- let mangled_name = if item . is_toplevel ( ctx ) {
1498+ let mangled_name = if is_toplevel {
13601499 variant_name. clone ( )
13611500 } else {
1362- if parent_canonical_name. is_none ( ) {
1363- parent_canonical_name = Some ( item. parent_id ( )
1364- . canonical_name ( ctx) ) ;
1365- }
1366-
13671501 let parent_name = parent_canonical_name. as_ref ( )
13681502 . unwrap ( ) ;
13691503
@@ -1384,8 +1518,8 @@ impl CodeGenerator for Enum {
13841518 }
13851519 }
13861520
1387-
1388- result. push ( builder . build ( ) ) ;
1521+ let enum_ = builder . build ( ctx , enum_rust_ty , result ) ;
1522+ result. push ( enum_ ) ;
13891523 }
13901524}
13911525
0 commit comments