diff --git a/src/cc65/expr.c b/src/cc65/expr.c index 70b28a408..44137a773 100644 --- a/src/cc65/expr.c +++ b/src/cc65/expr.c @@ -395,12 +395,18 @@ static unsigned FunctionParamList (FuncDesc* Func, int IsFastcall) } + /* Handle struct/union specially */ + if (IsTypeStruct (Expr.Type) || IsTypeUnion (Expr.Type)) { + /* Use the replacement type */ + Flags |= TypeOf (GetReplacementType (Expr.Type)); + } else { + /* Use the type of the argument for the push */ + Flags |= TypeOf (Expr.Type); + } + /* Load the value into the primary if it is not already there */ LoadExpr (Flags, &Expr); - /* Use the type of the argument for the push */ - Flags |= TypeOf (Expr.Type); - /* If this is a fastcall function, don't push the last argument */ if ((CurTok.Tok == TOK_COMMA && NextTok.Tok != TOK_RPAREN) || !IsFastcall) { unsigned ArgSize = sizeofarg (Flags); @@ -651,8 +657,8 @@ static void FunctionCall (ExprDesc* Expr) ED_FinalizeRValLoad (Expr); ReturnType = GetFuncReturn (Expr->Type); - /* Handle struct specially */ - if (IsTypeStruct (ReturnType)) { + /* Handle struct/union specially */ + if (IsTypeStruct (ReturnType) || IsTypeUnion (ReturnType)) { /* If there is no replacement type, then it is just the address */ if (ReturnType == GetReplacementType (ReturnType)) { /* Dereference it */ diff --git a/src/cc65/function.c b/src/cc65/function.c index 8da084ac1..df667e8fa 100644 --- a/src/cc65/function.c +++ b/src/cc65/function.c @@ -380,6 +380,7 @@ void NewFunc (SymEntry* Func) { int C99MainFunc = 0;/* Flag for C99 main function returning int */ SymEntry* Param; + const Type* RType; /* Real type used for struct parameters */ /* Get the function descriptor from the function entry */ FuncDesc* D = Func->V.F.Func; @@ -475,7 +476,12 @@ void NewFunc (SymEntry* Func) /* Pointer to function */ Flags = CF_PTR; } else { - Flags = TypeOf (D->LastParam->Type) | CF_FORCECHAR; + /* Handle struct/union specially */ + if (IsTypeStruct (D->LastParam->Type) || IsTypeUnion (D->LastParam->Type)) { + Flags = TypeOf (GetReplacementType (D->LastParam->Type)) | CF_FORCECHAR; + } else { + Flags = TypeOf (D->LastParam->Type) | CF_FORCECHAR; + } } g_push (Flags, 0); } @@ -498,11 +504,25 @@ void NewFunc (SymEntry* Func) Param = D->SymTab->SymHead; while (Param && (Param->Flags & SC_PARAM) != 0) { + /* Check if we need copy for struct/union type */ + RType = Param->Type; + if (IsTypeStruct (RType) || IsTypeUnion (RType)) { + RType = GetReplacementType (RType); + + /* If there is no replacement type, then it is just the address. + ** We don't currently support this case. + */ + if (RType == Param->Type) { + Error ("Passing %s of this size by value is not supported", GetBasicTypeName (Param->Type)); + } + } + + /* Check for a register variable */ if (SymIsRegVar (Param)) { /* Allocate space */ - int Reg = F_AllocRegVar (CurrentFunc, Param->Type); + int Reg = F_AllocRegVar (CurrentFunc, RType); /* Could we allocate a register? */ if (Reg < 0) { @@ -513,7 +533,7 @@ void NewFunc (SymEntry* Func) Param->V.R.RegOffs = Reg; /* Generate swap code */ - g_swap_regvars (Param->V.R.SaveOffs, Reg, CheckedSizeOf (Param->Type)); + g_swap_regvars (Param->V.R.SaveOffs, Reg, CheckedSizeOf (RType)); } }