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:
@@ -78,7 +78,7 @@ static int CopyStruct (ExprDesc* LExpr, ExprDesc* RExpr)
|
|||||||
hie1 (RExpr);
|
hie1 (RExpr);
|
||||||
|
|
||||||
/* Check for equality of the structs/unions */
|
/* 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,
|
TypeCompatibilityDiagnostic (ltype, RExpr->Type, 1,
|
||||||
"Incompatible types in assignment to '%s' from '%s'");
|
"Incompatible types in assignment to '%s' from '%s'");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,6 +108,7 @@ enum {
|
|||||||
T_QUAL_CONST = 0x001000,
|
T_QUAL_CONST = 0x001000,
|
||||||
T_QUAL_VOLATILE = 0x002000,
|
T_QUAL_VOLATILE = 0x002000,
|
||||||
T_QUAL_RESTRICT = 0x004000,
|
T_QUAL_RESTRICT = 0x004000,
|
||||||
|
T_QUAL_CVR = T_QUAL_CONST | T_QUAL_VOLATILE | T_QUAL_RESTRICT,
|
||||||
T_QUAL_NEAR = 0x008000,
|
T_QUAL_NEAR = 0x008000,
|
||||||
T_QUAL_FAR = 0x010000,
|
T_QUAL_FAR = 0x010000,
|
||||||
T_QUAL_ADDRSIZE = T_QUAL_NEAR | T_QUAL_FAR,
|
T_QUAL_ADDRSIZE = T_QUAL_NEAR | T_QUAL_FAR,
|
||||||
|
|||||||
@@ -1821,7 +1821,7 @@ static void Declarator (const DeclSpec* Spec, Declaration* D, declmode_t Mode)
|
|||||||
NextToken ();
|
NextToken ();
|
||||||
|
|
||||||
/* Allow const, restrict, and volatile qualifiers */
|
/* 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 */
|
/* Parse the type that the pointer points to */
|
||||||
Declarator (Spec, D, Mode);
|
Declarator (Spec, D, Mode);
|
||||||
|
|||||||
@@ -2447,15 +2447,11 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */
|
|||||||
}
|
}
|
||||||
} else if (IsClassPtr (Expr->Type)) {
|
} else if (IsClassPtr (Expr->Type)) {
|
||||||
if (IsClassPtr (Expr2.Type)) {
|
if (IsClassPtr (Expr2.Type)) {
|
||||||
/* Both pointers are allowed in comparison if they point to
|
/* Pointers are allowed in comparison */
|
||||||
** the same type, or if one of them is a void pointer.
|
if (TypeCmp (Expr->Type, Expr2.Type).C < TC_STRICT_COMPATIBLE) {
|
||||||
*/
|
/* Warn about distinct pointer types */
|
||||||
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 */
|
|
||||||
TypeCompatibilityDiagnostic (PtrConversion (Expr->Type), PtrConversion (Expr2.Type), 0,
|
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)) {
|
} else if (!ED_IsNullPtr (&Expr2)) {
|
||||||
if (IsClassInt (Expr2.Type)) {
|
if (IsClassInt (Expr2.Type)) {
|
||||||
@@ -3268,17 +3264,25 @@ static void parsesub (ExprDesc* Expr)
|
|||||||
if (IsClassPtr (lhst) && IsClassPtr (rhst)) {
|
if (IsClassPtr (lhst) && IsClassPtr (rhst)) {
|
||||||
|
|
||||||
/* Pointer diff */
|
/* Pointer diff */
|
||||||
if (TypeCmp (Indirect (lhst), Indirect (rhst)) < TC_QUAL_DIFF) {
|
if (TypeCmp (lhst, rhst).C >= TC_STRICT_COMPATIBLE) {
|
||||||
Error ("Incompatible pointer types");
|
/* 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 */
|
/* Operate on pointers, result type is an integer */
|
||||||
flags = CF_PTR;
|
flags = CF_PTR;
|
||||||
Expr->Type = type_int;
|
Expr->Type = type_int;
|
||||||
|
|
||||||
/* We'll have to scale the result */
|
|
||||||
rscale = CheckedPSizeOf (lhst);
|
|
||||||
|
|
||||||
/* Check for a constant rhs expression */
|
/* Check for a constant rhs expression */
|
||||||
if (ED_IsQuasiConst (&Expr2) && ED_CodeRangeIsEmpty (&Expr2)) {
|
if (ED_IsQuasiConst (&Expr2) && ED_CodeRangeIsEmpty (&Expr2)) {
|
||||||
/* The right hand side is constant. Check left hand side. */
|
/* The right hand side is constant. Check left hand side. */
|
||||||
@@ -4069,13 +4073,17 @@ static void hieQuest (ExprDesc* Expr)
|
|||||||
** Conversion rules for ?: expression are:
|
** Conversion rules for ?: expression are:
|
||||||
** - if both expressions are int expressions, default promotion
|
** - if both expressions are int expressions, default promotion
|
||||||
** rules for ints apply.
|
** rules for ints apply.
|
||||||
** - if both expressions are pointers of the same type, the
|
** - if both expressions have the same structure, union or void type,
|
||||||
** result of the expression is of this 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
|
** - if one of the expressions is a pointer and the other is
|
||||||
** a zero constant, the resulting type is that of the pointer
|
** a null pointer constant, the resulting type is that of the
|
||||||
** type.
|
** pointer type.
|
||||||
** - if both expressions are void expressions, the result is of
|
|
||||||
** type void.
|
|
||||||
** - all other cases are flagged by an error.
|
** - all other cases are flagged by an error.
|
||||||
*/
|
*/
|
||||||
if (IsClassInt (Expr2.Type) && IsClassInt (Expr3.Type)) {
|
if (IsClassInt (Expr2.Type) && IsClassInt (Expr3.Type)) {
|
||||||
@@ -4105,12 +4113,28 @@ static void hieQuest (ExprDesc* Expr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else if (IsClassPtr (Expr2.Type) && IsClassPtr (Expr3.Type)) {
|
} else if (IsClassPtr (Expr2.Type) && IsClassPtr (Expr3.Type)) {
|
||||||
/* Must point to same type */
|
/* If one of the two is 'void *', the result type is a pointer to
|
||||||
if (TypeCmp (Indirect (Expr2.Type), Indirect (Expr3.Type)) < TC_EQUAL) {
|
** appropriately qualified void.
|
||||||
Error ("Incompatible pointer types");
|
*/
|
||||||
|
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) {
|
} else if (IsClassPtr (Expr2.Type) && Expr3IsNULL) {
|
||||||
/* Result type is pointer, no cast needed */
|
/* Result type is pointer, no cast needed */
|
||||||
ResultType = Expr2.Type;
|
ResultType = Expr2.Type;
|
||||||
@@ -4119,10 +4143,10 @@ static void hieQuest (ExprDesc* Expr)
|
|||||||
ResultType = Expr3.Type;
|
ResultType = Expr3.Type;
|
||||||
} else if (IsTypeVoid (Expr2.Type) && IsTypeVoid (Expr3.Type)) {
|
} else if (IsTypeVoid (Expr2.Type) && IsTypeVoid (Expr3.Type)) {
|
||||||
/* Result type is void */
|
/* Result type is void */
|
||||||
ResultType = Expr3.Type;
|
ResultType = type_void;
|
||||||
} else {
|
} else {
|
||||||
if (IsClassStruct (Expr2.Type) && IsClassStruct (Expr3.Type) &&
|
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 */
|
/* Result type is struct/union */
|
||||||
ResultType = Expr2.Type;
|
ResultType = Expr2.Type;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -59,6 +59,7 @@
|
|||||||
#include "stackptr.h"
|
#include "stackptr.h"
|
||||||
#include "symentry.h"
|
#include "symentry.h"
|
||||||
#include "typecmp.h"
|
#include "typecmp.h"
|
||||||
|
#include "typeconv.h"
|
||||||
#include "symtab.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)
|
static int HandleSymRedefinition (SymEntry* Entry, const Type* T, unsigned Flags)
|
||||||
/* Check and handle redefinition of existing symbols.
|
/* Check and handle redefinition of existing symbols.
|
||||||
** Complete array sizes and function descriptors as well.
|
** 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 */
|
/* Existing typedefs cannot be redeclared as anything different */
|
||||||
if (SCType == SC_TYPEDEF) {
|
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);
|
Error ("Conflicting types for typedef '%s'", Entry->Name);
|
||||||
Entry = 0;
|
Entry = 0;
|
||||||
}
|
}
|
||||||
@@ -591,7 +605,7 @@ static int HandleSymRedefinition (SymEntry* Entry, const Type* T, unsigned Flags
|
|||||||
Entry = 0;
|
Entry = 0;
|
||||||
} else {
|
} else {
|
||||||
/* New type must be compatible with the composite prototype */
|
/* 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);
|
Error ("Conflicting function types for '%s'", Entry->Name);
|
||||||
Entry = 0;
|
Entry = 0;
|
||||||
} else {
|
} else {
|
||||||
@@ -621,7 +635,7 @@ static int HandleSymRedefinition (SymEntry* Entry, const Type* T, unsigned Flags
|
|||||||
** is incomplete, complete it.
|
** is incomplete, complete it.
|
||||||
*/
|
*/
|
||||||
if ((Size != UNSPECIFIED && ESize != UNSPECIFIED && Size != ESize) ||
|
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 */
|
/* Conflicting element types */
|
||||||
Error ("Conflicting array types for '%s[]'", Entry->Name);
|
Error ("Conflicting array types for '%s[]'", Entry->Name);
|
||||||
Entry = 0;
|
Entry = 0;
|
||||||
@@ -639,7 +653,7 @@ static int HandleSymRedefinition (SymEntry* Entry, const Type* T, unsigned Flags
|
|||||||
if (SCType != E_SCType) {
|
if (SCType != E_SCType) {
|
||||||
Error ("Redefinition of '%s' as different kind of symbol", Entry->Name);
|
Error ("Redefinition of '%s' as different kind of symbol", Entry->Name);
|
||||||
Entry = 0;
|
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);
|
Error ("Conflicting types for '%s'", Entry->Name);
|
||||||
Entry = 0;
|
Entry = 0;
|
||||||
} else if (E_SCType == SC_ENUMERATOR) {
|
} else if (E_SCType == SC_ENUMERATOR) {
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
/* cc65 */
|
/* cc65 */
|
||||||
#include "funcdesc.h"
|
#include "error.h"
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "symtab.h"
|
#include "symtab.h"
|
||||||
#include "typecmp.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)
|
static int ParamsHaveDefaultPromotions (const FuncDesc* F)
|
||||||
/* Check if any of the parameters of function F has a default promotion. In
|
/* 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
|
** 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 */
|
/* Compare this field */
|
||||||
if (TypeCmp (Type1, Type2) < TC_EQUAL) {
|
if (TypeCmp (Type1, Type2).C < TC_EQUAL) {
|
||||||
/* Field types not equal */
|
/* Field types not equal */
|
||||||
return 0;
|
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)
|
static void DoCompare (const Type* lhs, const Type* rhs, typecmp_t* Result)
|
||||||
/* Recursively compare two types. */
|
/* Recursively compare two types. */
|
||||||
{
|
{
|
||||||
unsigned Indirections;
|
|
||||||
unsigned ElementCount;
|
|
||||||
SymEntry* Sym1;
|
SymEntry* Sym1;
|
||||||
SymEntry* Sym2;
|
SymEntry* Sym2;
|
||||||
FuncDesc* F1;
|
FuncDesc* F1;
|
||||||
FuncDesc* F2;
|
FuncDesc* F2;
|
||||||
|
TypeCode LeftType, RightType;
|
||||||
|
long LeftCount, RightCount;
|
||||||
|
|
||||||
|
|
||||||
/* Initialize stuff */
|
|
||||||
Indirections = 0;
|
|
||||||
ElementCount = 0;
|
|
||||||
|
|
||||||
/* Compare two types. Determine, where they differ */
|
/* Compare two types. Determine, where they differ */
|
||||||
while (lhs->C != T_END) {
|
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 */
|
/* Check if the end of the type string is reached */
|
||||||
if (rhs->C == T_END) {
|
if (rhs->C == T_END) {
|
||||||
/* End of comparison reached */
|
/* End of comparison reached */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compare qualifiers */
|
||||||
|
if (CmpQuals (lhs, rhs, Result)->C == TC_INCOMPATIBLE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the left and right types, signs and qualifiers */
|
/* Get the left and right types */
|
||||||
LeftType = (GetUnderlyingTypeCode (lhs) & T_MASK_TYPE);
|
LeftType = (GetUnderlyingTypeCode (lhs) & T_MASK_TYPE);
|
||||||
RightType = (GetUnderlyingTypeCode (rhs) & 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
|
/* If one side is a pointer and the other side is an array, both are
|
||||||
** are compatible.
|
** compatible.
|
||||||
*/
|
*/
|
||||||
if (LeftType == T_TYPE_PTR && RightType == T_TYPE_ARRAY) {
|
if (LeftType == T_TYPE_PTR && RightType == T_TYPE_ARRAY) {
|
||||||
RightType = T_TYPE_PTR;
|
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);
|
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' */
|
/* 'char' is neither 'signed char' nor 'unsigned char' */
|
||||||
if ((IsISOChar (lhs) && !IsISOChar (rhs)) ||
|
if ((IsISOChar (lhs) && !IsISOChar (rhs)) ||
|
||||||
(!IsISOChar (lhs) && IsISOChar (rhs))) {
|
(!IsISOChar (lhs) && IsISOChar (rhs))) {
|
||||||
SetResult (Result, TC_COMPATIBLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* On indirection level zero, a qualifier or sign difference is
|
|
||||||
** accepted. The types are no longer equal, but compatible.
|
|
||||||
*/
|
|
||||||
if (LeftSign != RightSign) {
|
|
||||||
if (ElementCount == 0) {
|
|
||||||
SetResult (Result, TC_SIGN_DIFF);
|
SetResult (Result, TC_SIGN_DIFF);
|
||||||
} else {
|
|
||||||
SetResult (Result, TC_INCOMPATIBLE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LeftType == T_TYPE_FUNC) {
|
/* On indirection level zero, a sign difference is accepted.
|
||||||
/* If a calling convention wasn't set explicitly,
|
** The types are no longer equal, but compatible.
|
||||||
** then assume the default one.
|
|
||||||
*/
|
*/
|
||||||
if ((LeftQual & T_QUAL_CCONV) == T_QUAL_NONE) {
|
if (GetSignedness (lhs) != GetSignedness (rhs)) {
|
||||||
LeftQual |= (AutoCDecl || IsVariadicFunc (lhs)) ? T_QUAL_CDECL : T_QUAL_FASTCALL;
|
SetResult (Result, TC_SIGN_DIFF);
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for special type elements */
|
/* Check for special type elements */
|
||||||
switch (LeftType) {
|
switch (LeftType) {
|
||||||
case T_TYPE_PTR:
|
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;
|
break;
|
||||||
|
|
||||||
case T_TYPE_FUNC:
|
case T_TYPE_FUNC:
|
||||||
@@ -364,8 +430,14 @@ static void DoCompare (const Type* lhs, const Type* rhs, typecmp_t* Result)
|
|||||||
SetResult (Result, TC_INCOMPATIBLE);
|
SetResult (Result, TC_INCOMPATIBLE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* We take into account which side is more specified */
|
||||||
|
if (LeftCount == UNSPECIFIED) {
|
||||||
|
SetResult (Result, TC_UNSPECIFY);
|
||||||
|
} else {
|
||||||
SetResult (Result, TC_EQUAL);
|
SetResult (Result, TC_EQUAL);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_TYPE_STRUCT:
|
case T_TYPE_STRUCT:
|
||||||
@@ -397,11 +469,10 @@ static void DoCompare (const Type* lhs, const Type* rhs, typecmp_t* Result)
|
|||||||
/* Next type string element */
|
/* Next type string element */
|
||||||
++lhs;
|
++lhs;
|
||||||
++rhs;
|
++rhs;
|
||||||
++ElementCount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if end of rhs reached */
|
/* Check if lhs and rhs both reached ends */
|
||||||
if (rhs->C == T_END) {
|
if (lhs->C == T_END && rhs->C == T_END) {
|
||||||
SetResult (Result, TC_IDENTICAL);
|
SetResult (Result, TC_IDENTICAL);
|
||||||
} else {
|
} else {
|
||||||
SetResult (Result, TC_INCOMPATIBLE);
|
SetResult (Result, TC_INCOMPATIBLE);
|
||||||
@@ -414,7 +485,7 @@ typecmp_t TypeCmp (const Type* lhs, const Type* rhs)
|
|||||||
/* Compare two types and return the result */
|
/* Compare two types and return the result */
|
||||||
{
|
{
|
||||||
/* Assume the types are identical */
|
/* Assume the types are identical */
|
||||||
typecmp_t Result = TC_IDENTICAL;
|
typecmp_t Result = TYPECMP_INITIALIZER;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
printf ("Left : "); PrintRawType (stdout, lhs);
|
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);
|
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 */
|
||||||
static void CompositeFuncParams (const FuncDesc* F1, const FuncDesc* F2)
|
|
||||||
/* Composite two function symbol tables regarding function parameters */
|
|
||||||
{
|
{
|
||||||
/* Get the symbol tables */
|
StrBuf NewTypeName = STATIC_STRBUF_INITIALIZER;
|
||||||
const SymTable* Tab1 = F1->SymTab;
|
StrBuf OldTypeName = STATIC_STRBUF_INITIALIZER;
|
||||||
const SymTable* Tab2 = F2->SymTab;
|
GetFullTypeNameBuf (&NewTypeName, NewType);
|
||||||
|
GetFullTypeNameBuf (&OldTypeName, OldType);
|
||||||
/* Composite the parameter lists */
|
if (IsError) {
|
||||||
const SymEntry* Sym1 = Tab1->SymHead;
|
Error (Msg, SB_GetConstBuf (&NewTypeName), SB_GetConstBuf (&OldTypeName));
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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 {
|
} else {
|
||||||
TypeCopy (OldType, NewType);
|
Warning (Msg, SB_GetConstBuf (&NewTypeName), SB_GetConstBuf (&OldTypeName));
|
||||||
Old->Flags &= ~FD_EMPTY;
|
|
||||||
}
|
}
|
||||||
}
|
SB_Done (&OldTypeName);
|
||||||
|
SB_Done (&NewTypeName);
|
||||||
return Old;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
typedef enum {
|
||||||
TC_INCOMPATIBLE, /* Distinct types */
|
TC_INCOMPATIBLE, /* Distinct types */
|
||||||
TC_SIGN_DIFF, /* Signedness differs */
|
TC_SIGN_DIFF, /* Signedness differs */
|
||||||
TC_COMPATIBLE = TC_SIGN_DIFF, /* Compatible types */
|
TC_PTR_INCOMPATIBLE, /* Distinct pointer types */
|
||||||
TC_QUAL_DIFF, /* Types differ in qualifier of pointer */
|
TC_VOID_PTR, /* Non-void and void pointers */
|
||||||
TC_STRICT_COMPATIBLE, /* Strict compatibility */
|
TC_STRICT_COMPATIBLE, /* Strict compatibility according to the C Standard */
|
||||||
TC_EQUAL, /* Types are equivalent */
|
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 */
|
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;
|
} typecmp_t;
|
||||||
|
|
||||||
|
#define TYPECMP_INITIALIZER { TC_IDENTICAL, TCF_NONE, 0 }
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Code */
|
/* Code */
|
||||||
@@ -70,8 +95,9 @@ typedef enum {
|
|||||||
typecmp_t TypeCmp (const Type* lhs, const Type* rhs);
|
typecmp_t TypeCmp (const Type* lhs, const Type* rhs);
|
||||||
/* Compare two types and return the result */
|
/* Compare two types and return the result */
|
||||||
|
|
||||||
FuncDesc* RefineFuncDesc (Type* OldType, const Type* NewType);
|
void TypeCompatibilityDiagnostic (const Type* NewType, const Type* OldType, int IsError, const char* Msg);
|
||||||
/* Refine the existing function descriptor with a new one */
|
/* Print error or warning message about type compatibility with proper type names */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* End of typecmp.h */
|
/* End of typecmp.h */
|
||||||
|
|||||||
@@ -43,7 +43,6 @@
|
|||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
#include "loadexpr.h"
|
#include "loadexpr.h"
|
||||||
#include "scanner.h"
|
|
||||||
#include "typecmp.h"
|
#include "typecmp.h"
|
||||||
#include "typeconv.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)
|
static void DoConversion (ExprDesc* Expr, const Type* NewType)
|
||||||
/* Emit code to convert the given expression to a new type. */
|
/* Emit code to convert the given expression to a new type. */
|
||||||
{
|
{
|
||||||
@@ -208,6 +189,7 @@ void TypeConversion (ExprDesc* Expr, const Type* NewType)
|
|||||||
PrintRawType (stdout, NewType);
|
PrintRawType (stdout, NewType);
|
||||||
#endif
|
#endif
|
||||||
/* First, do some type checking */
|
/* First, do some type checking */
|
||||||
|
typecmp_t Result = TYPECMP_INITIALIZER;
|
||||||
int HasWarning = 0;
|
int HasWarning = 0;
|
||||||
int HasError = 0;
|
int HasError = 0;
|
||||||
const char* Msg = 0;
|
const char* Msg = 0;
|
||||||
@@ -219,20 +201,13 @@ void TypeConversion (ExprDesc* Expr, const Type* NewType)
|
|||||||
HasError = 1;
|
HasError = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If both types are strictly compatible, no conversion is needed */
|
/* If both types are the same, no conversion is needed */
|
||||||
if (TypeCmp (NewType, OldType) >= TC_STRICT_COMPATIBLE) {
|
Result = TypeCmp (NewType, OldType);
|
||||||
/* We're already done */
|
if (Result.C < TC_IDENTICAL && (IsTypeArray (OldType) || IsTypeFunc (OldType))) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If Expr is an array or a function, convert it to a pointer */
|
/* If Expr is an array or a function, convert it to a pointer */
|
||||||
Expr->Type = PtrConversion (Expr->Type);
|
Expr->Type = PtrConversion (Expr->Type);
|
||||||
|
/* Recompare */
|
||||||
/* If we have changed the type, check again for strictly compatibility */
|
Result = TypeCmp (NewType, Expr->Type);
|
||||||
if (Expr->Type != OldType &&
|
|
||||||
TypeCmp (NewType, Expr->Type) >= TC_STRICT_COMPATIBLE) {
|
|
||||||
/* We're already done */
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for conversion problems */
|
/* Check for conversion problems */
|
||||||
@@ -253,37 +228,27 @@ void TypeConversion (ExprDesc* Expr, const Type* NewType)
|
|||||||
/* Handle conversions to pointer type */
|
/* Handle conversions to pointer type */
|
||||||
if (IsClassPtr (Expr->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
|
** - both point to the same types, or
|
||||||
** - the rhs pointer is a void pointer, or
|
** - the rhs pointer is a void pointer, or
|
||||||
** - the lhs pointer is a void pointer.
|
** - the lhs pointer is a void pointer.
|
||||||
*/
|
*/
|
||||||
if (!IsTypeVoid (IndirectConst (NewType)) && !IsTypeVoid (Indirect (Expr->Type))) {
|
if (Result.C <= TC_PTR_INCOMPATIBLE ||
|
||||||
/* Compare the types */
|
(Result.F & TCF_INCOMPATIBLE_QUAL) != 0)
|
||||||
switch (TypeCmp (NewType, Expr->Type)) {
|
{
|
||||||
|
|
||||||
case TC_INCOMPATIBLE:
|
|
||||||
HasWarning = 1;
|
HasWarning = 1;
|
||||||
Msg = "Incompatible pointer assignment to '%s' from '%s'";
|
Msg = "Incompatible pointer conversion to '%s' from '%s'";
|
||||||
/* Use the pointer type in the diagnostic */
|
/* Use the pointer type in the diagnostic */
|
||||||
OldType = Expr->Type;
|
OldType = Expr->Type;
|
||||||
break;
|
} else if ((Result.F & TCF_PTR_QUAL_DIFF) != 0) {
|
||||||
|
|
||||||
case TC_QUAL_DIFF:
|
|
||||||
HasWarning = 1;
|
HasWarning = 1;
|
||||||
Msg = "Pointer assignment to '%s' from '%s' discards qualifiers";
|
Msg = "Pointer conversion to '%s' from '%s' discards qualifiers";
|
||||||
/* Use the pointer type in the diagnostic */
|
/* Use the pointer type in the diagnostic */
|
||||||
OldType = Expr->Type;
|
OldType = Expr->Type;
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
/* Ok */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (IsClassInt (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) {
|
if (!ED_IsConstAbsInt (Expr) || Expr->IVal != 0) {
|
||||||
Warning ("Converting integer to pointer without a cast");
|
Warning ("Converting integer to pointer without a cast");
|
||||||
}
|
}
|
||||||
@@ -291,11 +256,12 @@ void TypeConversion (ExprDesc* Expr, const Type* NewType)
|
|||||||
HasError = 1;
|
HasError = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else if (Result.C < TC_IDENTICAL) {
|
||||||
/* Invalid automatic conversion */
|
/* Invalid automatic conversion */
|
||||||
HasError = 1;
|
HasError = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set default diagnostic message */
|
||||||
if (Msg == 0) {
|
if (Msg == 0) {
|
||||||
Msg = "Converting to '%s' from '%s'";
|
Msg = "Converting to '%s' from '%s'";
|
||||||
}
|
}
|
||||||
@@ -350,13 +316,13 @@ void TypeCast (ExprDesc* Expr)
|
|||||||
/* Convert functions and arrays to "pointer to" object */
|
/* Convert functions and arrays to "pointer to" object */
|
||||||
Expr->Type = PtrConversion (Expr->Type);
|
Expr->Type = PtrConversion (Expr->Type);
|
||||||
|
|
||||||
if (TypeCmp (NewType, Expr->Type) >= TC_QUAL_DIFF) {
|
if (TypeCmp (NewType, Expr->Type).C >= TC_PTR_INCOMPATIBLE) {
|
||||||
/* If the new type only differs in qualifiers, just use it to
|
/* If the new type has the same underlying presentation, just
|
||||||
** replace the old one.
|
** use it to replace the old one.
|
||||||
*/
|
*/
|
||||||
ReplaceType (Expr, NewType);
|
ReplaceType (Expr, NewType);
|
||||||
} else if (IsCastType (Expr->Type)) {
|
} 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);
|
DoConversion (Expr, NewType);
|
||||||
} else {
|
} else {
|
||||||
TypeCompatibilityDiagnostic (NewType, Expr->Type, 1,
|
TypeCompatibilityDiagnostic (NewType, Expr->Type, 1,
|
||||||
@@ -379,3 +345,142 @@ void TypeCast (ExprDesc* Expr)
|
|||||||
/* The result is always an rvalue */
|
/* The result is always an rvalue */
|
||||||
ED_MarkExprAsRVal (Expr);
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -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);
|
void TypeConversion (ExprDesc* Expr, const Type* NewType);
|
||||||
/* Do an automatic conversion of the given expression to the new type. Output
|
/* Do an automatic conversion of the given expression to the new type. Output
|
||||||
** warnings or errors where this automatic conversion is suspicious or
|
** 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);
|
void TypeCast (ExprDesc* Expr);
|
||||||
/* Handle an explicit cast. */
|
/* 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 */
|
/* End of typeconv.h */
|
||||||
|
|||||||
Reference in New Issue
Block a user