diff --git a/src/cc65/asmlabel.c b/src/cc65/asmlabel.c index 7d5db75e6..a07607048 100644 --- a/src/cc65/asmlabel.c +++ b/src/cc65/asmlabel.c @@ -52,7 +52,7 @@ -static struct Segments* CurrentFunctionSegment; +static struct SegContext* CurrentFunctionSegment; @@ -62,7 +62,7 @@ static struct Segments* CurrentFunctionSegment; -void UseLabelPoolFromSegments (struct Segments* Seg) +void UseLabelPoolFromSegments (struct SegContext* Seg) /* Use the info in segments for generating new label numbers */ { CurrentFunctionSegment = Seg; diff --git a/src/cc65/asmlabel.h b/src/cc65/asmlabel.h index dbfe2f443..7e8039cc4 100644 --- a/src/cc65/asmlabel.h +++ b/src/cc65/asmlabel.h @@ -44,7 +44,7 @@ -struct Segments; +struct SegContext; @@ -54,7 +54,7 @@ struct Segments; -void UseLabelPoolFromSegments (struct Segments* Seg); +void UseLabelPoolFromSegments (struct SegContext* Seg); /* Use the info in segments for generating new label numbers */ unsigned GetLocalLabel (void); diff --git a/src/cc65/datatype.c b/src/cc65/datatype.c index 37fe54023..cb013ca21 100644 --- a/src/cc65/datatype.c +++ b/src/cc65/datatype.c @@ -816,6 +816,14 @@ const Type* GetStructReplacementType (const Type* SType) +const Type* GetBitFieldDeclType (const Type* Type) +/* Get the original integer type used to declare the bit-field */ +{ + return Type + 1; +} + + + const Type* GetBitFieldChunkType (const Type* Type) /* Get the type needed to operate on the byte chunk containing the bit-field */ { @@ -864,6 +872,16 @@ int IsTypeFragBitField (const Type* T) +#if !defined(HAVE_INLINE) +int IsTypeFuncLike (const Type* T) +/* Return true if this is a function or a function pointer */ +{ + return IsTypeFunc (T) || IsTypeFuncPtr (T); +} +#endif + + + int IsObjectType (const Type* T) /* Return true if this is a fully described object type */ { @@ -923,6 +941,14 @@ int IsAggregateType (const Type* T) +int IsDerivedDeclaratorType (const Type* T) +/* Return true if this is an array, function or pointer type */ +{ + return IsTypeArray (T) || IsTypeFunc (T) || IsTypePtr (T); +} + + + int IsRelationType (const Type* T) /* Return true if this is an arithmetic, array or pointer type */ { @@ -957,6 +983,17 @@ int IsIncompleteESUType (const Type* T) +int IsPassByRefType (const Type* T) +/* Return true if this is a large struct/union type that doesn't fit in the +** primary. This returns false for the void value extension type since it is +** not passable at all. +*/ +{ + return IsClassStruct (T) && GetStructReplacementType (T) == T; +} + + + int IsEmptiableObjectType (const Type* T) /* Return true if this is a struct/union/void type that can have zero size */ { @@ -1223,7 +1260,7 @@ void SetESUTagSym (Type* T, struct SymEntry* S) const char* GetBasicTypeName (const Type* T) /* Return a const name string of the basic type. -** Return "type" for unknown basic types. +** Return "" for unknown basic types. */ { switch (GetRawTypeRank (T)) { @@ -1273,7 +1310,7 @@ const char* GetBasicTypeName (const Type* T) } } } - return "type"; + return ""; } @@ -1433,7 +1470,7 @@ static struct StrBuf* GetFullTypeNameWestEast (struct StrBuf* West, struct StrBu if (!IsTypeBitField (T)) { SB_AppendStr (&Buf, GetTagSymName (T)); } else { - SB_AppendStr (&Buf, GetBasicTypeName (T + 1)); + SB_AppendStr (&Buf, GetBasicTypeName (GetBitFieldDeclType (T))); } if (!SB_IsEmpty (West)) { diff --git a/src/cc65/datatype.h b/src/cc65/datatype.h index eebd3abd8..06bb9168b 100644 --- a/src/cc65/datatype.h +++ b/src/cc65/datatype.h @@ -482,6 +482,9 @@ const Type* GetUnderlyingType (const Type* Type); const Type* GetStructReplacementType (const Type* SType); /* Get a replacement type for passing a struct/union by value in the primary */ +const Type* GetBitFieldDeclType (const Type* Type); +/* Get the original integer type used to declare the bit-field */ + const Type* GetBitFieldChunkType (const Type* Type); /* Get the type needed to operate on the byte chunk containing the bit-field */ @@ -690,6 +693,17 @@ INLINE int IsTypeFuncPtr (const Type* T) # define IsTypeFuncPtr(T) (IsTypePtr (T) && IsTypeFunc (T+1)) #endif +#if defined(HAVE_INLINE) +INLINE int IsTypeFuncLike (const Type* T) +/* Return true if this is a function or a function pointer */ +{ + return IsTypeFunc (T) || IsTypeFuncPtr (T); +} +#else +int IsTypeFuncLike (const Type* T); +/* Return true if this is a function or a function pointer */ +#endif + #if defined(HAVE_INLINE) INLINE int IsClassInt (const Type* T) /* Return true if this is an integer type */ @@ -761,6 +775,9 @@ int IsDerivedType (const Type* T); int IsAggregateType (const Type* T); /* Return true if this is an array or struct type */ +int IsDerivedDeclaratorType (const Type* T); +/* Return true if this is an array, function or pointer type */ + int IsRelationType (const Type* T); /* Return true if this is an arithmetic, array or pointer type */ @@ -773,6 +790,12 @@ int IsESUType (const Type* T); int IsIncompleteESUType (const Type* T); /* Return true if this is an incomplete ESU type */ +int IsPassByRefType (const Type* T); +/* Return true if this is a large struct/union type that doesn't fit in the +** primary. This returns false for the void value extension type since it is +** not passable at all. +*/ + int IsEmptiableObjectType (const Type* T); /* Return true if this is a struct/union/void type that can have zero size */ @@ -1024,7 +1047,7 @@ void SetESUTagSym (Type* T, struct SymEntry* S); const char* GetBasicTypeName (const Type* T); /* Return a const name string of the basic type. -** Return "type" for unknown basic types. +** Return "" for unknown basic types. */ const char* GetFullTypeName (const Type* T); diff --git a/src/cc65/expr.c b/src/cc65/expr.c index fbb7beb37..f7ad5affc 100644 --- a/src/cc65/expr.c +++ b/src/cc65/expr.c @@ -1619,9 +1619,9 @@ static void hie11 (ExprDesc *Expr) break; case TOK_LPAREN: - /* Function call. */ - if (!IsTypeFunc (Expr->Type) && !IsTypeFuncPtr (Expr->Type)) { - /* Not a function */ + /* Function call */ + if (!IsTypeFuncLike (Expr->Type)) { + /* Not a function or function pointer */ Error ("Illegal function call"); /* Force the type to be a implicitly defined function, one ** returning an int and taking any number of arguments. @@ -2035,7 +2035,7 @@ void hie10 (ExprDesc* Expr) ** of dereference operators is legal, since the result will ** always be converted to "pointer to function". */ - if (IsTypeFuncPtr (Expr->Type) || IsTypeFunc (Expr->Type)) { + if (IsTypeFuncLike (Expr->Type)) { /* Expression not storable */ ED_MarkExprAsRVal (Expr); } else { @@ -3216,7 +3216,7 @@ static void parsesub (ExprDesc* Expr) Expr2.Flags |= Expr->Flags & E_MASK_KEEP_SUBEXPR; /* lhs cannot be function or pointer to function */ - if (IsTypeFunc (Expr->Type) || IsTypeFuncPtr (Expr->Type)) { + if (IsTypeFuncLike (Expr->Type)) { Error ("Invalid left operand for binary operator '-'"); /* Make it pointer to char to avoid further errors */ Expr->Type = type_uchar; @@ -3241,7 +3241,7 @@ static void parsesub (ExprDesc* Expr) MarkedExprWithCheck (hie9, &Expr2); /* rhs cannot be function or pointer to function */ - if (IsTypeFunc (Expr2.Type) || IsTypeFuncPtr (Expr2.Type)) { + if (IsTypeFuncLike (Expr2.Type)) { Error ("Invalid right operand for binary operator '-'"); /* Make it pointer to char to avoid further errors */ Expr2.Type = type_uchar; diff --git a/src/cc65/function.c b/src/cc65/function.c index 12a7b97bf..1ad89b111 100644 --- a/src/cc65/function.c +++ b/src/cc65/function.c @@ -547,7 +547,7 @@ void NewFunc (SymEntry* Func, FuncDesc* D) } /* Allocate code and data segments for this function */ - Func->V.F.Seg = PushSegments (Func); + Func->V.F.Seg = PushSegContext (Func); /* Use the info in the segments for generating new local labels */ UseLabelPoolFromSegments (Func->V.F.Seg); @@ -696,7 +696,7 @@ void NewFunc (SymEntry* Func, FuncDesc* D) } /* Switch back to the old segments */ - PopSegments (); + PopSegContext (); /* Reset the current function pointer */ FreeFunction (CurrentFunc); diff --git a/src/cc65/segments.c b/src/cc65/segments.c index 8283b9da5..764ae29ea 100644 --- a/src/cc65/segments.c +++ b/src/cc65/segments.c @@ -69,11 +69,11 @@ typedef struct { } SegAddrSize_t; -/* Pointer to the current segment list. Output goes here. */ -Segments* CS = 0; +/* Pointer to the current segment context. Output goes here. */ +SegContext* CS = 0; -/* Pointer to the global segment list */ -Segments* GS = 0; +/* Pointer to the global segment context */ +SegContext* GS = 0; /* Actual names for the segments */ static StrStack SegmentNames[SEG_COUNT]; @@ -86,12 +86,12 @@ static Collection SegmentAddrSizes; ** maximum stack depth is 2, so there is not really a need for a better ** implementation. */ -static Collection SegmentStack = STATIC_COLLECTION_INITIALIZER; +static Collection SegContextStack = STATIC_COLLECTION_INITIALIZER; /*****************************************************************************/ -/* Code */ +/* Segment name and address size */ /*****************************************************************************/ @@ -226,11 +226,17 @@ const char* GetSegName (segment_t Seg) -static Segments* NewSegments (SymEntry* Func) -/* Initialize a Segments structure (set all fields to NULL) */ +/*****************************************************************************/ +/* Segment context */ +/*****************************************************************************/ + + + +static SegContext* NewSegContext (SymEntry* Func) +/* Initialize a SegContext structure (set all fields to NULL) */ { /* Allocate memory */ - Segments* S = xmalloc (sizeof (Segments)); + SegContext* S = xmalloc (sizeof (SegContext)); /* Initialize the fields */ S->Text = NewTextSeg (Func); @@ -248,14 +254,14 @@ static Segments* NewSegments (SymEntry* Func) -Segments* PushSegments (SymEntry* Func) -/* Make the new segment list current but remember the old one */ +SegContext* PushSegContext (SymEntry* Func) +/* Make the new segment context current but remember the old one */ { /* Push the current pointer onto the stack */ - CollAppend (&SegmentStack, CS); + CollAppend (&SegContextStack, CS); - /* Create a new Segments structure */ - CS = NewSegments (Func); + /* Create a new SegContext structure */ + CS = NewSegContext (Func); /* Return the new struct */ return CS; @@ -263,14 +269,14 @@ Segments* PushSegments (SymEntry* Func) -void PopSegments (void) -/* Pop the old segment list (make it current) */ +void PopSegContext (void) +/* Pop the old segment context (make it current) */ { /* Must have something on the stack */ - PRECONDITION (CollCount (&SegmentStack) > 0); + PRECONDITION (CollCount (&SegContextStack) > 0); /* Pop the last segment and set it as current */ - CS = CollPop (&SegmentStack); + CS = CollPop (&SegContextStack); } @@ -278,13 +284,13 @@ void PopSegments (void) void CreateGlobalSegments (void) /* Create the global segments and remember them in GS */ { - GS = PushSegments (0); + GS = PushSegContext (0); } void UseDataSeg (segment_t DSeg) -/* For the current segment list, use the data segment DSeg */ +/* For the current segment context, use the data segment DSeg */ { /* Check the input */ PRECONDITION (CS && DSeg != SEG_CODE); @@ -372,7 +378,7 @@ void RemoveGlobalCode (void) -void OutputSegments (const Segments* S) +void OutputSegments (const SegContext* S) /* Output the given segments to the output file */ { /* Output the function prologue if the segments came from a function */ diff --git a/src/cc65/segments.h b/src/cc65/segments.h index 91d702df6..d7c9e3c11 100644 --- a/src/cc65/segments.h +++ b/src/cc65/segments.h @@ -78,8 +78,8 @@ typedef enum segment_t { } segment_t; /* A list of all segments used when generating code */ -typedef struct Segments Segments; -struct Segments { +typedef struct SegContext SegContext; +struct SegContext { struct TextSeg* Text; /* Text segment */ struct CodeSeg* Code; /* Code segment */ struct DataSeg* Data; /* Data segment */ @@ -90,11 +90,11 @@ struct Segments { unsigned NextDataLabel; /* Number to generate unique data labels */ }; -/* Pointer to the current segment list. Output goes here. */ -extern Segments* CS; +/* Pointer to the current segment context. Output goes here. */ +extern SegContext* CS; -/* Pointer to the global segment list */ -extern Segments* GS; +/* Pointer to the global segment context */ +extern SegContext* GS; @@ -132,17 +132,17 @@ void PopSegName (segment_t Seg); const char* GetSegName (segment_t Seg); /* Get the name of the given segment */ -Segments* PushSegments (struct SymEntry* Func); -/* Make the new segment list current but remember the old one */ +SegContext* PushSegContext (struct SymEntry* Func); +/* Make the new segment context current but remember the old one */ -void PopSegments (void); -/* Pop the old segment list (make it current) */ +void PopSegContext (void); +/* Pop the old segment context (make it current) */ void CreateGlobalSegments (void); /* Create the global segments and remember them in GS */ void UseDataSeg (segment_t DSeg); -/* For the current segment list, use the data segment DSeg */ +/* For the current segment context, use the data segment DSeg */ struct DataSeg* GetDataSeg (void); /* Return the current data segment */ @@ -165,7 +165,7 @@ int HaveGlobalCode (void); void RemoveGlobalCode (void); /* Remove all code from the global code segment. Used for error recovery. */ -void OutputSegments (const Segments* S); +void OutputSegments (const SegContext* S); /* Output the given segments to the output file */ diff --git a/src/cc65/symentry.h b/src/cc65/symentry.h index 5ebd30a75..76a4272ae 100644 --- a/src/cc65/symentry.h +++ b/src/cc65/symentry.h @@ -56,7 +56,7 @@ -struct Segments; +struct SegContext; struct LiteralPool; struct CodeEntry; @@ -156,7 +156,7 @@ struct SymEntry { /* Data for functions */ struct { - struct Segments* Seg; /* Segments for this function */ + struct SegContext* Seg; /* SegContext for this function */ struct LiteralPool* LitPool; /* Literal pool for this function */ } F; diff --git a/src/cc65/symtab.c b/src/cc65/symtab.c index 5efed63e8..a7436b6b6 100644 --- a/src/cc65/symtab.c +++ b/src/cc65/symtab.c @@ -1008,7 +1008,6 @@ SymEntry* AddBitField (const char* Name, const Type* T, unsigned Offs, Entry = NewSymEntry (Name, SC_BITFIELD); /* Set the symbol attributes. Bit-fields are always integral types. */ - Entry->Type = NewBitFieldOf (T, BitOffs, BitWidth); Entry->V.Offs = Offs; if (!SignednessSpecified) { @@ -1019,12 +1018,10 @@ SymEntry* AddBitField (const char* Name, const Type* T, unsigned Offs, ** is controlled by `--signed-chars`. In bit-fields, however, we perform the same ** `char -> unsigned char` adjustment that is performed with other integral types. */ - CHECK ((Entry->Type->C & T_MASK_SIGN) == T_SIGN_SIGNED || - IsRankChar (Entry->Type)); - Entry->Type[0].C &= ~T_MASK_SIGN; - Entry->Type[0].C |= T_SIGN_UNSIGNED; - Entry->Type[1].C &= ~T_MASK_SIGN; - Entry->Type[1].C |= T_SIGN_UNSIGNED; + CHECK (IsSignSigned (T) || IsRankChar (T)); + Entry->Type = NewBitFieldOf (GetUnsignedType (T), BitOffs, BitWidth); + } else { + Entry->Type = NewBitFieldOf (T, BitOffs, BitWidth); } /* Add the entry to the symbol table */ diff --git a/src/cc65/typecmp.c b/src/cc65/typecmp.c index c3239652f..bb8bca880 100644 --- a/src/cc65/typecmp.c +++ b/src/cc65/typecmp.c @@ -141,7 +141,7 @@ static void SetResult (typecmp_t* Result, typecmpcode_t Val) static typecmp_t* CmpQuals (const Type* lhst, const Type* rhst, typecmp_t* Result) -/* Copare the types regarding thier qualifiers. Return the Result */ +/* Compare the types regarding their qualifiers. Return via pointer *Result */ { TypeCode LeftQual, RightQual; @@ -249,16 +249,10 @@ static void DoCompare (const Type* lhs, const Type* rhs, typecmp_t* Result) /* Compare two types. Determine, where they differ */ - while (lhs->C != T_END) { - - /* Check if the end of the type string is reached */ - if (rhs->C == T_END) { - /* End of comparison reached */ - break; - } - + while (lhs->C != T_END && rhs->C != T_END) { /* Compare qualifiers */ if (CmpQuals (lhs, rhs, Result)->C == TC_INCOMPATIBLE) { + /* No need to compare further */ return; } @@ -266,6 +260,22 @@ static void DoCompare (const Type* lhs, const Type* rhs, typecmp_t* Result) LeftRank = (GetUnqualTypeCode (lhs) & T_MASK_RANK); RightRank = (GetUnqualTypeCode (rhs) & T_MASK_RANK); + /* Bit-fields are considered compatible if they have the same + ** signedness, bit-offset and bit-width. + */ + if (IsTypeBitField (lhs) || IsTypeBitField (rhs)) { + if (!IsTypeBitField (lhs) || + !IsTypeBitField (rhs) || + lhs->A.B.Offs != rhs->A.B.Offs || + lhs->A.B.Width != rhs->A.B.Width) { + /* Incompatible */ + goto Incompatible; + } + if (LeftRank != RightRank) { + SetResult (Result, TC_STRICT_COMPATIBLE); + } + } + /* If one side is a pointer and the other side is an array, both are ** compatible. */ @@ -280,56 +290,35 @@ static void DoCompare (const Type* lhs, const Type* rhs, typecmp_t* Result) } } - /* Bit-fields are considered compatible if they have the same - ** signedness, bit-offset and bit-width. - */ - if (IsTypeBitField (lhs) || IsTypeBitField (rhs)) { - if (!IsTypeBitField (lhs) || - !IsTypeBitField (rhs) || - lhs->A.B.Offs != rhs->A.B.Offs || - lhs->A.B.Width != rhs->A.B.Width) { - SetResult (Result, TC_INCOMPATIBLE); - } - if (LeftRank != RightRank) { - SetResult (Result, TC_STRICT_COMPATIBLE); - } - } - /* If the ranks are different, the types are incompatible */ if (LeftRank != RightRank) { - SetResult (Result, TC_INCOMPATIBLE); - return; + goto Incompatible; } /* Enums must be handled specially */ if ((IsTypeEnum (lhs) || IsTypeEnum (rhs))) { /* Compare the tag types */ - Sym1 = IsTypeEnum (lhs) ? GetESUTagSym (lhs) : 0; - Sym2 = IsTypeEnum (rhs) ? GetESUTagSym (rhs) : 0; + Sym1 = GetESUTagSym (lhs); + Sym2 = GetESUTagSym (rhs); + /* For the two to be identical, they must be declared in the same + ** scope and have the same name. + */ if (Sym1 != Sym2) { if (Sym1 == 0 || Sym2 == 0) { - /* Only one is an enum. So they can't be identical */ SetResult (Result, TC_STRICT_COMPATIBLE); - - } else { - /* For the two to be identical, they must be in the same - ** scope and have the same name. + } else if (Sym1->Owner != Sym2->Owner || + strcmp (Sym1->Name, Sym2->Name) != 0) { + /* If any one of the two is incomplete, we can't guess + ** their underlying types and have to assume that they + ** be incompatible. */ - if (Sym1->Owner != Sym2->Owner || - strcmp (Sym1->Name, Sym2->Name) != 0) { - - /* If any one of the two is incomplete, we can't guess - ** their underlying types and have to assume that they - ** be incompatible. - */ - if (SizeOf (lhs) == 0 || SizeOf (rhs) == 0) { - SetResult (Result, TC_INCOMPATIBLE); - return; - } + if (SizeOf (lhs) == 0 || SizeOf (rhs) == 0) { + goto Incompatible; } + SetResult (Result, TC_STRICT_COMPATIBLE); } } @@ -383,15 +372,13 @@ static void DoCompare (const Type* lhs, const Type* rhs, typecmp_t* Result) /* Check the remaining flags */ if ((F1->Flags & ~FD_IGNORE) != (F2->Flags & ~FD_IGNORE)) { /* Flags differ */ - SetResult (Result, TC_INCOMPATIBLE); - return; + goto Incompatible; } /* Compare the parameter lists */ if (EqualFuncParams (F1, F2) == 0) { /* Parameter list is not identical */ - SetResult (Result, TC_INCOMPATIBLE); - return; + goto Incompatible; } } @@ -406,8 +393,7 @@ static void DoCompare (const Type* lhs, const Type* rhs, typecmp_t* Result) if (LeftCount != UNSPECIFIED && RightCount != UNSPECIFIED) { /* Member count given but different */ - SetResult (Result, TC_INCOMPATIBLE); - return; + goto Incompatible; } /* We take into account which side is more specified */ @@ -436,8 +422,7 @@ static void DoCompare (const Type* lhs, const Type* rhs, typecmp_t* Result) /* This shouldn't happen in the current code base, but ** we still handle this case to be future-proof. */ - SetResult (Result, TC_INCOMPATIBLE); - return; + goto Incompatible; } } @@ -453,9 +438,11 @@ static void DoCompare (const Type* lhs, const Type* rhs, typecmp_t* Result) /* Check if lhs and rhs both reached ends */ if (lhs->C == T_END && rhs->C == T_END) { SetResult (Result, TC_IDENTICAL); - } else { - SetResult (Result, TC_INCOMPATIBLE); + return; } + +Incompatible: + SetResult (Result, TC_INCOMPATIBLE); } @@ -483,7 +470,10 @@ typecmp_t TypeCmp (const Type* lhs, const Type* rhs) void TypeCompatibilityDiagnostic (const Type* NewType, const Type* OldType, int IsError, const char* Msg) -/* Print error or warning message about type compatibility with proper type names */ +/* Print error or warning message about type compatibility with proper type +** names. The format string shall contain two '%s' specifiers for the names of +** the two types. +*/ { StrBuf NewTypeName = STATIC_STRBUF_INITIALIZER; StrBuf OldTypeName = STATIC_STRBUF_INITIALIZER; diff --git a/src/cc65/typecmp.h b/src/cc65/typecmp.h index 367df5245..fa97ca176 100644 --- a/src/cc65/typecmp.h +++ b/src/cc65/typecmp.h @@ -97,7 +97,10 @@ typecmp_t TypeCmp (const Type* lhs, const Type* rhs); /* Compare two types and return the result */ void TypeCompatibilityDiagnostic (const Type* NewType, const Type* OldType, int IsError, const char* Msg); -/* Print error or warning message about type compatibility with proper type names */ +/* Print error or warning message about type compatibility with proper type +** names. The format string shall contain two '%s' specifiers for the names of +** the two types. +*/