From 89642d9578c1b7f24e10def7b0bc0b301ad10f61 Mon Sep 17 00:00:00 2001 From: Alec Date: Mon, 12 Sep 2016 20:17:32 -0700 Subject: [PATCH 1/3] Preliminary support for unions added. --- src/Language/Rust/AST.hs | 5 +++++ src/Language/Rust/Corrode/C.md | 37 +++++++++++++++++++--------------- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/src/Language/Rust/AST.hs b/src/Language/Rust/AST.hs index e13cee8..e6ff3f4 100644 --- a/src/Language/Rust/AST.hs +++ b/src/Language/Rust/AST.hs @@ -82,6 +82,7 @@ data ItemKind = Function [FunctionAttribute] String [(Mutable, Var, Type)] Type Block | Static Mutable Var Type Expr | Struct String [(String, Type)] + | Union String [(String, Type)] | Extern [ExternItem] | Use String | Enum String [Enumerator] @@ -102,6 +103,10 @@ instance Pretty ItemKind where text "struct" <+> text name <+> text "{" $+$ nest 4 (vcat [ text "pub" <+> text field <+> text ":" <+> pPrint ty <> text "," | (field, ty) <- fields ]) $+$ text "}" + pPrint (Union name cases) = + text "union" <+> text name <+> text "{" $+$ + nest 4 (vcat [ text "pub" <+> text field <+> text ":" <+> pPrint ty <> text "," | (field, ty) <- cases ]) $+$ + text "}" pPrint (Extern defs) = vcat ( text "extern {" : map (nest 4 . pPrint) defs diff --git a/src/Language/Rust/Corrode/C.md b/src/Language/Rust/Corrode/C.md index 13d3da3..86c797c 100644 --- a/src/Language/Rust/Corrode/C.md +++ b/src/Language/Rust/Corrode/C.md @@ -104,6 +104,7 @@ data IdentKind = SymbolIdent { identOfKind :: Ident } | TypedefIdent { identOfKind :: Ident } | StructIdent { identOfKind :: Ident } + | UnionIdent { identOfKind :: Ident } | EnumIdent { identOfKind :: Ident } deriving Eq ``` @@ -2125,6 +2126,7 @@ interpretExpr _ expr@(CMember obj ident deref node) = do obj' <- interpretExpr True $ if deref then CUnary CIndOp obj node else obj fields <- case resultType obj' of IsStruct _ fields -> return fields + IsUnion _ fields -> return fields IsIncomplete tyIdent -> do (_, struct) <- getIdent (StructIdent tyIdent) case struct of @@ -2770,6 +2772,7 @@ data CType | IsFunc CType [(Maybe (Rust.Mutable, Ident), CType)] Bool | IsPtr Rust.Mutable CType | IsStruct String [(String, CType)] + | IsUnion String [(String, CType)] | IsEnum String | IsIncomplete Ident deriving Show @@ -2835,6 +2838,7 @@ toRustType (IsPtr mut to) = let Rust.TypeName to' = toRustType to in Rust.TypeNa rustMut Rust.Mutable = "*mut " rustMut Rust.Immutable = "*const " toRustType (IsStruct name _fields) = Rust.TypeName name +toRustType (IsUnion name _fields) = Rust.TypeName name toRustType (IsEnum name) = Rust.TypeName name toRustType (IsIncomplete ident) = Rust.TypeName (identToString ident) ``` @@ -2889,13 +2893,15 @@ baseTypeOf specs = do go (CDoubleType _) (mut, _) = return (mut, IsFloat 64) go (CVoidType _) (mut, _) = return (mut, IsVoid) go (CBoolType _) (mut, _) = return (mut, IsBool) - go (CSUType (CStruct CStructTag (Just ident) Nothing _ _) _) (mut, _) = do - (_name, mty) <- getIdent (StructIdent ident) + go (CSUType (CStruct structTag (Just ident) Nothing _ _) _) (mut, _) = do + (_name, mty) <- getIdent $ case structTag of + CStructTag -> StructIdent ident + CUnionTag -> UnionIdent ident ty <- case mty of Just (_, ty) -> return ty Nothing -> emitIncomplete ident return (mut, ty) - go (CSUType (CStruct CStructTag mident (Just declarations) _ _) _) (mut, _) = do + go (CSUType (CStruct structTag mident (Just declarations) _ _) _) (mut, _) = do fields <- fmap concat $ forM declarations $ \ declaration@(CDecl spec decls _) -> do (storage, base) <- baseTypeOf spec case storage of @@ -2908,22 +2914,21 @@ baseTypeOf specs = do return (identToString field, ty) (_, Nothing, Just _size) -> unimplemented declaration _ -> badSource declaration "field in struct" - name <- case mident of - Just ident -> do + name <- case (mident,structTag) of + (Just ident, CStructTag) -> do let name = identToString ident addIdent (StructIdent ident) (Rust.Immutable, IsStruct name fields) - Nothing -> uniqueName "Struct" + (Just ident, CUnionTag) -> do + let name = identToString ident + addIdent (UnionIdent ident) (Rust.Immutable, IsUnion name fields) + (Nothing, CStructTag) -> uniqueName "Struct" + (Nothing, CUnionTag) -> uniqueName "Union" let attrs = [Rust.Attribute "derive(Clone, Copy)", Rust.Attribute "repr(C)"] - emitItems [Rust.Item attrs Rust.Public (Rust.Struct name [ (field, toRustType fieldTy) | (field, fieldTy) <- fields ])] - return (mut, IsStruct name fields) - go (CSUType (CStruct CUnionTag mident _ _ _) node) (mut, _) = do - ident <- case mident of - Just ident -> return ident - Nothing -> do - name <- uniqueName "Union" - return (internalIdentAt (posOfNode node) name) - ty <- emitIncomplete ident - return (mut, ty) + (structOrUnion, typ) = case structTag of + CStructTag -> (Rust.Struct, IsStruct) + CUnionTag -> (Rust.Union, IsUnion) + emitItems [Rust.Item attrs Rust.Public (structOrUnion name [ (field, toRustType fieldTy) | (field, fieldTy) <- fields ])] + return (mut, typ name fields) go spec@(CEnumType (CEnum (Just ident) Nothing _ _) _) (mut, _) = do (_, mty) <- getIdent (EnumIdent ident) case mty of From d7926d7f24a0d78a786860b166586e3a6d4f0d9d Mon Sep 17 00:00:00 2001 From: Alec Date: Fri, 16 Sep 2016 23:07:16 -0700 Subject: [PATCH 2/3] Adds support for initialization of unions Apart from a couple of obvious bug fixes, this focuses on initialization for unions. The previous initialization code had been designed with only struct and arrays in mind, so some pretty deep changes had to be made. * the data type `Initializer` now has three constructors for regular scalar initializers, aggregate initializers (arrays and structs), and union initializers. Might want to think about naming `Scalar` differently (see section 6.2.5 point 21). * `Initializer` is no longer a `Monoid`, since we can't make a `mempty` without knowing the type we are initializing. Instead, it is a `Semigroup`, with some combinations not valid. This means that either we will need to enforce `base >= 4.9` or `semigroups`. To the best of my current knowledge and testing, this accurately and completely implements initialization of unions as per C99. --- src/Language/Rust/AST.hs | 3 + src/Language/Rust/Corrode/C.md | 153 ++++++++++++++++++++++----------- 2 files changed, 105 insertions(+), 51 deletions(-) diff --git a/src/Language/Rust/AST.hs b/src/Language/Rust/AST.hs index e6ff3f4..1b0de04 100644 --- a/src/Language/Rust/AST.hs +++ b/src/Language/Rust/AST.hs @@ -152,6 +152,7 @@ data Expr | Var Var | Path Path | StructExpr String [(String, Expr)] (Maybe Expr) + | UnionExpr String (String, Expr) | Call Expr [Expr] | MethodCall Expr Var [Expr] | Lambda [Var] Expr @@ -228,6 +229,8 @@ instance Pretty Expr where : punctuate (text ",") ([ nest 4 (text name <> text ":" <+> pPrint val) | (name, val) <- fields ] ++ maybe [] (\b -> [ text ".." <> pPrint b ]) base) ++ [text "}"] ) + UnionExpr str (name, val) -> sep + [ text str <+> text "{", nest 4 (text name <> text ":" <+> pPrint val), text "}" ] Call f args -> cat ( pPrintPrec l 13 f <> text "(" : punctuate (text ",") (map (nest 4 . pPrint) args) diff --git a/src/Language/Rust/Corrode/C.md b/src/Language/Rust/Corrode/C.md index 86c797c..212ef3a 100644 --- a/src/Language/Rust/Corrode/C.md +++ b/src/Language/Rust/Corrode/C.md @@ -34,14 +34,15 @@ import Data.Char import Data.Foldable import qualified Data.IntMap.Strict as IntMap import Data.Maybe -import Data.Monoid +import Data.Monoid hiding ((<>)) +import Data.Semigroup import Data.List import qualified Data.Set as Set import Language.C import Language.C.Data.Ident import qualified Language.Rust.AST as Rust import Numeric -import Text.PrettyPrint +import Text.PrettyPrint hiding ((<>)) ``` This translation proceeds in a syntax-directed way. That is, we just @@ -847,36 +848,47 @@ get initialized to their zero-equivalent values. ```haskell data Initializer - = Initializer (Maybe Rust.Expr) (IntMap.IntMap Initializer) -``` - -```haskell -scalar :: Rust.Expr -> Initializer -scalar expr = Initializer (Just expr) IntMap.empty + = Scalar Rust.Expr + | Aggregate (Maybe Rust.Expr) (IntMap.IntMap Initializer) + | Union Int Initializer ``` Notice that combining initializers is an associative binary operation. -This motivates us to use the `Monoid` typeclass again to represent the -operation for combining two initializers. +However, there is really no such thing as an empty initializer (or rather +we would need to know the type of what is being initialized to say what an +empty initializer would look like). This motivates us to use the +`Semigroup` typeclass to represent the operation for combining two +initializers. + ```haskell -instance Monoid Initializer where +instance Semigroup Initializer where ``` -- The identity element in this case will be the empty initializer. This is - because whenever it is combined with another initializer (either from - the left or the right), the result is just the other initializer. +- Whenever there is a scalar expression on the right hand side, it +overrides everything that came before it. + + ```haskell + _ <> Scalar e = Scalar e + Scalar e <> Aggregate m a = Aggregate (m `mplus` Just e) a + Scalar _ <> Union i a = Union i a + ``` + +- For aggregate initializers, the one on the right overrides/shadows +definitions made by the one on the left. For unions, this is even more +restrictive: we only use information from the left intializer if both +intializers are for the same union variant. ```haskell - mempty = Initializer Nothing IntMap.empty + Aggregate m1 a <> Aggregate m2 b = Aggregate (m2 `mplus` m1) (if null m2 then IntMap.unionWith (<>) a b else b) + Union i a <> Union j b = Union j (if i /= j then b else a <> b) ``` -- When combining two initializers, the one on the right overrides/shadows - definitions made by the one on the left. +- Note that we should never be trying to combine an initializer for a union with +one for an aggregate (and vice-versa). This case should be unreachable (even if +we can't prove this in the type-system). ```haskell - mappend _ b@(Initializer (Just _) _) = b - mappend (Initializer m a) (Initializer Nothing b) = - Initializer m (IntMap.unionWith mappend a b) + _ <> _ = error "Tried to merge initializers of incompatible types" ``` Now, we need to concern ourselves with constructing these initializers in @@ -899,12 +911,21 @@ data Designator * encodes the type of the object pointed to, its index in the parent, remaining fields in the parent, and the parent designator -In several places, we need to know the type of a designated object. +In several places, we need to know the type, as well as the chain of types, +of a designated object. Another useful operation is to find the chain of +(union or aggregate) indices that lead to a designated object. ```haskell designatorType :: Designator -> CType -designatorType (Base ty) = ty -designatorType (From ty _ _ _) = ty +designatorType = head . designatorTypes + +designatorTypes :: Designator -> [CType] +designatorTypes (Base ty) = [ty] +designatorTypes (From ty _ _ desig) = ty : designatorTypes desig + +designatorIndices :: Designator -> [Int] +designatorIndices (Base _) = [] +designatorIndices (From _ j _ desig) = j : designatorIndices desig ``` Then, given a list of designators and the type we are currently in, we can @@ -918,9 +939,10 @@ objectFromDesignators ty desigs = Just <$> go ty desigs (Base ty) go :: CType -> [CDesignator] -> Designator -> EnvMonad Designator go _ [] obj = pure obj - go (IsStruct name fields) (d@(CMemberDesig ident _) : ds) obj = do + go (isStructOrUnion -> Just (name, fields, struct)) (d@(CMemberDesig ident _) : ds) obj = do case span (\ (field, _) -> identToString ident /= field) fields of - (_, []) -> badSource d ("designator for field not in struct " ++ name) + (_, []) -> let ty' = if struct then "struct" else "union" + in badSource d (unwords [ "designator for field not in", ty', name ]) (earlier, (_, ty') : rest) -> go ty' ds (From ty' (length earlier) (map snd rest) obj) go ty' (d : _) _ = badSource d ("designator for " ++ show ty') @@ -942,7 +964,7 @@ nextObject (From _ _ [] base) = nextObject base The type of an initializer expression is compatible with the type of the object it's initializing if either: -- Both have structure type and they're the same `struct`, +- Both have structure type and they're the same `struct` or `union`, - Or neither have structure type. In the latter case we don't check what type they are, because we can @@ -953,6 +975,9 @@ compatibleInitializer :: CType -> CType -> Bool compatibleInitializer (IsStruct name1 _) (IsStruct name2 _) = name1 == name2 compatibleInitializer IsStruct{} _ = False compatibleInitializer _ IsStruct{} = False +compatibleInitializer (IsUnion name1 _) (IsUnion name2 _) = name1 == name2 +compatibleInitializer IsUnion{} _ = False +compatibleInitializer _ IsUnion{} = False compatibleInitializer _ _ = True ``` @@ -973,6 +998,8 @@ nestedObject ty desig = case designatorType desig of ty' | ty `compatibleInitializer` ty' -> Just desig IsStruct _ ((_ , ty') : fields) -> nestedObject ty (From ty' 0 (map snd fields) desig) + IsUnion _ ((_ , ty') : _) -> + nestedObject ty (From ty' 0 [] desig) _ -> Nothing ``` @@ -983,8 +1010,8 @@ When we have a list of expressions, we start by parsing all of the designators into our internal representation. ```haskell -translateInitList :: CType -> CInitList -> EnvMonad Initializer -translateInitList ty list = do +translateInitList :: CType -> CInitList -> CInit -> EnvMonad Initializer +translateInitList ty list n = do objectsAndInitializers <- forM list $ \ (desigs, initial) -> do currObj <- objectFromDesignators ty desigs @@ -997,19 +1024,22 @@ types it points to the primitive itself. For example ```c struct point { int x, y }; +union number { int i; long l; float f; } int i = { 1, 3 }; struct point p = { 1, 3 }; +union number n = { 1, 3 }; ``` In the first example, the whole of `i` gets initialized to `1` (and `3` is ignored) since `i` is not a struct. On the other, in the second example, it is the fields of `p` that get initialized to `1` and `3` since `p` is a -struct. +struct. Finally, in the last example, only `i` gets initialized to `1`. ```haskell let base = case ty of IsStruct _ ((_,ty'):fields) -> From ty' 0 (map snd fields) (Base ty) + IsUnion _ ((_,ty'):_) -> From ty' 0 [] (Base ty) _ -> Base ty ``` @@ -1023,8 +1053,10 @@ initializer lists never affect the current object of their enclosing initializer. ```haskell - (_, initializer) <- foldM resolveCurrentObject (Just base, mempty) objectsAndInitializers - return initializer + (_, initializerOpt) <- foldM resolveCurrentObject (Just base, mempty) objectsAndInitializers + case getOption initializerOpt of + Nothing -> badSource n "Empty intializer lists are not allowed" + Just initializer -> return initializer ``` Resolution takes a current object to use if no designator is specified. It @@ -1034,9 +1066,9 @@ initialized. ```haskell resolveCurrentObject - :: (CurrentObject, Initializer) + :: (CurrentObject, Option Initializer) -> (CurrentObject, CInit) - -> EnvMonad (CurrentObject, Initializer) + -> EnvMonad (CurrentObject, Option Initializer) resolveCurrentObject (obj0, prior) (obj1, cinitial) = case obj1 `mplus` obj0 of Nothing -> return (Nothing, prior) Just obj -> do @@ -1051,7 +1083,7 @@ using `nestedObject`. ```haskell (obj', initial) <- case cinitial of CInitList list' _ -> do - initial <- translateInitList (designatorType obj) list' + initial <- translateInitList (designatorType obj) list' cinitial return (obj, initial) CInitExpr expr _ -> do expr' <- interpretExpr True expr @@ -1059,7 +1091,7 @@ using `nestedObject`. Nothing -> badSource cinitial "type in initializer" Just obj' -> do let s = castTo (designatorType obj') expr' - return (obj', scalar s) + return (obj', Scalar s) ``` Now that we've settled on the right current object and constructed an @@ -1067,12 +1099,15 @@ intermediate `Initializer` for it, we need to wrap the latter in a minimal aggregate initializer for each designator in the former. ```haskell - let indices = unfoldr (\o -> case o of - Base{} -> Nothing - From _ j _ p -> Just (j,p)) obj' - let initializer = foldl (\a j -> Initializer Nothing (IntMap.singleton j a)) initial indices - return (nextObject obj', prior `mappend` initializer) + let initializer = foldl + (\a (ty,j) -> case ty of + IsUnion{} -> Union j a + _ -> Aggregate Nothing (IntMap.singleton j a)) + initial + (tail (designatorTypes obj') `zip` designatorIndices obj') + + return (nextObject obj', prior `mappend` pure initializer) ``` Finally, we can implement the full `interpretInitializer` function we @@ -1090,12 +1125,12 @@ interpretInitializer ty initial = do CInitExpr expr _ -> do expr' <- interpretExpr True expr if resultType expr' `compatibleInitializer` ty - then pure $ scalar (castTo ty expr') + then pure $ Scalar (castTo ty expr') else badSource initial "initializer for incompatible type" - CInitList list _ -> translateInitList ty list + CInitList list _ -> translateInitList ty list initial zeroed <- zeroInitializer ty - case helper ty (zeroed `mappend` initial') of + case helper ty (zeroed <> initial') of Nothing -> badSource initial "initializer" Just expr -> pure expr @@ -1107,17 +1142,20 @@ initializes in a way that the underlying memory of the target is just zeroed out. ```haskell - zeroInitializer IsBool{} = return $ scalar (Rust.Lit (Rust.LitRep "false")) + zeroInitializer IsBool{} = return $ Scalar (Rust.Lit (Rust.LitRep "false")) zeroInitializer IsVoid{} = badSource initial "initializer for void" - zeroInitializer t@IsInt{} = return $ scalar (Rust.Lit (Rust.LitRep ("0" ++ s))) + zeroInitializer t@IsInt{} = return $ Scalar (Rust.Lit (Rust.LitRep ("0" ++ s))) where Rust.TypeName s = toRustType t - zeroInitializer t@IsFloat{} = return $ scalar (Rust.Lit (Rust.LitRep ("0" ++ s))) + zeroInitializer t@IsFloat{} = return $ Scalar (Rust.Lit (Rust.LitRep ("0" ++ s))) where Rust.TypeName s = toRustType t - zeroInitializer t@IsPtr{} = return $ scalar (Rust.Cast 0 (toRustType t)) - zeroInitializer t@IsFunc{} = return $ scalar (Rust.Cast 0 (toRustType t)) + zeroInitializer t@IsPtr{} = return $ Scalar (Rust.Cast 0 (toRustType t)) + zeroInitializer t@IsFunc{} = return $ Scalar (Rust.Cast 0 (toRustType t)) zeroInitializer (IsStruct _ fields) = do fields' <- mapM (zeroInitializer . snd) fields - return (Initializer Nothing (IntMap.fromList $ zip [0..] fields')) + return (Aggregate Nothing (IntMap.fromList $ zip [0..] fields')) + zeroInitializer (IsUnion _ fields) = do + field <- zeroInitializer (snd (head fields)) + return (Union 0 field) zeroInitializer IsEnum{} = unimplemented initial zeroInitializer (IsIncomplete ident) = do (_, struct) <- getIdent (StructIdent ident) @@ -1128,14 +1166,22 @@ zeroed out. ```haskell helper :: CType -> Initializer -> Maybe Rust.Expr - helper _ (Initializer (Just expr) initials) | IntMap.null initials = Just expr - helper (IsStruct str fields) (Initializer expr initials) = + helper _ (Scalar expr) = Just expr + helper _ (Aggregate (Just expr) initials) | IntMap.null initials = Just expr + helper (IsStruct str fields) (Aggregate expr initials) = Rust.StructExpr str <$> fields' <*> pure expr where fields' = forM (IntMap.toList initials) $ \ (idx, value) -> do (field, ty') <- listToMaybe (drop idx fields) value' <- helper ty' value Just (field, value') + helper (IsUnion str fields) (Union idx value) = + Rust.UnionExpr str <$> field' + where + field' = do + (field, ty') <- listToMaybe (drop idx fields) + value' <- helper ty' value + Just (field, value') helper _ _ = Nothing ``` @@ -2776,6 +2822,11 @@ data CType | IsEnum String | IsIncomplete Ident deriving Show + +isStructOrUnion :: CType -> Maybe (String, [(String, CType)], Bool) +isStructOrUnion (IsStruct name fields) = Just (name, fields, True) +isStructOrUnion (IsUnion name fields) = Just (name, fields, False) +isStructOrUnion _ = Nothing ``` Deriving a default implementation of the `Eq` typeclass for equality From 498c5ad595a7d3090321900f6534f285f01a453f Mon Sep 17 00:00:00 2001 From: Alec Date: Sat, 17 Sep 2016 18:50:59 -0700 Subject: [PATCH 3/3] Use `IsIncomplete` for union types too Add support for incomplete unions in the context of: * completing them * performing member access on them * zero initializing them Also added missing case in `Eq CType` for unions. --- src/Language/Rust/Corrode/C.md | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/Language/Rust/Corrode/C.md b/src/Language/Rust/Corrode/C.md index 212ef3a..dfba63a 100644 --- a/src/Language/Rust/Corrode/C.md +++ b/src/Language/Rust/Corrode/C.md @@ -36,7 +36,7 @@ import qualified Data.IntMap.Strict as IntMap import Data.Maybe import Data.Monoid hiding ((<>)) import Data.Semigroup -import Data.List +import Data.List hiding (union) import qualified Data.Set as Set import Language.C import Language.C.Data.Ident @@ -466,6 +466,7 @@ don't derive `Copy` or `Clone` for it. completeTypes = Set.fromList $ catMaybes [ case item of Rust.Item _ _ (Rust.Struct name _) -> Just name + Rust.Item _ _ (Rust.Union name _) -> Just name _ -> Nothing | item <- outputItems output ] @@ -508,6 +509,7 @@ those types aren't actually used. ```haskell neededTypes = Set.unions (usesTypes output : map declaredNames externTypes) keepItem (Rust.Item _ _ (Rust.Struct name _)) = name `Set.member` neededTypes + keepItem (Rust.Item _ _ (Rust.Union name _)) = name `Set.member` neededTypes keepItem (Rust.Item _ _ (Rust.Enum name _)) = name `Set.member` neededTypes keepItem _ = True @@ -1159,8 +1161,10 @@ zeroed out. zeroInitializer IsEnum{} = unimplemented initial zeroInitializer (IsIncomplete ident) = do (_, struct) <- getIdent (StructIdent ident) - case struct of + (_, union) <- getIdent (UnionIdent ident) + case struct `mplus` union of Just (_, ty'@IsStruct{}) -> zeroInitializer ty' + Just (_, ty'@IsUnion{}) -> zeroInitializer ty' _ -> badSource initial "initialization of incomplete type" ``` @@ -2175,10 +2179,12 @@ interpretExpr _ expr@(CMember obj ident deref node) = do IsUnion _ fields -> return fields IsIncomplete tyIdent -> do (_, struct) <- getIdent (StructIdent tyIdent) - case struct of + (_, union) <- getIdent (UnionIdent tyIdent) + case struct `mplus` union of Just (_, IsStruct _ fields) -> return fields + Just (_, IsUnion _ fields) -> return fields _ -> badSource expr "member access of incomplete type" - _ -> badSource expr "member access of non-struct" + _ -> badSource expr "member access of non-struct/union" let field = identToString ident ty <- case lookup field fields of Just ty -> return ty @@ -2846,6 +2852,8 @@ instance Eq CType where IsPtr aMut aTy == IsPtr bMut bTy = aMut == bMut && aTy == bTy IsStruct aName aFields == IsStruct bName bFields = aName == bName && aFields == bFields + IsUnion aName aFields == IsUnion bName bFields = + aName == bName && aFields == bFields IsEnum aName == IsEnum bName = aName == bName IsIncomplete aName == IsIncomplete bName = aName == bName _ == _ = False @@ -2860,8 +2868,8 @@ declaredNames :: CType -> Set.Set String declaredNames (IsFunc retTy args _) = Set.unions (map declaredNames (retTy : map snd args)) declaredNames (IsPtr _ ty) = declaredNames ty -declaredNames (IsStruct name fields) = Set.insert name - (Set.unions (map (declaredNames . snd) fields)) +declaredNames (IsStruct name fields) = Set.insert name (Set.unions (map (declaredNames . snd) fields)) +declaredNames (IsUnion name fields) = Set.insert name (Set.unions (map (declaredNames . snd) fields)) declaredNames (IsEnum name) = Set.singleton name declaredNames (IsIncomplete ident) = Set.singleton (identToString ident) declaredNames _ = Set.empty @@ -2888,8 +2896,8 @@ toRustType (IsPtr mut to) = let Rust.TypeName to' = toRustType to in Rust.TypeNa where rustMut Rust.Mutable = "*mut " rustMut Rust.Immutable = "*const " -toRustType (IsStruct name _fields) = Rust.TypeName name -toRustType (IsUnion name _fields) = Rust.TypeName name +toRustType (IsStruct name _) = Rust.TypeName name +toRustType (IsUnion name _) = Rust.TypeName name toRustType (IsEnum name) = Rust.TypeName name toRustType (IsIncomplete ident) = Rust.TypeName (identToString ident) ```