mirror of
https://github.com/cc65/cc65.git
synced 2025-01-10 19:29:45 +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:
parent
31c1172a3a
commit
b802efde54
@ -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'");
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
} else {
|
||||
SetResult (Result, TC_INCOMPATIBLE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (LeftType == T_TYPE_FUNC) {
|
||||
/* If a calling convention wasn't set explicitly,
|
||||
** then assume the default one.
|
||||
/* On indirection level zero, a sign difference is accepted.
|
||||
** The types are no longer equal, but compatible.
|
||||
*/
|
||||
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,8 +430,14 @@ static void DoCompare (const Type* lhs, const Type* rhs, typecmp_t* Result)
|
||||
SetResult (Result, TC_INCOMPATIBLE);
|
||||
return;
|
||||
}
|
||||
|
||||
/* We take into account which side is more specified */
|
||||
if (LeftCount == UNSPECIFIED) {
|
||||
SetResult (Result, TC_UNSPECIFY);
|
||||
} else {
|
||||
SetResult (Result, TC_EQUAL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case T_TYPE_STRUCT:
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
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);
|
||||
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 {
|
||||
TypeCopy (OldType, NewType);
|
||||
Old->Flags &= ~FD_EMPTY;
|
||||
Warning (Msg, SB_GetConstBuf (&NewTypeName), SB_GetConstBuf (&OldTypeName));
|
||||
}
|
||||
}
|
||||
|
||||
return Old;
|
||||
SB_Done (&OldTypeName);
|
||||
SB_Done (&NewTypeName);
|
||||
}
|
||||
|
@ -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_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 */
|
||||
|
@ -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,6 +189,7 @@ void TypeConversion (ExprDesc* Expr, const Type* NewType)
|
||||
PrintRawType (stdout, NewType);
|
||||
#endif
|
||||
/* First, do some type checking */
|
||||
typecmp_t Result = TYPECMP_INITIALIZER;
|
||||
int HasWarning = 0;
|
||||
int HasError = 0;
|
||||
const char* Msg = 0;
|
||||
@ -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 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);
|
||||
|
||||
/* 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;
|
||||
/* 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:
|
||||
if (Result.C <= TC_PTR_INCOMPATIBLE ||
|
||||
(Result.F & TCF_INCOMPATIBLE_QUAL) != 0)
|
||||
{
|
||||
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 */
|
||||
OldType = Expr->Type;
|
||||
break;
|
||||
|
||||
case TC_QUAL_DIFF:
|
||||
} else if ((Result.F & TCF_PTR_QUAL_DIFF) != 0) {
|
||||
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 */
|
||||
OldType = Expr->Type;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Ok */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} 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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user