1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-26 20:29:34 +00:00

Small fixes and tidy-up based on PR review.

Renamed GetReplacementType() to GetStructReplacementType().
Clarified in comments that most *Struct* facilities work for unions as well.
Made it clear in some error messages with regards to structs/unions.
This commit is contained in:
acqn 2020-07-19 13:47:48 +08:00 committed by Oliver Schmidt
parent 0c3e1b491f
commit 768e03a474
8 changed files with 60 additions and 47 deletions

View File

@ -55,15 +55,15 @@
static int CopyStruct (ExprDesc* LExpr, ExprDesc* RExpr) static int CopyStruct (ExprDesc* LExpr, ExprDesc* RExpr)
/* Copy the struct represented by RExpr to the one represented by LExpr */ /* Copy the struct/union represented by RExpr to the one represented by LExpr */
{ {
/* If the size is that of a basic type (char, int, long), we will copy /* If the size is that of a basic type (char, int, long), we will copy
** the struct using the primary register, otherwise we use memcpy. In ** the struct using the primary register, otherwise we use memcpy. In
** the former case, push the address only if really needed. ** the former case, push the address only if really needed.
*/ */
const Type* ltype = LExpr->Type; const Type* ltype = LExpr->Type;
const Type* stype = GetReplacementType (ltype); const Type* stype = GetStructReplacementType (ltype);
int UseReg = (stype != LExpr->Type); int UseReg = (stype != ltype);
if (UseReg) { if (UseReg) {
PushAddr (LExpr); PushAddr (LExpr);
@ -105,7 +105,7 @@ static int CopyStruct (ExprDesc* LExpr, ExprDesc* RExpr)
/* Push the address (or whatever is in ax in case of errors) */ /* Push the address (or whatever is in ax in case of errors) */
g_push (CF_PTR | CF_UNSIGNED, 0); g_push (CF_PTR | CF_UNSIGNED, 0);
/* Load the size of the struct into the primary */ /* Load the size of the struct or union into the primary */
g_getimmed (CF_INT | CF_UNSIGNED | CF_CONST, CheckedSizeOf (ltype), 0); g_getimmed (CF_INT | CF_UNSIGNED | CF_CONST, CheckedSizeOf (ltype), 0);
/* Call the memcpy function */ /* Call the memcpy function */
@ -137,12 +137,13 @@ void Assignment (ExprDesc* Expr)
/* Skip the '=' token */ /* Skip the '=' token */
NextToken (); NextToken ();
/* cc65 does not have full support for handling structs by value. Since /* cc65 does not have full support for handling structs or unions. Since
** assigning structs is one of the more useful operations from this ** assigning structs is one of the more useful operations from this family,
** family, allow it here. ** allow it here.
** Note: IsClassStruct() is also true for union types.
*/ */
if (IsClassStruct (ltype)) { if (IsClassStruct (ltype)) {
/* Copy the struct by value */ /* Copy the struct or union by value */
CopyStruct (Expr, &Expr2); CopyStruct (Expr, &Expr2);
} else if (ED_IsBitField (Expr)) { } else if (ED_IsBitField (Expr)) {

View File

@ -225,7 +225,7 @@ Type* GetImplicitFuncType (void)
const Type* GetReplacementType (const Type* SType) const Type* GetStructReplacementType (const Type* SType)
/* Get a replacement type for passing a struct/union in the primary register */ /* Get a replacement type for passing a struct/union in the primary register */
{ {
const Type* NewType; const Type* NewType;

View File

@ -243,7 +243,7 @@ Type* GetCharArrayType (unsigned Len);
Type* GetImplicitFuncType (void); Type* GetImplicitFuncType (void);
/* Return a type string for an inplicitly declared function */ /* Return a type string for an inplicitly declared function */
const Type* GetReplacementType (const Type* SType); const Type* GetStructReplacementType (const Type* SType);
/* Get a replacement type for passing a struct/union in the primary register */ /* Get a replacement type for passing a struct/union in the primary register */
Type* PointerTo (const Type* T); Type* PointerTo (const Type* T);
@ -483,7 +483,7 @@ INLINE int IsClassPtr (const Type* T)
#if defined(HAVE_INLINE) #if defined(HAVE_INLINE)
INLINE int IsClassStruct (const Type* T) INLINE int IsClassStruct (const Type* T)
/* Return true if this is a struct type */ /* Return true if this is a struct or union type */
{ {
return (GetClass (T) == T_CLASS_STRUCT); return (GetClass (T) == T_CLASS_STRUCT);
} }

View File

@ -398,7 +398,7 @@ static unsigned FunctionParamList (FuncDesc* Func, int IsFastcall)
/* Handle struct/union specially */ /* Handle struct/union specially */
if (IsTypeStruct (Expr.Type) || IsTypeUnion (Expr.Type)) { if (IsTypeStruct (Expr.Type) || IsTypeUnion (Expr.Type)) {
/* Use the replacement type */ /* Use the replacement type */
Flags |= TypeOf (GetReplacementType (Expr.Type)); Flags |= TypeOf (GetStructReplacementType (Expr.Type));
} else { } else {
/* Use the type of the argument for the push */ /* Use the type of the argument for the push */
Flags |= TypeOf (Expr.Type); Flags |= TypeOf (Expr.Type);
@ -660,7 +660,7 @@ static void FunctionCall (ExprDesc* Expr)
/* Handle struct/union specially */ /* Handle struct/union specially */
if (IsTypeStruct (ReturnType) || IsTypeUnion (ReturnType)) { if (IsTypeStruct (ReturnType) || IsTypeUnion (ReturnType)) {
/* If there is no replacement type, then it is just the address */ /* If there is no replacement type, then it is just the address */
if (ReturnType == GetReplacementType (ReturnType)) { if (ReturnType == GetStructReplacementType (ReturnType)) {
/* Dereference it */ /* Dereference it */
ED_IndExpr (Expr); ED_IndExpr (Expr);
ED_MarkExprAsRVal (Expr); ED_MarkExprAsRVal (Expr);
@ -1198,7 +1198,7 @@ static void ArrayRef (ExprDesc* Expr)
static void StructRef (ExprDesc* Expr) static void StructRef (ExprDesc* Expr)
/* Process struct field after . or ->. */ /* Process struct/union field after . or ->. */
{ {
ident Ident; ident Ident;
SymEntry* Field; SymEntry* Field;
@ -1214,38 +1214,41 @@ static void StructRef (ExprDesc* Expr)
return; return;
} }
/* Get the symbol table entry and check for a struct field */ /* Get the symbol table entry and check for a struct/union field */
strcpy (Ident, CurTok.Ident); strcpy (Ident, CurTok.Ident);
NextToken (); NextToken ();
Field = FindStructField (Expr->Type, Ident); Field = FindStructField (Expr->Type, Ident);
if (Field == 0) { if (Field == 0) {
Error ("Struct/union has no field named '%s'", Ident); Error ("No field named '%s' found in %s", GetBasicTypeName (Expr->Type), Ident);
/* Make the expression an integer at address zero */ /* Make the expression an integer at address zero */
ED_MakeConstAbs (Expr, 0, type_int); ED_MakeConstAbs (Expr, 0, type_int);
return; return;
} }
/* A struct is usually an lvalue. If not, it is a struct passed in the /* A struct/union is usually an lvalue. If not, it is a struct/union passed
** primary register, which is usually a result returned from a function. ** in the primary register, which is usually the result returned from a
** However, it is possible that this rvalue is a result of certain ** function. However, it is possible that this rvalue is the result of
** operations on an lvalue, and there are no reasons to disallow that. ** certain kind of operations on an lvalue such as assignment, and there
** So we just rely on the check on function returns to catch the errors ** are no reasons to disallow such use cases. So we just rely on the check
** and dereference the rvalue address of the struct here. ** upon function returns to catch the unsupported cases and dereference the
** rvalue address of the struct/union here all the time.
*/ */
if (IsTypePtr (Expr->Type) || if (IsTypePtr (Expr->Type) ||
(ED_IsRVal (Expr) && (ED_IsRVal (Expr) &&
ED_IsLocPrimary (Expr) && ED_IsLocPrimary (Expr) &&
Expr->Type == GetReplacementType (Expr->Type))) { Expr->Type == GetStructReplacementType (Expr->Type))) {
if (!ED_IsConst (Expr) && !ED_IsLocPrimary (Expr)) { if (!ED_IsConst (Expr) && !ED_IsLocPrimary (Expr)) {
/* If we have a non-const struct pointer, load its content now */ /* If we have a non-const struct/union pointer that is not in the
** primary yet, load its content now.
*/
LoadExpr (CF_NONE, Expr); LoadExpr (CF_NONE, Expr);
/* Clear the offset */ /* Clear the offset */
Expr->IVal = 0; Expr->IVal = 0;
} }
/* Dereference the expression */ /* Dereference the address expression */
ED_IndExpr (Expr); ED_IndExpr (Expr);
} else if (!ED_IsLocQuasiConst (Expr) && !ED_IsLocPrimaryOrExpr (Expr)) { } else if (!ED_IsLocQuasiConst (Expr) && !ED_IsLocPrimaryOrExpr (Expr)) {
@ -1255,7 +1258,7 @@ static void StructRef (ExprDesc* Expr)
LoadExpr (CF_NONE, Expr); LoadExpr (CF_NONE, Expr);
} }
/* The type is the type of the field plus any qualifiers from the struct */ /* The type is the field type plus any qualifiers from the struct/union */
if (IsClassStruct (Expr->Type)) { if (IsClassStruct (Expr->Type)) {
Q = GetQualifier (Expr->Type); Q = GetQualifier (Expr->Type);
} else { } else {
@ -1280,13 +1283,22 @@ static void StructRef (ExprDesc* Expr)
/* Safety check */ /* Safety check */
CHECK (Field->V.Offs + FieldSize <= StructSize); CHECK (Field->V.Offs + FieldSize <= StructSize);
/* The type of the operation depends on the type of the struct */ /* The type of the operation depends on the type of the struct/union */
switch (StructSize) { switch (StructSize) {
case 1: Flags = CF_CHAR | CF_UNSIGNED | CF_CONST; break; case 1:
case 2: Flags = CF_INT | CF_UNSIGNED | CF_CONST; break; Flags = CF_CHAR | CF_UNSIGNED | CF_CONST;
case 3: /* FALLTHROUGH */ break;
case 4: Flags = CF_LONG | CF_UNSIGNED | CF_CONST; break; case 2:
default: Internal ("Invalid struct size: %u", StructSize); break; Flags = CF_INT | CF_UNSIGNED | CF_CONST;
break;
case 3:
/* FALLTHROUGH */
case 4:
Flags = CF_LONG | CF_UNSIGNED | CF_CONST;
break;
default:
Internal ("Invalid %s size: %u", GetBasicTypeName (Expr->Type), StructSize);
break;
} }
/* Generate a shift to get the field in the proper position in the /* Generate a shift to get the field in the proper position in the
@ -1312,16 +1324,16 @@ static void StructRef (ExprDesc* Expr)
} else { } else {
/* Set the struct field offset */ /* Set the struct/union field offset */
Expr->IVal += Field->V.Offs; Expr->IVal += Field->V.Offs;
/* Use the new type */ /* Use the new type */
Expr->Type = FinalType; Expr->Type = FinalType;
/* An struct member is actually a variable. So the rules for variables /* The usual rules for variables with respect to the reference types
** with respect to the reference type apply: If it's an array, it is ** apply to struct/union fields as well: If a field is an array, it is
** virtually an rvalue address, otherwise it's an lvalue reference. (A ** virtually an rvalue address, otherwise it's an lvalue reference. (A
** function would also be an rvalue address, but a struct field cannot ** function would also be an rvalue address, but a struct/union cannot
** contain functions). ** contain functions).
*/ */
if (IsTypeArray (Expr->Type)) { if (IsTypeArray (Expr->Type)) {
@ -1376,7 +1388,7 @@ static void hie11 (ExprDesc *Expr)
case TOK_DOT: case TOK_DOT:
if (!IsClassStruct (Expr->Type)) { if (!IsClassStruct (Expr->Type)) {
Error ("Struct expected"); Error ("Struct or union expected");
} }
StructRef (Expr); StructRef (Expr);
break; break;
@ -1387,7 +1399,7 @@ static void hie11 (ExprDesc *Expr)
Expr->Type = ArrayToPtr (Expr->Type); Expr->Type = ArrayToPtr (Expr->Type);
} }
if (!IsClassPtr (Expr->Type) || !IsClassStruct (Indirect (Expr->Type))) { if (!IsClassPtr (Expr->Type) || !IsClassStruct (Indirect (Expr->Type))) {
Error ("Struct pointer expected"); Error ("Struct pointer or union pointer expected");
} }
StructRef (Expr); StructRef (Expr);
break; break;

View File

@ -478,7 +478,7 @@ void NewFunc (SymEntry* Func)
} else { } else {
/* Handle struct/union specially */ /* Handle struct/union specially */
if (IsTypeStruct (D->LastParam->Type) || IsTypeUnion (D->LastParam->Type)) { if (IsTypeStruct (D->LastParam->Type) || IsTypeUnion (D->LastParam->Type)) {
Flags = TypeOf (GetReplacementType (D->LastParam->Type)) | CF_FORCECHAR; Flags = TypeOf (GetStructReplacementType (D->LastParam->Type)) | CF_FORCECHAR;
} else { } else {
Flags = TypeOf (D->LastParam->Type) | CF_FORCECHAR; Flags = TypeOf (D->LastParam->Type) | CF_FORCECHAR;
} }
@ -507,7 +507,7 @@ void NewFunc (SymEntry* Func)
/* Check if we need copy for struct/union type */ /* Check if we need copy for struct/union type */
RType = Param->Type; RType = Param->Type;
if (IsTypeStruct (RType) || IsTypeUnion (RType)) { if (IsTypeStruct (RType) || IsTypeUnion (RType)) {
RType = GetReplacementType (RType); RType = GetStructReplacementType (RType);
/* If there is no replacement type, then it is just the address. /* If there is no replacement type, then it is just the address.
** We don't currently support this case. ** We don't currently support this case.

View File

@ -331,7 +331,7 @@ static void ReturnStatement (void)
/* Load the value into the primary */ /* Load the value into the primary */
if (IsTypeStruct (Expr.Type) || IsTypeUnion (Expr.Type)) { if (IsTypeStruct (Expr.Type) || IsTypeUnion (Expr.Type)) {
/* Handle struct/union specially */ /* Handle struct/union specially */
ReturnType = GetReplacementType (Expr.Type); ReturnType = GetStructReplacementType (Expr.Type);
if (ReturnType == Expr.Type) { if (ReturnType == Expr.Type) {
Error ("Returning %s of this size by value is not supported", GetBasicTypeName (Expr.Type)); Error ("Returning %s of this size by value is not supported", GetBasicTypeName (Expr.Type));
} }

View File

@ -488,24 +488,24 @@ SymEntry* FindTagSym (const char* Name)
SymEntry* FindStructField (const Type* T, const char* Name) SymEntry* FindStructField (const Type* T, const char* Name)
/* Find a struct field in the fields list */ /* Find a struct/union field in the fields list */
{ {
SymEntry* Field = 0; SymEntry* Field = 0;
/* The given type may actually be a pointer to struct */ /* The given type may actually be a pointer to struct/union */
if (IsTypePtr (T)) { if (IsTypePtr (T)) {
++T; ++T;
} }
/* Non-structs do not have any struct fields... */ /* Only structs/unions have struct/union fields... */
if (IsClassStruct (T)) { if (IsClassStruct (T)) {
/* Get a pointer to the struct/union type */ /* Get a pointer to the struct/union type */
const SymEntry* Struct = GetSymEntry (T); const SymEntry* Struct = GetSymEntry (T);
CHECK (Struct != 0); CHECK (Struct != 0);
/* Now search in the struct symbol table. Beware: The table may not /* Now search in the struct/union symbol table. Beware: The table may
** exist. ** not exist.
*/ */
if (Struct->V.S.SymTab) { if (Struct->V.S.SymTab) {
Field = FindSymInTable (Struct->V.S.SymTab, Name, HashStr (Name)); Field = FindSymInTable (Struct->V.S.SymTab, Name, HashStr (Name));

View File

@ -134,7 +134,7 @@ SymEntry* FindTagSym (const char* Name);
/* Find the symbol with the given name in the tag table */ /* Find the symbol with the given name in the tag table */
SymEntry* FindStructField (const Type* TypeArray, const char* Name); SymEntry* FindStructField (const Type* TypeArray, const char* Name);
/* Find a struct field in the fields list */ /* Find a struct/union field in the fields list */
unsigned short FindSPAdjustment (const char* Name); unsigned short FindSPAdjustment (const char* Name);
/* Search for an entry in the table of SP adjustments */ /* Search for an entry in the table of SP adjustments */