1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-07 23:29:39 +00:00

Fixed ternary result type detection with pointer types.

Fixed pointer type comparison and conversion, especially regarding qualifiers.
Improved diagnostics about type comparison and conversion.
Reorganized some type-comparison/conversion functions.
This commit is contained in:
acqn 2021-03-15 16:59:08 +08:00 committed by Oliver Schmidt
parent 31c1172a3a
commit b802efde54
9 changed files with 466 additions and 336 deletions

View File

@ -78,7 +78,7 @@ static int CopyStruct (ExprDesc* LExpr, ExprDesc* RExpr)
hie1 (RExpr);
/* Check for equality of the structs/unions */
if (TypeCmp (ltype, RExpr->Type) < TC_STRICT_COMPATIBLE) {
if (TypeCmp (ltype, RExpr->Type).C < TC_STRICT_COMPATIBLE) {
TypeCompatibilityDiagnostic (ltype, RExpr->Type, 1,
"Incompatible types in assignment to '%s' from '%s'");
}

View File

@ -108,6 +108,7 @@ enum {
T_QUAL_CONST = 0x001000,
T_QUAL_VOLATILE = 0x002000,
T_QUAL_RESTRICT = 0x004000,
T_QUAL_CVR = T_QUAL_CONST | T_QUAL_VOLATILE | T_QUAL_RESTRICT,
T_QUAL_NEAR = 0x008000,
T_QUAL_FAR = 0x010000,
T_QUAL_ADDRSIZE = T_QUAL_NEAR | T_QUAL_FAR,

View File

@ -1821,7 +1821,7 @@ static void Declarator (const DeclSpec* Spec, Declaration* D, declmode_t Mode)
NextToken ();
/* Allow const, restrict, and volatile qualifiers */
Qualifiers |= OptionalQualifiers (T_QUAL_CONST | T_QUAL_VOLATILE | T_QUAL_RESTRICT);
Qualifiers |= OptionalQualifiers (T_QUAL_CVR);
/* Parse the type that the pointer points to */
Declarator (Spec, D, Mode);

View File

@ -2447,15 +2447,11 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */
}
} else if (IsClassPtr (Expr->Type)) {
if (IsClassPtr (Expr2.Type)) {
/* Both pointers are allowed in comparison if they point to
** the same type, or if one of them is a void pointer.
*/
Type* left = Indirect (Expr->Type);
Type* right = Indirect (Expr2.Type);
if (TypeCmp (left, right) < TC_QUAL_DIFF && left->C != T_VOID && right->C != T_VOID) {
/* Incompatible pointers */
/* Pointers are allowed in comparison */
if (TypeCmp (Expr->Type, Expr2.Type).C < TC_STRICT_COMPATIBLE) {
/* Warn about distinct pointer types */
TypeCompatibilityDiagnostic (PtrConversion (Expr->Type), PtrConversion (Expr2.Type), 0,
"Incompatible pointer types comparing '%s' with '%s'");
"Distinct pointer types comparing '%s' with '%s'");
}
} else if (!ED_IsNullPtr (&Expr2)) {
if (IsClassInt (Expr2.Type)) {
@ -3268,17 +3264,25 @@ static void parsesub (ExprDesc* Expr)
if (IsClassPtr (lhst) && IsClassPtr (rhst)) {
/* Pointer diff */
if (TypeCmp (Indirect (lhst), Indirect (rhst)) < TC_QUAL_DIFF) {
Error ("Incompatible pointer types");
if (TypeCmp (lhst, rhst).C >= TC_STRICT_COMPATIBLE) {
/* We'll have to scale the result */
rscale = PSizeOf (lhst);
/* We cannot scale by 0-size or unknown-size */
if (rscale == 0) {
TypeCompatibilityDiagnostic (lhst, rhst,
1, "Invalid pointer types in subtraction: '%s' and '%s'");
/* Avoid further errors */
rscale = 1;
}
} else {
TypeCompatibilityDiagnostic (lhst, rhst,
1, "Incompatible pointer types in subtraction: '%s' and '%s'");
}
/* Operate on pointers, result type is an integer */
flags = CF_PTR;
Expr->Type = type_int;
/* We'll have to scale the result */
rscale = CheckedPSizeOf (lhst);
/* Check for a constant rhs expression */
if (ED_IsQuasiConst (&Expr2) && ED_CodeRangeIsEmpty (&Expr2)) {
/* The right hand side is constant. Check left hand side. */
@ -4069,13 +4073,17 @@ static void hieQuest (ExprDesc* Expr)
** Conversion rules for ?: expression are:
** - if both expressions are int expressions, default promotion
** rules for ints apply.
** - if both expressions are pointers of the same type, the
** result of the expression is of this type.
** - if both expressions have the same structure, union or void type,
** the result has the same type.
** - if both expressions are pointers to compatible types (possibly
** qualified differently), the result of the expression is an
** appropriately qualified version of the composite type.
** - if one of the expressions is a pointer and the other is a
** pointer to (possibly qualified) void, the resulting type is a
** pointer to appropriately qualified void.
** - if one of the expressions is a pointer and the other is
** a zero constant, the resulting type is that of the pointer
** type.
** - if both expressions are void expressions, the result is of
** type void.
** a null pointer constant, the resulting type is that of the
** pointer type.
** - all other cases are flagged by an error.
*/
if (IsClassInt (Expr2.Type) && IsClassInt (Expr3.Type)) {
@ -4105,12 +4113,28 @@ static void hieQuest (ExprDesc* Expr)
}
} else if (IsClassPtr (Expr2.Type) && IsClassPtr (Expr3.Type)) {
/* Must point to same type */
if (TypeCmp (Indirect (Expr2.Type), Indirect (Expr3.Type)) < TC_EQUAL) {
Error ("Incompatible pointer types");
/* If one of the two is 'void *', the result type is a pointer to
** appropriately qualified void.
*/
if (IsTypeVoid (Indirect (Expr2.Type))) {
ResultType = PointerTo (Indirect (Expr2.Type));
ResultType[1].C |= GetQualifier (Indirect (Expr3.Type));
} else if (IsTypeVoid (Indirect (Expr3.Type))) {
ResultType = PointerTo (Indirect (Expr3.Type));
ResultType[1].C |= GetQualifier (Indirect (Expr2.Type));
} else {
/* Must point to compatible types */
if (TypeCmp (Expr2.Type, Expr3.Type).C < TC_VOID_PTR) {
TypeCompatibilityDiagnostic (Expr2.Type, Expr3.Type,
1, "Incompatible pointer types in ternary: '%s' and '%s'");
/* Avoid further errors */
ResultType = PointerTo (type_void);
} else {
/* Result has the composite type */
ResultType = TypeDup (Expr2.Type);
TypeComposition (ResultType, Expr3.Type);
}
}
/* Result has the common type */
ResultType = Expr2.Type;
} else if (IsClassPtr (Expr2.Type) && Expr3IsNULL) {
/* Result type is pointer, no cast needed */
ResultType = Expr2.Type;
@ -4119,10 +4143,10 @@ static void hieQuest (ExprDesc* Expr)
ResultType = Expr3.Type;
} else if (IsTypeVoid (Expr2.Type) && IsTypeVoid (Expr3.Type)) {
/* Result type is void */
ResultType = Expr3.Type;
ResultType = type_void;
} else {
if (IsClassStruct (Expr2.Type) && IsClassStruct (Expr3.Type) &&
TypeCmp (Expr2.Type, Expr3.Type) == TC_IDENTICAL) {
TypeCmp (Expr2.Type, Expr3.Type).C == TC_IDENTICAL) {
/* Result type is struct/union */
ResultType = Expr2.Type;
} else {
@ -4148,7 +4172,7 @@ static void hieQuest (ExprDesc* Expr)
}
/* Setup the target expression */
Expr->Type = ResultType;
Expr->Type = ResultType;
}
}

View File

@ -59,6 +59,7 @@
#include "stackptr.h"
#include "symentry.h"
#include "typecmp.h"
#include "typeconv.h"
#include "symtab.h"
@ -549,6 +550,19 @@ SymEntry FindStructField (const Type* T, const char* Name)
static int IsDistinctRedef (const Type* lhst, const Type* rhst, typecmpcode_t Code, typecmpflag_t Flags)
/* Return if type compatibility result is "worse" than Code or if any bit of
** qualifier Flags is set.
*/
{
typecmp_t Result = TypeCmp (lhst, rhst);
if (Result.C < Code || (Result.F & TCF_MASK_QUAL & Flags) != 0) {
return 1;
}
return 0;
}
static int HandleSymRedefinition (SymEntry* Entry, const Type* T, unsigned Flags)
/* Check and handle redefinition of existing symbols.
** Complete array sizes and function descriptors as well.
@ -565,7 +579,7 @@ static int HandleSymRedefinition (SymEntry* Entry, const Type* T, unsigned Flags
/* Existing typedefs cannot be redeclared as anything different */
if (SCType == SC_TYPEDEF) {
if (TypeCmp (E_Type, T) < TC_IDENTICAL) {
if (IsDistinctRedef (E_Type, T, TC_IDENTICAL, TCF_MASK_QUAL)) {
Error ("Conflicting types for typedef '%s'", Entry->Name);
Entry = 0;
}
@ -591,7 +605,7 @@ static int HandleSymRedefinition (SymEntry* Entry, const Type* T, unsigned Flags
Entry = 0;
} else {
/* New type must be compatible with the composite prototype */
if (TypeCmp (Entry->Type, T) < TC_EQUAL) {
if (IsDistinctRedef (E_Type, T, TC_EQUAL, TCF_MASK_QUAL)) {
Error ("Conflicting function types for '%s'", Entry->Name);
Entry = 0;
} else {
@ -621,7 +635,7 @@ static int HandleSymRedefinition (SymEntry* Entry, const Type* T, unsigned Flags
** is incomplete, complete it.
*/
if ((Size != UNSPECIFIED && ESize != UNSPECIFIED && Size != ESize) ||
TypeCmp (T + 1, E_Type + 1) < TC_EQUAL) {
IsDistinctRedef (E_Type + 1, T + 1, TC_IDENTICAL, TCF_MASK_QUAL)) {
/* Conflicting element types */
Error ("Conflicting array types for '%s[]'", Entry->Name);
Entry = 0;
@ -639,7 +653,7 @@ static int HandleSymRedefinition (SymEntry* Entry, const Type* T, unsigned Flags
if (SCType != E_SCType) {
Error ("Redefinition of '%s' as different kind of symbol", Entry->Name);
Entry = 0;
} else if (TypeCmp (E_Type, T) < TC_EQUAL) {
} else if (IsDistinctRedef (E_Type, T, TC_EQUAL, TCF_MASK_QUAL)) {
Error ("Conflicting types for '%s'", Entry->Name);
Entry = 0;
} else if (E_SCType == SC_ENUMERATOR) {

View File

@ -36,7 +36,7 @@
#include <string.h>
/* cc65 */
#include "funcdesc.h"
#include "error.h"
#include "global.h"
#include "symtab.h"
#include "typecmp.h"
@ -49,17 +49,6 @@
static void SetResult (typecmp_t* Result, typecmp_t Val)
/* Set a new result value if it is less than the existing one */
{
if (Val < *Result) {
/* printf ("SetResult = %d\n", Val); */
*Result = Val;
}
}
static int ParamsHaveDefaultPromotions (const FuncDesc* F)
/* Check if any of the parameters of function F has a default promotion. In
** this case, the function is not compatible with an empty parameter name list
@ -129,7 +118,7 @@ static int EqualFuncParams (const FuncDesc* F1, const FuncDesc* F2)
}
/* Compare this field */
if (TypeCmp (Type1, Type2) < TC_EQUAL) {
if (TypeCmp (Type1, Type2).C < TC_EQUAL) {
/* Field types not equal */
return 0;
}
@ -148,48 +137,169 @@ static int EqualFuncParams (const FuncDesc* F1, const FuncDesc* F2)
static void SetResult (typecmp_t* Result, typecmpcode_t Val)
/* Set a new result value if it is less than the existing one */
{
if (Val < Result->C) {
if (Result->Indirections > 0) {
if (Val >= TC_STRICT_COMPATIBLE) {
Result->C = Val;
} else if (Result->Indirections == 1) {
/* C Standard allows implicit conversion as long as one side is
** a pointer to void type, but doesn't care which side is.
*/
if ((Result->F & TCF_MASK_VOID_PTR) != 0) {
Result->C = TC_VOID_PTR;
} else {
Result->C = TC_PTR_INCOMPATIBLE;
}
} else {
Result->C = TC_PTR_INCOMPATIBLE;
}
} else {
Result->C = Val;
}
/* printf ("SetResult = %d\n", Val); */
}
}
static typecmp_t* CmpQuals (const Type* lhst, const Type* rhst, typecmp_t* Result)
/* Copare the types regarding thier qualifiers. Return the Result */
{
TypeCode LeftQual, RightQual;
/* Get the left and right qualifiers */
LeftQual = GetQualifier (lhst);
RightQual = GetQualifier (rhst);
/* If type is function without a calling convention set explicitly,
** then assume the default one.
*/
if (IsTypeFunc (lhst)) {
if ((LeftQual & T_QUAL_CCONV) == T_QUAL_NONE) {
LeftQual |= (AutoCDecl || IsVariadicFunc (lhst)) ? T_QUAL_CDECL : T_QUAL_FASTCALL;
}
}
if (IsTypeFunc (rhst)) {
if ((RightQual & T_QUAL_CCONV) == T_QUAL_NONE) {
RightQual |= (AutoCDecl || IsVariadicFunc (rhst)) ? T_QUAL_CDECL : T_QUAL_FASTCALL;
}
}
/* Default address size qualifiers */
if ((LeftQual & T_QUAL_ADDRSIZE) == T_QUAL_NONE) {
LeftQual |= (IsTypeFunc (lhst) ? CodeAddrSizeQualifier () : DataAddrSizeQualifier ());
}
if ((RightQual & T_QUAL_ADDRSIZE) == T_QUAL_NONE) {
RightQual |= (IsTypeFunc (rhst) ? CodeAddrSizeQualifier () : DataAddrSizeQualifier ());
}
/* Just return if nothing to do */
if (LeftQual == RightQual) {
return Result;
}
/* On the first indirection level, different qualifiers mean that the types
** are still compatible. On the second level, that is a (maybe minor) error.
** We create a special return-code if a qualifier is dropped from a pointer.
** But, different calling conventions are incompatible. Starting from the
** next level, the types are incompatible if the qualifiers differ.
*/
/* (Debugging statement) */
/* printf ("Ind = %d %06X != %06X\n", Result->Indirections, LeftQual, RightQual); */
switch (Result->Indirections) {
case 0:
/* Compare C qualifiers */
if ((LeftQual & T_QUAL_CVR) > (RightQual & T_QUAL_CVR)) {
Result->F |= TCF_QUAL_IMPLICIT;
} else if ((LeftQual & T_QUAL_CVR) != (RightQual & T_QUAL_CVR)) {
Result->F |= TCF_QUAL_DIFF;
}
/* Compare address size qualifiers */
if ((LeftQual & T_QUAL_ADDRSIZE) != (RightQual & T_QUAL_ADDRSIZE)) {
Result->F |= TCF_ADDRSIZE_QUAL_DIFF;
}
/* Compare function calling conventions */
if ((LeftQual & T_QUAL_CCONV) != (RightQual & T_QUAL_CCONV)) {
SetResult (Result, TC_INCOMPATIBLE);
}
break;
case 1:
/* A non-const value on the right is compatible to a
** const one to the left, same for volatile.
*/
if ((LeftQual & T_QUAL_CVR) > (RightQual & T_QUAL_CVR)) {
Result->F |= TCF_PTR_QUAL_IMPLICIT;
} else if ((LeftQual & T_QUAL_CVR) != (RightQual & T_QUAL_CVR)) {
Result->F |= TCF_PTR_QUAL_DIFF;
}
/* Compare address size qualifiers */
if ((LeftQual & T_QUAL_ADDRSIZE) != (RightQual & T_QUAL_ADDRSIZE)) {
Result->F |= TCF_ADDRSIZE_QUAL_DIFF;
}
/* Compare function calling conventions */
if ((!IsTypeFunc (lhst) && !IsTypeFunc (rhst)) ||
(LeftQual & T_QUAL_CCONV) == (RightQual & T_QUAL_CCONV)) {
break;
}
/* else fall through */
default:
/* Pointer types mismatch */
SetResult (Result, TC_INCOMPATIBLE);
break;
}
return Result;
}
static void DoCompare (const Type* lhs, const Type* rhs, typecmp_t* Result)
/* Recursively compare two types. */
{
unsigned Indirections;
unsigned ElementCount;
SymEntry* Sym1;
SymEntry* Sym2;
FuncDesc* F1;
FuncDesc* F2;
TypeCode LeftType, RightType;
long LeftCount, RightCount;
/* Initialize stuff */
Indirections = 0;
ElementCount = 0;
/* Compare two types. Determine, where they differ */
while (lhs->C != T_END) {
TypeCode LeftType, RightType;
TypeCode LeftSign, RightSign;
TypeCode LeftQual, RightQual;
long LeftCount, RightCount;
/* Check if the end of the type string is reached */
if (rhs->C == T_END) {
/* End of comparison reached */
break;
}
/* Compare qualifiers */
if (CmpQuals (lhs, rhs, Result)->C == TC_INCOMPATIBLE) {
return;
}
/* Get the left and right types, signs and qualifiers */
/* Get the left and right types */
LeftType = (GetUnderlyingTypeCode (lhs) & T_MASK_TYPE);
RightType = (GetUnderlyingTypeCode (rhs) & T_MASK_TYPE);
LeftSign = GetSignedness (lhs);
RightSign = GetSignedness (rhs);
LeftQual = GetQualifier (lhs);
RightQual = GetQualifier (rhs);
/* If the left type is a pointer and the right is an array, both
** are compatible.
/* If one side is a pointer and the other side is an array, both are
** compatible.
*/
if (LeftType == T_TYPE_PTR && RightType == T_TYPE_ARRAY) {
RightType = T_TYPE_PTR;
SetResult (Result, TC_PTR_DECAY);
}
if (LeftType == T_TYPE_ARRAY && RightType == T_TYPE_PTR) {
LeftType = T_TYPE_PTR;
SetResult (Result, TC_STRICT_COMPATIBLE);
}
@ -236,74 +346,30 @@ static void DoCompare (const Type* lhs, const Type* rhs, typecmp_t* Result)
/* 'char' is neither 'signed char' nor 'unsigned char' */
if ((IsISOChar (lhs) && !IsISOChar (rhs)) ||
(!IsISOChar (lhs) && IsISOChar (rhs))) {
SetResult (Result, TC_COMPATIBLE);
SetResult (Result, TC_SIGN_DIFF);
}
/* On indirection level zero, a qualifier or sign difference is
** accepted. The types are no longer equal, but compatible.
/* On indirection level zero, a sign difference is accepted.
** The types are no longer equal, but compatible.
*/
if (LeftSign != RightSign) {
if (ElementCount == 0) {
SetResult (Result, TC_SIGN_DIFF);
} else {
SetResult (Result, TC_INCOMPATIBLE);
return;
}
}
if (LeftType == T_TYPE_FUNC) {
/* If a calling convention wasn't set explicitly,
** then assume the default one.
*/
if ((LeftQual & T_QUAL_CCONV) == T_QUAL_NONE) {
LeftQual |= (AutoCDecl || IsVariadicFunc (lhs)) ? T_QUAL_CDECL : T_QUAL_FASTCALL;
}
if ((RightQual & T_QUAL_CCONV) == T_QUAL_NONE) {
RightQual |= (AutoCDecl || IsVariadicFunc (rhs)) ? T_QUAL_CDECL : T_QUAL_FASTCALL;
}
}
if (LeftQual != RightQual) {
/* On the first indirection level, different qualifiers mean
** that the types still are compatible. On the second level,
** that is a (maybe minor) error. We create a special return-code
** if a qualifier is dropped from a pointer. But, different calling
** conventions are incompatible. Starting from the next level,
** the types are incompatible if the qualifiers differ.
*/
/* (Debugging statement) */
/* printf ("Ind = %d %06X != %06X\n", Indirections, LeftQual, RightQual); */
switch (Indirections) {
case 0:
SetResult (Result, TC_STRICT_COMPATIBLE);
break;
case 1:
/* A non-const value on the right is compatible to a
** const one to the left, same for volatile.
*/
if ((LeftQual & T_QUAL_CONST) < (RightQual & T_QUAL_CONST) ||
(LeftQual & T_QUAL_VOLATILE) < (RightQual & T_QUAL_VOLATILE)) {
SetResult (Result, TC_QUAL_DIFF);
} else {
SetResult (Result, TC_STRICT_COMPATIBLE);
}
if (LeftType != T_TYPE_FUNC || (LeftQual & T_QUAL_CCONV) == (RightQual & T_QUAL_CCONV)) {
break;
}
/* else fall through */
default:
SetResult (Result, TC_INCOMPATIBLE);
return;
}
if (GetSignedness (lhs) != GetSignedness (rhs)) {
SetResult (Result, TC_SIGN_DIFF);
}
/* Check for special type elements */
switch (LeftType) {
case T_TYPE_PTR:
++Indirections;
++Result->Indirections;
if (Result->Indirections == 1) {
if ((GetUnderlyingTypeCode (lhs + 1) & T_MASK_TYPE) == T_TYPE_VOID) {
Result->F |= TCF_VOID_PTR_ON_LEFT;
}
if ((GetUnderlyingTypeCode (rhs + 1) & T_MASK_TYPE) == T_TYPE_VOID) {
Result->F |= TCF_VOID_PTR_ON_RIGHT;
}
} else {
Result->F &= ~TCF_MASK_VOID_PTR;
}
break;
case T_TYPE_FUNC:
@ -364,7 +430,13 @@ static void DoCompare (const Type* lhs, const Type* rhs, typecmp_t* Result)
SetResult (Result, TC_INCOMPATIBLE);
return;
}
SetResult (Result, TC_EQUAL);
/* We take into account which side is more specified */
if (LeftCount == UNSPECIFIED) {
SetResult (Result, TC_UNSPECIFY);
} else {
SetResult (Result, TC_EQUAL);
}
}
break;
@ -397,11 +469,10 @@ static void DoCompare (const Type* lhs, const Type* rhs, typecmp_t* Result)
/* Next type string element */
++lhs;
++rhs;
++ElementCount;
}
/* Check if end of rhs reached */
if (rhs->C == T_END) {
/* 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);
@ -414,7 +485,7 @@ typecmp_t TypeCmp (const Type* lhs, const Type* rhs)
/* Compare two types and return the result */
{
/* Assume the types are identical */
typecmp_t Result = TC_IDENTICAL;
typecmp_t Result = TYPECMP_INITIALIZER;
#if 0
printf ("Left : "); PrintRawType (stdout, lhs);
@ -432,134 +503,18 @@ typecmp_t TypeCmp (const Type* lhs, const Type* rhs)
static Type* DoComposite (Type* lhs, const Type* rhs);
static void CompositeFuncParams (const FuncDesc* F1, const FuncDesc* F2)
/* Composite two function symbol tables regarding function parameters */
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 */
{
/* Get the symbol tables */
const SymTable* Tab1 = F1->SymTab;
const SymTable* Tab2 = F2->SymTab;
/* Composite the parameter lists */
const SymEntry* Sym1 = Tab1->SymHead;
const SymEntry* Sym2 = Tab2->SymHead;
/* Composite the fields */
while (Sym1 && (Sym1->Flags & SC_PARAM) && Sym2 && (Sym2->Flags & SC_PARAM)) {
/* Get the symbol types */
Type* Type1 = Sym1->Type;
Type* Type2 = Sym2->Type;
/* If either of both functions is old style, apply the default
** promotions to the parameter type.
*/
if (F1->Flags & FD_OLDSTYLE) {
if (IsClassInt (Type1)) {
Type1 = IntPromotion (Type1);
}
}
if (F2->Flags & FD_OLDSTYLE) {
if (IsClassInt (Type2)) {
Type2 = IntPromotion (Type2);
}
}
/* Composite this field */
DoComposite (Type1, Type2);
/* Get the pointers to the next fields */
Sym1 = Sym1->NextSym;
Sym2 = Sym2->NextSym;
StrBuf NewTypeName = STATIC_STRBUF_INITIALIZER;
StrBuf OldTypeName = STATIC_STRBUF_INITIALIZER;
GetFullTypeNameBuf (&NewTypeName, NewType);
GetFullTypeNameBuf (&OldTypeName, OldType);
if (IsError) {
Error (Msg, SB_GetConstBuf (&NewTypeName), SB_GetConstBuf (&OldTypeName));
} else {
Warning (Msg, SB_GetConstBuf (&NewTypeName), SB_GetConstBuf (&OldTypeName));
}
}
static Type* DoComposite (Type* lhs, const Type* rhs)
/* Recursively composite two types into lhs */
{
FuncDesc* F1;
FuncDesc* F2;
long LeftCount, RightCount;
/* Composite two types */
while (lhs->C != T_END) {
/* Check if the end of the type string is reached */
if (rhs->C == T_END) {
return lhs;
}
/* Check for sanity */
CHECK (GetUnderlyingTypeCode (lhs) == GetUnderlyingTypeCode (rhs));
/* Check for special type elements */
if (IsTypeFunc (lhs)) {
/* Composite the function descriptors */
F1 = GetFuncDesc (lhs);
F2 = GetFuncDesc (rhs);
/* If one of both functions has an empty parameter list (which
** does also mean, it is not a function definition, because the
** flag is reset in this case), it is replaced by the other
** definition, provided that the other has no default
** promotions in the parameter list. If none of both parameter
** lists is empty, we have to composite the parameter lists and
** other attributes.
*/
if ((F1->Flags & FD_EMPTY) == FD_EMPTY) {
if ((F2->Flags & FD_EMPTY) == 0) {
/* Copy the parameters and flags */
TypeCopy (lhs, rhs);
F1->Flags = F2->Flags;
}
} else if ((F2->Flags & FD_EMPTY) == 0) {
/* Composite the parameter lists */
CompositeFuncParams (F1, F2);
}
} else if (IsTypeArray (lhs)) {
/* Check member count */
LeftCount = GetElementCount (lhs);
RightCount = GetElementCount (rhs);
/* Set composite type if it is requested */
if (LeftCount != UNSPECIFIED) {
SetElementCount (lhs, LeftCount);
} else if (RightCount != UNSPECIFIED) {
SetElementCount (lhs, RightCount);
}
}
/* Next type string element */
++lhs;
++rhs;
}
return lhs;
}
FuncDesc* RefineFuncDesc (Type* OldType, const Type* NewType)
/* Refine the existing function descriptor with a new one */
{
FuncDesc* Old = GetFuncDesc (OldType);
FuncDesc* New = GetFuncDesc (NewType);
CHECK (Old != 0 && New != 0);
if ((New->Flags & FD_EMPTY) == 0) {
if ((Old->Flags & FD_EMPTY) == 0) {
DoComposite (OldType, NewType);
} else {
TypeCopy (OldType, NewType);
Old->Flags &= ~FD_EMPTY;
}
}
return Old;
SB_Done (&OldTypeName);
SB_Done (&NewTypeName);
}

View File

@ -48,18 +48,43 @@
/* Degree of type compatibility. Must be in ascending order */
/* Degree of type compatibility affected. Must be in ascending order */
typedef enum {
TC_INCOMPATIBLE, /* Distinct types */
TC_SIGN_DIFF, /* Signedness differs */
TC_COMPATIBLE = TC_SIGN_DIFF, /* Compatible types */
TC_QUAL_DIFF, /* Types differ in qualifier of pointer */
TC_STRICT_COMPATIBLE, /* Strict compatibility */
TC_EQUAL, /* Types are equivalent */
TC_IDENTICAL /* Types are identical */
TC_INCOMPATIBLE, /* Distinct types */
TC_SIGN_DIFF, /* Signedness differs */
TC_PTR_INCOMPATIBLE, /* Distinct pointer types */
TC_VOID_PTR, /* Non-void and void pointers */
TC_STRICT_COMPATIBLE, /* Strict compatibility according to the C Standard */
TC_PTR_DECAY, /* rhs is an array and lhs is a pointer */
TC_EQUAL, /* Array types with unspecified lengths */
TC_UNSPECIFY, /* lhs has unspecified length while rhs has specified length */
TC_IDENTICAL /* Types are identical */
} typecmpcode_t;
/* Degree of type compatibility affected by qualifiers as well as some extra info */
typedef enum {
TCF_NONE = 0x00, /* None of the below */
TCF_VOID_PTR_ON_LEFT = 0x01, /* lhs is a void pointer */
TCF_VOID_PTR_ON_RIGHT = 0x02, /* rhs is a void pointer */
TCF_MASK_VOID_PTR = TCF_VOID_PTR_ON_LEFT | TCF_VOID_PTR_ON_RIGHT,
TCF_QUAL_DIFF = 0x04, /* CVR qualifiers differ in a way that doesn't matter */
TCF_QUAL_IMPLICIT = 0x08, /* CVR qualifiers of lhs are stricter than those of rhs */
TCF_PTR_QUAL_DIFF = 0x10, /* CVR qualifiers of pointers differ */
TCF_PTR_QUAL_IMPLICIT = 0x20, /* CVR qualifiers of pointers are stricter on lhs than those on rhs */
TCF_MASK_C_QUAL_DIFF = 0x3C, /* All C Standard qualifiers */
TCF_ADDRSIZE_QUAL_DIFF = 0x40, /* Address size qualifiers differ */
TCF_CCONV_QUAL_DIFF = 0x80, /* Function calling conventions differ. Unused now */
TCF_INCOMPATIBLE_QUAL = TCF_ADDRSIZE_QUAL_DIFF | TCF_CCONV_QUAL_DIFF,
TCF_MASK_QUAL = TCF_MASK_C_QUAL_DIFF | TCF_INCOMPATIBLE_QUAL,
} typecmpflag_t;
typedef struct {
typecmpcode_t C;
typecmpflag_t F;
int Indirections;
} typecmp_t;
#define TYPECMP_INITIALIZER { TC_IDENTICAL, TCF_NONE, 0 }
/*****************************************************************************/
/* Code */
@ -70,8 +95,9 @@ typedef enum {
typecmp_t TypeCmp (const Type* lhs, const Type* rhs);
/* Compare two types and return the result */
FuncDesc* RefineFuncDesc (Type* OldType, const Type* NewType);
/* Refine the existing function descriptor with a new one */
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 */
/* End of typecmp.h */

View File

@ -43,7 +43,6 @@
#include "error.h"
#include "expr.h"
#include "loadexpr.h"
#include "scanner.h"
#include "typecmp.h"
#include "typeconv.h"
@ -55,24 +54,6 @@
void TypeCompatibilityDiagnostic (const Type* NewType, const Type* OldType, int IsError, const char* Msg)
/* Print error or warning message about type conversion with proper type names */
{
StrBuf NewTypeName = STATIC_STRBUF_INITIALIZER;
StrBuf OldTypeName = STATIC_STRBUF_INITIALIZER;
GetFullTypeNameBuf (&NewTypeName, NewType);
GetFullTypeNameBuf (&OldTypeName, OldType);
if (IsError) {
Error (Msg, SB_GetConstBuf (&NewTypeName), SB_GetConstBuf (&OldTypeName));
} else {
Warning (Msg, SB_GetConstBuf (&NewTypeName), SB_GetConstBuf (&OldTypeName));
}
SB_Done (&OldTypeName);
SB_Done (&NewTypeName);
}
static void DoConversion (ExprDesc* Expr, const Type* NewType)
/* Emit code to convert the given expression to a new type. */
{
@ -208,9 +189,10 @@ void TypeConversion (ExprDesc* Expr, const Type* NewType)
PrintRawType (stdout, NewType);
#endif
/* First, do some type checking */
int HasWarning = 0;
int HasError = 0;
const char* Msg = 0;
typecmp_t Result = TYPECMP_INITIALIZER;
int HasWarning = 0;
int HasError = 0;
const char* Msg = 0;
const Type* OldType = Expr->Type;
@ -219,20 +201,13 @@ void TypeConversion (ExprDesc* Expr, const Type* NewType)
HasError = 1;
}
/* If both types are strictly compatible, no conversion is needed */
if (TypeCmp (NewType, OldType) >= TC_STRICT_COMPATIBLE) {
/* We're already done */
return;
}
/* If Expr is an array or a function, convert it to a pointer */
Expr->Type = PtrConversion (Expr->Type);
/* If we have changed the type, check again for strictly compatibility */
if (Expr->Type != OldType &&
TypeCmp (NewType, Expr->Type) >= TC_STRICT_COMPATIBLE) {
/* We're already done */
return;
/* If both types are the same, no conversion is needed */
Result = TypeCmp (NewType, OldType);
if (Result.C < TC_IDENTICAL && (IsTypeArray (OldType) || IsTypeFunc (OldType))) {
/* If Expr is an array or a function, convert it to a pointer */
Expr->Type = PtrConversion (Expr->Type);
/* Recompare */
Result = TypeCmp (NewType, Expr->Type);
}
/* Check for conversion problems */
@ -253,37 +228,27 @@ void TypeConversion (ExprDesc* Expr, const Type* NewType)
/* Handle conversions to pointer type */
if (IsClassPtr (Expr->Type)) {
/* Pointer to pointer assignment is valid, if:
/* Implicit pointer-to-pointer conversion is valid, if:
** - both point to the same types, or
** - the rhs pointer is a void pointer, or
** - the lhs pointer is a void pointer.
*/
if (!IsTypeVoid (IndirectConst (NewType)) && !IsTypeVoid (Indirect (Expr->Type))) {
/* Compare the types */
switch (TypeCmp (NewType, Expr->Type)) {
case TC_INCOMPATIBLE:
HasWarning = 1;
Msg = "Incompatible pointer assignment to '%s' from '%s'";
/* Use the pointer type in the diagnostic */
OldType = Expr->Type;
break;
case TC_QUAL_DIFF:
HasWarning = 1;
Msg = "Pointer assignment to '%s' from '%s' discards qualifiers";
/* Use the pointer type in the diagnostic */
OldType = Expr->Type;
break;
default:
/* Ok */
break;
}
if (Result.C <= TC_PTR_INCOMPATIBLE ||
(Result.F & TCF_INCOMPATIBLE_QUAL) != 0)
{
HasWarning = 1;
Msg = "Incompatible pointer conversion to '%s' from '%s'";
/* Use the pointer type in the diagnostic */
OldType = Expr->Type;
} else if ((Result.F & TCF_PTR_QUAL_DIFF) != 0) {
HasWarning = 1;
Msg = "Pointer conversion to '%s' from '%s' discards qualifiers";
/* Use the pointer type in the diagnostic */
OldType = Expr->Type;
}
} else if (IsClassInt (Expr->Type)) {
/* Int to pointer assignment is valid only for constant zero */
/* Int to pointer conversion is valid only for constant zero */
if (!ED_IsConstAbsInt (Expr) || Expr->IVal != 0) {
Warning ("Converting integer to pointer without a cast");
}
@ -291,11 +256,12 @@ void TypeConversion (ExprDesc* Expr, const Type* NewType)
HasError = 1;
}
} else {
} else if (Result.C < TC_IDENTICAL) {
/* Invalid automatic conversion */
HasError = 1;
}
/* Set default diagnostic message */
if (Msg == 0) {
Msg = "Converting to '%s' from '%s'";
}
@ -350,13 +316,13 @@ void TypeCast (ExprDesc* Expr)
/* Convert functions and arrays to "pointer to" object */
Expr->Type = PtrConversion (Expr->Type);
if (TypeCmp (NewType, Expr->Type) >= TC_QUAL_DIFF) {
/* If the new type only differs in qualifiers, just use it to
** replace the old one.
if (TypeCmp (NewType, Expr->Type).C >= TC_PTR_INCOMPATIBLE) {
/* If the new type has the same underlying presentation, just
** use it to replace the old one.
*/
ReplaceType (Expr, NewType);
} else if (IsCastType (Expr->Type)) {
/* Convert the value. The rsult has always the new type */
/* Convert the value. The result has always the new type */
DoConversion (Expr, NewType);
} else {
TypeCompatibilityDiagnostic (NewType, Expr->Type, 1,
@ -379,3 +345,142 @@ void TypeCast (ExprDesc* Expr)
/* The result is always an rvalue */
ED_MarkExprAsRVal (Expr);
}
static void CompositeFuncParamList (const FuncDesc* F1, const FuncDesc* F2)
/* Composite two function symbol tables regarding function parameters */
{
/* Get the symbol tables */
const SymTable* Tab1 = F1->SymTab;
const SymTable* Tab2 = F2->SymTab;
/* Composite the parameter lists */
const SymEntry* Sym1 = Tab1->SymHead;
const SymEntry* Sym2 = Tab2->SymHead;
/* Composite the fields */
while (Sym1 && (Sym1->Flags & SC_PARAM) && Sym2 && (Sym2->Flags & SC_PARAM)) {
/* Get the symbol types */
Type* Type1 = Sym1->Type;
Type* Type2 = Sym2->Type;
/* If either of both functions is old style, apply the default
** promotions to the parameter type.
*/
if (F1->Flags & FD_OLDSTYLE) {
if (IsClassInt (Type1)) {
Type1 = IntPromotion (Type1);
}
}
if (F2->Flags & FD_OLDSTYLE) {
if (IsClassInt (Type2)) {
Type2 = IntPromotion (Type2);
}
}
/* Compose this field */
TypeComposition (Type1, Type2);
/* Get the pointers to the next fields */
Sym1 = Sym1->NextSym;
Sym2 = Sym2->NextSym;
}
}
void TypeComposition (Type* lhs, const Type* rhs)
/* Recursively compose two types into lhs. The two types must have compatible
** type or this fails with a critical check.
*/
{
FuncDesc* F1;
FuncDesc* F2;
long LeftCount, RightCount;
/* Composite two types */
while (lhs->C != T_END) {
/* Check if the end of the type string is reached */
if (rhs->C == T_END) {
break;
}
/* Check for sanity */
CHECK (GetUnderlyingTypeCode (lhs) == GetUnderlyingTypeCode (rhs));
/* Check for special type elements */
if (IsTypeFunc (lhs)) {
/* Composite the function descriptors */
F1 = GetFuncDesc (lhs);
F2 = GetFuncDesc (rhs);
/* If one of both functions has an empty parameter list (which
** does also mean, it is not a function definition, because the
** flag is reset in this case), it is replaced by the other
** definition, provided that the other has no default
** promotions in the parameter list. If none of both parameter
** lists is empty, we have to composite the parameter lists and
** other attributes.
*/
if ((F1->Flags & FD_EMPTY) == FD_EMPTY) {
if ((F2->Flags & FD_EMPTY) == 0) {
/* Copy the parameters and flags */
TypeCopy (lhs, rhs);
F1->Flags = F2->Flags;
}
} else if ((F2->Flags & FD_EMPTY) == 0) {
/* Composite the parameter lists */
CompositeFuncParamList (F1, F2);
}
} else if (IsTypeArray (lhs)) {
/* Check member count */
LeftCount = GetElementCount (lhs);
RightCount = GetElementCount (rhs);
/* Set composite type if it is requested */
if (LeftCount != UNSPECIFIED) {
SetElementCount (lhs, LeftCount);
} else if (RightCount != UNSPECIFIED) {
SetElementCount (lhs, RightCount);
}
} else {
/* Combine the qualifiers */
if (IsClassPtr (lhs)) {
++lhs;
++rhs;
lhs->C |= GetQualifier (rhs);
}
}
/* Next type string element */
++lhs;
++rhs;
}
return;
}
FuncDesc* RefineFuncDesc (Type* OldType, const Type* NewType)
/* Refine the existing function descriptor with a new one */
{
FuncDesc* Old = GetFuncDesc (OldType);
FuncDesc* New = GetFuncDesc (NewType);
CHECK (Old != 0 && New != 0);
if ((New->Flags & FD_EMPTY) == 0) {
if ((Old->Flags & FD_EMPTY) == 0) {
TypeComposition (OldType, NewType);
} else {
TypeCopy (OldType, NewType);
Old->Flags &= ~FD_EMPTY;
}
}
return Old;
}

View File

@ -49,9 +49,6 @@
void TypeCompatibilityDiagnostic (const Type* NewType, const Type* OldType, int IsError, const char* Msg);
/* Print error or warning message about type conversion with proper type names */
void TypeConversion (ExprDesc* Expr, const Type* NewType);
/* Do an automatic conversion of the given expression to the new type. Output
** warnings or errors where this automatic conversion is suspicious or
@ -61,6 +58,14 @@ void TypeConversion (ExprDesc* Expr, const Type* NewType);
void TypeCast (ExprDesc* Expr);
/* Handle an explicit cast. */
void TypeComposition (Type* lhs, const Type* rhs);
/* Recursively compose two types into lhs. The two types must have compatible
** type or this fails with a critical check.
*/
FuncDesc* RefineFuncDesc (Type* OldType, const Type* NewType);
/* Refine the existing function descriptor with a new one */
/* End of typeconv.h */