mirror of
https://github.com/cc65/cc65.git
synced 2025-02-03 22:32:24 +00:00
Fixed underlying types of enums.
Made enumerator diagnostics more sensible. Fixed Issue #1048 as a natural result.
This commit is contained in:
parent
c272c73686
commit
daa65199b3
@ -83,14 +83,9 @@ const char* GetBasicTypeName (const Type* T)
|
||||
** Return "type" for unknown basic types.
|
||||
*/
|
||||
{
|
||||
switch (GetType (T)) {
|
||||
case T_TYPE_CHAR: return "char";
|
||||
case T_TYPE_SHORT: return "short";
|
||||
case T_TYPE_INT: return "integer";
|
||||
case T_TYPE_LONG: return "long";
|
||||
case T_TYPE_LONGLONG: return "long long";
|
||||
switch (GetRawType (T)) {
|
||||
case T_TYPE_ENUM: return "enum";
|
||||
case T_TYPE_FLOAT: return "poinfloatter";
|
||||
case T_TYPE_FLOAT: return "float";
|
||||
case T_TYPE_DOUBLE: return "double";
|
||||
case T_TYPE_VOID: return "void";
|
||||
case T_TYPE_STRUCT: return "struct";
|
||||
@ -99,8 +94,42 @@ const char* GetBasicTypeName (const Type* T)
|
||||
case T_TYPE_PTR: return "pointer";
|
||||
case T_TYPE_FUNC: return "function";
|
||||
case T_TYPE_NONE: /* FALLTHROUGH */
|
||||
default: return "type";
|
||||
default: break;
|
||||
}
|
||||
if (IsClassInt (T)) {
|
||||
if (IsSignSigned (T)) {
|
||||
switch (GetRawType (T)) {
|
||||
case T_TYPE_CHAR: return "signed char";
|
||||
case T_TYPE_SHORT: return "short";
|
||||
case T_TYPE_INT: return "int";
|
||||
case T_TYPE_LONG: return "long";
|
||||
case T_TYPE_LONGLONG: return "long long";
|
||||
default:
|
||||
return "signed integer";
|
||||
}
|
||||
} else if (IsSignUnsigned (T)) {
|
||||
switch (GetRawType (T)) {
|
||||
case T_TYPE_CHAR: return "unsigned char";
|
||||
case T_TYPE_SHORT: return "unsigned short";
|
||||
case T_TYPE_INT: return "unsigned int";
|
||||
case T_TYPE_LONG: return "unsigned long";
|
||||
case T_TYPE_LONGLONG: return "unsigned long long";
|
||||
default:
|
||||
return "unsigned integer";
|
||||
}
|
||||
} else {
|
||||
switch (GetRawType (T)) {
|
||||
case T_TYPE_CHAR: return "char";
|
||||
case T_TYPE_SHORT: return "short";
|
||||
case T_TYPE_INT: return "int";
|
||||
case T_TYPE_LONG: return "long";
|
||||
case T_TYPE_LONGLONG: return "long long";
|
||||
default:
|
||||
return "integer";
|
||||
}
|
||||
}
|
||||
}
|
||||
return "type";
|
||||
}
|
||||
|
||||
|
||||
@ -245,6 +274,49 @@ const Type* GetStructReplacementType (const Type* SType)
|
||||
|
||||
|
||||
|
||||
long GetIntegerTypeMin (const Type* Type)
|
||||
/* Get the smallest possible value of the integer type */
|
||||
{
|
||||
if (IsSignSigned (Type)) {
|
||||
return (long)(0xFFFFFFFF << (CHAR_BITS * SizeOf (Type) - 1U));
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned long GetIntegerTypeMax (const Type* Type)
|
||||
/* Get the largest possible value of the integer type */
|
||||
{
|
||||
if (IsSignSigned (Type)) {
|
||||
return (1UL << (CHAR_BITS * SizeOf (Type) - 1U)) - 1UL;
|
||||
} else {
|
||||
return (1UL << (CHAR_BITS * SizeOf (Type))) - 1UL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static unsigned TypeOfBySize (const Type* Type)
|
||||
/* Get the code generator replacement type of the object by its size */
|
||||
{
|
||||
unsigned NewType;
|
||||
/* If the size is less than or equal to that of a a long, we will copy
|
||||
** the struct using the primary register, otherwise we use memcpy.
|
||||
*/
|
||||
switch (SizeOf (Type)) {
|
||||
case 1: NewType = CF_CHAR; break;
|
||||
case 2: NewType = CF_INT; break;
|
||||
case 3: /* FALLTHROUGH */
|
||||
case 4: NewType = CF_LONG; break;
|
||||
default: NewType = CF_NONE; break;
|
||||
}
|
||||
|
||||
return NewType;
|
||||
}
|
||||
|
||||
|
||||
Type* PointerTo (const Type* T)
|
||||
/* Return a type string that is "pointer to T". The type string is allocated
|
||||
** on the heap and may be freed after use.
|
||||
@ -321,6 +393,9 @@ void PrintType (FILE* F, const Type* T)
|
||||
case T_TYPE_LONGLONG:
|
||||
fprintf (F, "long long");
|
||||
break;
|
||||
case T_TYPE_ENUM:
|
||||
fprintf (F, "enum");
|
||||
break;
|
||||
case T_TYPE_FLOAT:
|
||||
fprintf (F, "float");
|
||||
break;
|
||||
@ -430,10 +505,68 @@ int TypeHasAttr (const Type* T)
|
||||
|
||||
|
||||
|
||||
const Type* GetUnderlyingType (const Type* Type)
|
||||
/* Get the underlying type of an enum or other integer class type */
|
||||
{
|
||||
if (IsTypeEnum (Type)) {
|
||||
|
||||
/* This should not happen, but just in case */
|
||||
if (Type->A.P == 0) {
|
||||
Internal ("Enum tag type error in GetUnderlyingTypeCode");
|
||||
}
|
||||
|
||||
return ((SymEntry*)Type->A.P)->V.E.Type;
|
||||
}
|
||||
|
||||
return Type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
TypeCode GetUnderlyingTypeCode (const Type* Type)
|
||||
/* Get the type code of the unqualified underlying type of TCode.
|
||||
** Return UnqualifiedType (TCode) if TCode is not scalar.
|
||||
*/
|
||||
{
|
||||
TypeCode Underlying = UnqualifiedType (Type->C);
|
||||
TypeCode TCode;
|
||||
|
||||
/* We could also support other T_CLASS_INT types, but just enums for now */
|
||||
if (IsTypeEnum (Type)) {
|
||||
|
||||
/* This should not happen, but just in case */
|
||||
if (Type->A.P == 0) {
|
||||
Internal ("Enum tag type error in GetUnderlyingTypeCode");
|
||||
}
|
||||
|
||||
/* Inspect the underlying type of the enum */
|
||||
if (((SymEntry*)Type->A.P)->V.E.Type == 0) {
|
||||
/* Incomplete enum type is used */
|
||||
return Underlying;
|
||||
}
|
||||
TCode = UnqualifiedType (((SymEntry*)Type->A.P)->V.E.Type->C);
|
||||
|
||||
/* Replace the type code with integer */
|
||||
Underlying = (TCode & ~T_MASK_TYPE);
|
||||
switch (TCode & T_MASK_SIZE) {
|
||||
case T_SIZE_INT: Underlying |= T_TYPE_INT; break;
|
||||
case T_SIZE_LONG: Underlying |= T_TYPE_LONG; break;
|
||||
case T_SIZE_SHORT: Underlying |= T_TYPE_SHORT; break;
|
||||
case T_SIZE_CHAR: Underlying |= T_TYPE_CHAR; break;
|
||||
case T_SIZE_LONGLONG: Underlying |= T_TYPE_LONGLONG; break;
|
||||
default: Underlying |= T_TYPE_INT; break;
|
||||
}
|
||||
}
|
||||
|
||||
return Underlying;
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned SizeOf (const Type* T)
|
||||
/* Compute size of object represented by type array. */
|
||||
{
|
||||
switch (UnqualifiedType (T->C)) {
|
||||
switch (GetUnderlyingTypeCode (T)) {
|
||||
|
||||
case T_VOID:
|
||||
/* A void variable is a cc65 extension.
|
||||
@ -470,9 +603,6 @@ unsigned SizeOf (const Type* T)
|
||||
case T_ULONGLONG:
|
||||
return SIZEOF_LONGLONG;
|
||||
|
||||
case T_ENUM:
|
||||
return SIZEOF_INT;
|
||||
|
||||
case T_FLOAT:
|
||||
return SIZEOF_FLOAT;
|
||||
|
||||
@ -491,7 +621,12 @@ unsigned SizeOf (const Type* T)
|
||||
return T->A.U * SizeOf (T + 1);
|
||||
}
|
||||
|
||||
case T_ENUM:
|
||||
/* Incomplete enum type */
|
||||
return 0;
|
||||
|
||||
default:
|
||||
|
||||
Internal ("Unknown type in SizeOf: %04lX", T->C);
|
||||
return 0;
|
||||
|
||||
@ -547,7 +682,9 @@ unsigned CheckedPSizeOf (const Type* T)
|
||||
unsigned TypeOf (const Type* T)
|
||||
/* Get the code generator base type of the object */
|
||||
{
|
||||
switch (UnqualifiedType (T->C)) {
|
||||
unsigned NewType;
|
||||
|
||||
switch (GetUnderlyingTypeCode (T)) {
|
||||
|
||||
case T_SCHAR:
|
||||
return CF_CHAR;
|
||||
@ -557,7 +694,6 @@ unsigned TypeOf (const Type* T)
|
||||
|
||||
case T_SHORT:
|
||||
case T_INT:
|
||||
case T_ENUM:
|
||||
return CF_INT;
|
||||
|
||||
case T_USHORT:
|
||||
@ -582,6 +718,10 @@ unsigned TypeOf (const Type* T)
|
||||
|
||||
case T_STRUCT:
|
||||
case T_UNION:
|
||||
NewType = TypeOfBySize (T);
|
||||
if (NewType != CF_NONE) {
|
||||
return NewType;
|
||||
}
|
||||
/* Address of ... */
|
||||
return CF_INT | CF_UNSIGNED;
|
||||
|
||||
@ -726,8 +866,8 @@ Type* GetBaseElementType (Type* T)
|
||||
SymEntry* GetSymEntry (const Type* T)
|
||||
/* Return a SymEntry pointer from a type */
|
||||
{
|
||||
/* Only structs or unions have a SymEntry attribute */
|
||||
CHECK (IsClassStruct (T));
|
||||
/* Only enums, structs or unions have a SymEntry attribute */
|
||||
CHECK (IsClassStruct (T) || IsTypeEnum (T));
|
||||
|
||||
/* Return the attribute */
|
||||
return T->A.P;
|
||||
@ -738,8 +878,8 @@ SymEntry* GetSymEntry (const Type* T)
|
||||
void SetSymEntry (Type* T, SymEntry* S)
|
||||
/* Set the SymEntry pointer for a type */
|
||||
{
|
||||
/* Only structs or unions have a SymEntry attribute */
|
||||
CHECK (IsClassStruct (T));
|
||||
/* Only enums, structs or unions have a SymEntry attribute */
|
||||
CHECK (IsClassStruct (T) || IsTypeEnum (T));
|
||||
|
||||
/* Set the attribute */
|
||||
T->A.P = S;
|
||||
|
@ -96,37 +96,39 @@ enum {
|
||||
|
||||
/* Type size modifiers */
|
||||
T_SIZE_NONE = 0x000000,
|
||||
T_SIZE_SHORT = 0x000200,
|
||||
T_SIZE_LONG = 0x000400,
|
||||
T_SIZE_LONGLONG = 0x000600,
|
||||
T_MASK_SIZE = 0x000600,
|
||||
T_SIZE_CHAR = 0x000200,
|
||||
T_SIZE_SHORT = 0x000400,
|
||||
T_SIZE_INT = 0x000600,
|
||||
T_SIZE_LONG = 0x000800,
|
||||
T_SIZE_LONGLONG = 0x000A00,
|
||||
T_MASK_SIZE = 0x000E00,
|
||||
|
||||
/* Type qualifiers */
|
||||
T_QUAL_NONE = 0x000000,
|
||||
T_QUAL_CONST = 0x000800,
|
||||
T_QUAL_VOLATILE = 0x001000,
|
||||
T_QUAL_RESTRICT = 0x002000,
|
||||
T_QUAL_NEAR = 0x004000,
|
||||
T_QUAL_FAR = 0x008000,
|
||||
T_QUAL_CONST = 0x001000,
|
||||
T_QUAL_VOLATILE = 0x002000,
|
||||
T_QUAL_RESTRICT = 0x004000,
|
||||
T_QUAL_NEAR = 0x008000,
|
||||
T_QUAL_FAR = 0x010000,
|
||||
T_QUAL_ADDRSIZE = T_QUAL_NEAR | T_QUAL_FAR,
|
||||
T_QUAL_FASTCALL = 0x010000,
|
||||
T_QUAL_CDECL = 0x020000,
|
||||
T_QUAL_FASTCALL = 0x020000,
|
||||
T_QUAL_CDECL = 0x040000,
|
||||
T_QUAL_CCONV = T_QUAL_FASTCALL | T_QUAL_CDECL,
|
||||
T_MASK_QUAL = 0x03F800,
|
||||
T_MASK_QUAL = 0x07F000,
|
||||
|
||||
/* Types */
|
||||
T_CHAR = T_TYPE_CHAR | T_CLASS_INT | T_SIGN_UNSIGNED | T_SIZE_NONE,
|
||||
T_SCHAR = T_TYPE_CHAR | T_CLASS_INT | T_SIGN_SIGNED | T_SIZE_NONE,
|
||||
T_UCHAR = T_TYPE_CHAR | T_CLASS_INT | T_SIGN_UNSIGNED | T_SIZE_NONE,
|
||||
T_CHAR = T_TYPE_CHAR | T_CLASS_INT | T_SIGN_UNSIGNED | T_SIZE_CHAR,
|
||||
T_SCHAR = T_TYPE_CHAR | T_CLASS_INT | T_SIGN_SIGNED | T_SIZE_CHAR,
|
||||
T_UCHAR = T_TYPE_CHAR | T_CLASS_INT | T_SIGN_UNSIGNED | T_SIZE_CHAR,
|
||||
T_SHORT = T_TYPE_SHORT | T_CLASS_INT | T_SIGN_SIGNED | T_SIZE_SHORT,
|
||||
T_USHORT = T_TYPE_SHORT | T_CLASS_INT | T_SIGN_UNSIGNED | T_SIZE_SHORT,
|
||||
T_INT = T_TYPE_INT | T_CLASS_INT | T_SIGN_SIGNED | T_SIZE_NONE,
|
||||
T_UINT = T_TYPE_INT | T_CLASS_INT | T_SIGN_UNSIGNED | T_SIZE_NONE,
|
||||
T_INT = T_TYPE_INT | T_CLASS_INT | T_SIGN_SIGNED | T_SIZE_INT,
|
||||
T_UINT = T_TYPE_INT | T_CLASS_INT | T_SIGN_UNSIGNED | T_SIZE_INT,
|
||||
T_LONG = T_TYPE_LONG | T_CLASS_INT | T_SIGN_SIGNED | T_SIZE_LONG,
|
||||
T_ULONG = T_TYPE_LONG | T_CLASS_INT | T_SIGN_UNSIGNED | T_SIZE_LONG,
|
||||
T_LONGLONG = T_TYPE_LONGLONG | T_CLASS_INT | T_SIGN_SIGNED | T_SIZE_LONGLONG,
|
||||
T_ULONGLONG = T_TYPE_LONGLONG | T_CLASS_INT | T_SIGN_UNSIGNED | T_SIZE_LONGLONG,
|
||||
T_ENUM = T_TYPE_ENUM | T_CLASS_INT | T_SIGN_SIGNED | T_SIZE_NONE,
|
||||
T_ENUM = T_TYPE_ENUM | T_CLASS_INT | T_SIGN_NONE | T_SIZE_NONE,
|
||||
T_FLOAT = T_TYPE_FLOAT | T_CLASS_FLOAT | T_SIGN_NONE | T_SIZE_NONE,
|
||||
T_DOUBLE = T_TYPE_DOUBLE | T_CLASS_FLOAT | T_SIGN_NONE | T_SIZE_NONE,
|
||||
T_VOID = T_TYPE_VOID | T_CLASS_NONE | T_SIGN_NONE | T_SIZE_NONE,
|
||||
@ -246,6 +248,12 @@ Type* GetImplicitFuncType (void);
|
||||
const Type* GetStructReplacementType (const Type* SType);
|
||||
/* Get a replacement type for passing a struct/union in the primary register */
|
||||
|
||||
long GetIntegerTypeMin (const Type* Type);
|
||||
/* Get the smallest possible value of the integer type */
|
||||
|
||||
unsigned long GetIntegerTypeMax (const Type* Type);
|
||||
/* Get the largest possible value of the integer type */
|
||||
|
||||
Type* PointerTo (const Type* T);
|
||||
/* Return a type string that is "pointer to T". The type string is allocated
|
||||
** on the heap and may be freed after use.
|
||||
@ -283,6 +291,14 @@ INLINE TypeCode UnqualifiedType (TypeCode T)
|
||||
# define UnqualifiedType(T) ((T) & ~T_MASK_QUAL)
|
||||
#endif
|
||||
|
||||
const Type* GetUnderlyingType (const Type* Type);
|
||||
/* Get the underlying type of an enum or other integer class type */
|
||||
|
||||
TypeCode GetUnderlyingTypeCode (const Type* Type);
|
||||
/* Get the type code of the unqualified underlying type of TCode.
|
||||
** Return TCode if it is not scalar.
|
||||
*/
|
||||
|
||||
unsigned SizeOf (const Type* T);
|
||||
/* Compute size of object represented by type array. */
|
||||
|
||||
@ -312,123 +328,163 @@ Type* ArrayToPtr (Type* T);
|
||||
/* Convert an array to a pointer to it's first element */
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE TypeCode GetType (const Type* T)
|
||||
INLINE TypeCode GetRawType (const Type* T)
|
||||
/* Get the raw type */
|
||||
{
|
||||
return (T->C & T_MASK_TYPE);
|
||||
}
|
||||
#else
|
||||
# define GetType(T) ((T)->C & T_MASK_TYPE)
|
||||
# define GetRawType(T) ((T)->C & T_MASK_TYPE)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int IsTypeChar (const Type* T)
|
||||
/* Return true if this is a character type */
|
||||
{
|
||||
return (GetType (T) == T_TYPE_CHAR);
|
||||
return (GetRawType (GetUnderlyingType (T)) == T_TYPE_CHAR);
|
||||
}
|
||||
#else
|
||||
# define IsTypeChar(T) (GetType (T) == T_TYPE_CHAR)
|
||||
# define IsTypeChar(T) (GetRawType (GetUnderlyingType (T)) == T_TYPE_CHAR)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int IsTypeInt (const Type* T)
|
||||
/* Return true if this is an int type (signed or unsigned) */
|
||||
{
|
||||
return (GetType (T) == T_TYPE_INT);
|
||||
return (GetRawType (GetUnderlyingType (T)) == T_TYPE_INT);
|
||||
}
|
||||
#else
|
||||
# define IsTypeInt(T) (GetType (T) == T_TYPE_INT)
|
||||
# define IsTypeInt(T) (GetRawType (GetUnderlyingType (T)) == T_TYPE_INT)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int IsTypeLong (const Type* T)
|
||||
/* Return true if this is a long type (signed or unsigned) */
|
||||
{
|
||||
return (GetType (T) == T_TYPE_LONG);
|
||||
return (GetRawType (GetUnderlyingType (T)) == T_TYPE_LONG);
|
||||
}
|
||||
#else
|
||||
# define IsTypeLong(T) (GetType (T) == T_TYPE_LONG)
|
||||
# define IsTypeLong(T) (GetRawType (GetUnderlyingType (T)) == T_TYPE_LONG)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int IsRawTypeChar (const Type* T)
|
||||
/* Return true if this is a character raw type */
|
||||
{
|
||||
return (GetRawType (T) == T_TYPE_CHAR);
|
||||
}
|
||||
#else
|
||||
# define IsRawTypeChar(T) (GetRawType (T) == T_TYPE_CHAR)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int IsRawTypeInt (const Type* T)
|
||||
/* Return true if this is an int raw type (signed or unsigned) */
|
||||
{
|
||||
return (GetRawType (T) == T_TYPE_INT);
|
||||
}
|
||||
#else
|
||||
# define IsRawTypeInt(T) (GetRawType (T) == T_TYPE_INT)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int IsRawTypeLong (const Type* T)
|
||||
/* Return true if this is a long raw type (signed or unsigned) */
|
||||
{
|
||||
return (GetRawType (T) == T_TYPE_LONG);
|
||||
}
|
||||
#else
|
||||
# define IsRawTypeLong(T) (GetRawType (T) == T_TYPE_LONG)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int IsTypeFloat (const Type* T)
|
||||
/* Return true if this is a float type */
|
||||
{
|
||||
return (GetType (T) == T_TYPE_FLOAT);
|
||||
return (GetRawType (T) == T_TYPE_FLOAT);
|
||||
}
|
||||
#else
|
||||
# define IsTypeFloat(T) (GetType (T) == T_TYPE_FLOAT)
|
||||
# define IsTypeFloat(T) (GetRawType (T) == T_TYPE_FLOAT)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int IsTypeDouble (const Type* T)
|
||||
/* Return true if this is a double type */
|
||||
{
|
||||
return (GetType (T) == T_TYPE_DOUBLE);
|
||||
return (GetRawType (T) == T_TYPE_DOUBLE);
|
||||
}
|
||||
#else
|
||||
# define IsTypeDouble(T) (GetType (T) == T_TYPE_DOUBLE)
|
||||
# define IsTypeDouble(T) (GetRawType (T) == T_TYPE_DOUBLE)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int IsTypePtr (const Type* T)
|
||||
/* Return true if this is a pointer type */
|
||||
{
|
||||
return (GetType (T) == T_TYPE_PTR);
|
||||
return (GetRawType (T) == T_TYPE_PTR);
|
||||
}
|
||||
#else
|
||||
# define IsTypePtr(T) (GetType (T) == T_TYPE_PTR)
|
||||
# define IsTypePtr(T) (GetRawType (T) == T_TYPE_PTR)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int IsTypeEnum (const Type* T)
|
||||
/* Return true if this is an enum type */
|
||||
{
|
||||
return (GetRawType (T) == T_TYPE_ENUM);
|
||||
}
|
||||
#else
|
||||
# define IsTypeEnum(T) (GetRawType (T) == T_TYPE_ENUM)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int IsTypeStruct (const Type* T)
|
||||
/* Return true if this is a struct type */
|
||||
{
|
||||
return (GetType (T) == T_TYPE_STRUCT);
|
||||
return (GetRawType (T) == T_TYPE_STRUCT);
|
||||
}
|
||||
#else
|
||||
# define IsTypeStruct(T) (GetType (T) == T_TYPE_STRUCT)
|
||||
# define IsTypeStruct(T) (GetRawType (T) == T_TYPE_STRUCT)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int IsTypeUnion (const Type* T)
|
||||
/* Return true if this is a union type */
|
||||
{
|
||||
return (GetType (T) == T_TYPE_UNION);
|
||||
return (GetRawType (T) == T_TYPE_UNION);
|
||||
}
|
||||
#else
|
||||
# define IsTypeUnion(T) (GetType (T) == T_TYPE_UNION)
|
||||
# define IsTypeUnion(T) (GetRawType (T) == T_TYPE_UNION)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int IsTypeArray (const Type* T)
|
||||
/* Return true if this is an array type */
|
||||
{
|
||||
return (GetType (T) == T_TYPE_ARRAY);
|
||||
return (GetRawType (T) == T_TYPE_ARRAY);
|
||||
}
|
||||
#else
|
||||
# define IsTypeArray(T) (GetType (T) == T_TYPE_ARRAY)
|
||||
# define IsTypeArray(T) (GetRawType (T) == T_TYPE_ARRAY)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int IsTypeVoid (const Type* T)
|
||||
/* Return true if this is a void type */
|
||||
{
|
||||
return (GetType (T) == T_TYPE_VOID);
|
||||
return (GetRawType (T) == T_TYPE_VOID);
|
||||
}
|
||||
#else
|
||||
# define IsTypeVoid(T) (GetType (T) == T_TYPE_VOID)
|
||||
# define IsTypeVoid(T) (GetRawType (T) == T_TYPE_VOID)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int IsTypeFunc (const Type* T)
|
||||
/* Return true if this is a function class */
|
||||
{
|
||||
return (GetType (T) == T_TYPE_FUNC);
|
||||
return (GetRawType (T) == T_TYPE_FUNC);
|
||||
}
|
||||
#else
|
||||
# define IsTypeFunc(T) (GetType (T) == T_TYPE_FUNC)
|
||||
# define IsTypeFunc(T) (GetRawType (T) == T_TYPE_FUNC)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
@ -502,13 +558,23 @@ INLINE int IsClassFunc (const Type* T)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE TypeCode GetSignedness (const Type* T)
|
||||
/* Get the sign of a type */
|
||||
INLINE TypeCode GetRawSignedness (const Type* T)
|
||||
/* Get the raw signedness of a type */
|
||||
{
|
||||
return (T->C & T_MASK_SIGN);
|
||||
return ((T)->C & T_MASK_SIGN);
|
||||
}
|
||||
#else
|
||||
# define GetSignedness(T) ((T)->C & T_MASK_SIGN)
|
||||
# define GetRawSignedness(T) ((T)->C & T_MASK_SIGN)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE TypeCode GetSignedness (const Type* T)
|
||||
/* Get the signedness of a type */
|
||||
{
|
||||
return (GetUnderlyingTypeCode (T) & T_MASK_SIGN);
|
||||
}
|
||||
#else
|
||||
# define GetSignedness(T) (GetUnderlyingTypeCode (T) & T_MASK_SIGN)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
|
@ -453,27 +453,99 @@ static void ParseStorageClass (DeclSpec* D, unsigned DefStorage)
|
||||
|
||||
|
||||
|
||||
static void ParseEnumDecl (void)
|
||||
/* Process an enum declaration . */
|
||||
static SymEntry* ESUForwardDecl (const char* Name, unsigned Type)
|
||||
/* Handle an enum, struct or union forward decl */
|
||||
{
|
||||
int EnumVal;
|
||||
ident Ident;
|
||||
/* Try to find an enum/struct/union with the given name. If there is none,
|
||||
** insert a forward declaration into the current lexical level.
|
||||
*/
|
||||
SymEntry* Entry = FindTagSym (Name);
|
||||
if (Entry == 0) {
|
||||
if (Type != SC_ENUM) {
|
||||
Entry = AddStructSym (Name, Type, 0, 0);
|
||||
} else {
|
||||
Entry = AddEnumSym (Name, 0, 0);
|
||||
}
|
||||
} else if ((Entry->Flags & SC_TYPEMASK) != Type) {
|
||||
/* Already defined, but not the same type class */
|
||||
Error ("Symbol '%s' is already different kind", Name);
|
||||
}
|
||||
return Entry;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static const Type* GetEnumeratorType (long Min, unsigned long Max, int Signed)
|
||||
/* GitHub #1093 - We use unsigned types to save spaces whenever possible.
|
||||
** If both the signed and unsigned integer types of the same minimum size
|
||||
** capable of representing all values of the enum, we prefer the unsigned
|
||||
** one.
|
||||
** Return 0 if impossible to represent Min and Max as the same integer type.
|
||||
*/
|
||||
{
|
||||
const Type* Underlying = type_int; /* default type */
|
||||
|
||||
/* Change the underlying type if necessary */
|
||||
if (Min < 0 || Signed) {
|
||||
/* We can't use unsigned types if there are any negative values */
|
||||
if (Max > (unsigned long)INT32_MAX) {
|
||||
/* No way to represent both Min and Max as the same integer type */
|
||||
Underlying = 0;
|
||||
} else if (Min < INT16_MIN || Max > (unsigned long)INT16_MAX) {
|
||||
Underlying = type_long;
|
||||
} else if (Min < INT8_MIN || Max > (unsigned long)INT8_MAX) {
|
||||
Underlying = type_int;
|
||||
} else {
|
||||
Underlying = type_schar;
|
||||
}
|
||||
} else {
|
||||
if (Max > UINT16_MAX) {
|
||||
Underlying = type_ulong;
|
||||
} else if (Max > UINT8_MAX) {
|
||||
Underlying = type_uint;
|
||||
} else {
|
||||
Underlying = type_uchar;
|
||||
}
|
||||
}
|
||||
|
||||
return Underlying;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static SymEntry* ParseEnumDecl (const char* Name)
|
||||
/* Process an enum declaration */
|
||||
{
|
||||
SymTable* FieldTab;
|
||||
long EnumVal;
|
||||
int IsSigned;
|
||||
int IsIncremented;
|
||||
ident Ident;
|
||||
long MinConstant = 0;
|
||||
unsigned long MaxConstant = 0;
|
||||
const Type* NewType = type_int; /* new enumerator type */
|
||||
const Type* MemberType = type_int; /* default enumerator type */
|
||||
|
||||
/* Accept forward definitions */
|
||||
if (CurTok.Tok != TOK_LCURLY) {
|
||||
return;
|
||||
return ESUForwardDecl (Name, SC_ENUM);
|
||||
}
|
||||
|
||||
/* Add the enum tag */
|
||||
AddEnumSym (Name, 0, 0);
|
||||
|
||||
/* Skip the opening curly brace */
|
||||
NextToken ();
|
||||
|
||||
/* Read the enum tags */
|
||||
EnumVal = 0;
|
||||
EnumVal = -1L;
|
||||
while (CurTok.Tok != TOK_RCURLY) {
|
||||
|
||||
/* We expect an identifier */
|
||||
if (CurTok.Tok != TOK_IDENT) {
|
||||
Error ("Identifier expected");
|
||||
Error ("Identifier expected for enumerator declarator");
|
||||
/* Avoid excessive errors */
|
||||
NextToken ();
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -483,21 +555,116 @@ static void ParseEnumDecl (void)
|
||||
|
||||
/* Check for an assigned value */
|
||||
if (CurTok.Tok == TOK_ASSIGN) {
|
||||
|
||||
ExprDesc Expr;
|
||||
NextToken ();
|
||||
ConstAbsIntExpr (hie1, &Expr);
|
||||
EnumVal = Expr.IVal;
|
||||
EnumVal = Expr.IVal;
|
||||
MemberType = Expr.Type;
|
||||
IsSigned = IsSignSigned (MemberType);
|
||||
IsIncremented = 0;
|
||||
|
||||
} else {
|
||||
|
||||
/* Defaulted with the same signedness as the previous member's */
|
||||
IsSigned = IsSignSigned (MemberType) &&
|
||||
(unsigned long)EnumVal != GetIntegerTypeMax (MemberType);
|
||||
|
||||
/* Enumerate. Signed integer overflow is UB but unsigned integers
|
||||
** are guaranteed to wrap around.
|
||||
*/
|
||||
EnumVal = (long)((unsigned long)EnumVal + 1UL);
|
||||
|
||||
if (UnqualifiedType (MemberType->C) == T_ULONG && EnumVal == 0) {
|
||||
/* Warn on 'unsigned long' overflow in enumeration */
|
||||
Warning ("Enumerator '%s' overflows the range of '%s'",
|
||||
Ident,
|
||||
GetBasicTypeName (type_ulong));
|
||||
}
|
||||
|
||||
IsIncremented = 1;
|
||||
}
|
||||
|
||||
/* Add an entry to the symbol table */
|
||||
AddConstSym (Ident, type_int, SC_ENUMERATOR | SC_CONST, EnumVal++);
|
||||
/* Track down the min/max values and evaluate the type of EnumVal
|
||||
** using GetEnumeratorType in a tricky way.
|
||||
*/
|
||||
if (!IsSigned || EnumVal >= 0) {
|
||||
if ((unsigned long)EnumVal > MaxConstant) {
|
||||
MaxConstant = (unsigned long)EnumVal;
|
||||
}
|
||||
NewType = GetEnumeratorType (0, EnumVal, IsSigned);
|
||||
} else {
|
||||
if (EnumVal < MinConstant) {
|
||||
MinConstant = EnumVal;
|
||||
}
|
||||
NewType = GetEnumeratorType (EnumVal, 0, 1);
|
||||
}
|
||||
|
||||
/* GetEnumeratorType above should never fail, but just in case */
|
||||
if (NewType == 0) {
|
||||
Internal ("Unexpected failure with GetEnumeratorType: %lx", EnumVal);
|
||||
NewType = type_ulong;
|
||||
} else if (SizeOf (NewType) < SizeOf (type_int)) {
|
||||
/* Integer constants are not shorter than int */
|
||||
NewType = type_int;
|
||||
}
|
||||
|
||||
/* Warn if the incremented value exceeds the range of the previous
|
||||
** type.
|
||||
*/
|
||||
if (IsIncremented &&
|
||||
EnumVal >= 0 &&
|
||||
NewType->C != UnqualifiedType (MemberType->C)) {
|
||||
/* The possible overflow here can only be when EnumVal > 0 */
|
||||
Warning ("Enumerator '%s' (value = %lu) is of type '%s'",
|
||||
Ident,
|
||||
(unsigned long)EnumVal,
|
||||
GetBasicTypeName (NewType));
|
||||
}
|
||||
|
||||
/* Warn if the value exceeds range of 'int' in standard mode */
|
||||
if (IS_Get (&Standard) != STD_CC65 && NewType->C != T_INT) {
|
||||
if (!IsSigned || EnumVal >= 0) {
|
||||
Warning ("ISO C restricts enumerator values to range of 'int'\n"
|
||||
"\tEnumerator '%s' (value = %lu) is too large",
|
||||
Ident,
|
||||
(unsigned long)EnumVal);
|
||||
} else {
|
||||
Warning ("ISO C restricts enumerator values to range of 'int'\n"
|
||||
"\tEnumerator '%s' (value = %ld) is too small",
|
||||
Ident,
|
||||
EnumVal);
|
||||
}
|
||||
}
|
||||
|
||||
/* Add an entry of the enumerator to the symbol table */
|
||||
AddConstSym (Ident, NewType, SC_ENUMERATOR | SC_CONST, EnumVal);
|
||||
|
||||
/* Use this type for following members */
|
||||
MemberType = NewType;
|
||||
|
||||
/* Check for end of definition */
|
||||
if (CurTok.Tok != TOK_COMMA)
|
||||
if (CurTok.Tok != TOK_COMMA) {
|
||||
break;
|
||||
}
|
||||
NextToken ();
|
||||
}
|
||||
ConsumeRCurly ();
|
||||
|
||||
/* This evaluates the underlying type of the whole enum */
|
||||
MemberType = GetEnumeratorType (MinConstant, MaxConstant, 0);
|
||||
if (MemberType == 0) {
|
||||
/* It is very likely that the program is wrong */
|
||||
Error ("Enumeration values cannot be represented all as 'long'\n"
|
||||
"\tMin enumerator value = %ld, Max enumerator value = %lu",
|
||||
MinConstant, MaxConstant);
|
||||
|
||||
/* Avoid more errors */
|
||||
MemberType = type_long;
|
||||
}
|
||||
|
||||
FieldTab = GetSymTab ();
|
||||
return AddEnumSym (Name, MemberType, FieldTab);
|
||||
}
|
||||
|
||||
|
||||
@ -541,24 +708,6 @@ static int ParseFieldWidth (Declaration* Decl)
|
||||
|
||||
|
||||
|
||||
static SymEntry* StructOrUnionForwardDecl (const char* Name, unsigned Type)
|
||||
/* Handle a struct or union forward decl */
|
||||
{
|
||||
/* Try to find a struct/union with the given name. If there is none,
|
||||
** insert a forward declaration into the current lexical level.
|
||||
*/
|
||||
SymEntry* Entry = FindTagSym (Name);
|
||||
if (Entry == 0) {
|
||||
Entry = AddStructSym (Name, Type, 0, 0);
|
||||
} else if ((Entry->Flags & SC_TYPEMASK) != Type) {
|
||||
/* Already defined, but no struct */
|
||||
Error ("Symbol '%s' is already different kind", Name);
|
||||
}
|
||||
return Entry;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static unsigned CopyAnonStructFields (const Declaration* Decl, int Offs)
|
||||
/* Copy fields from an anon union/struct into the current lexical level. The
|
||||
** function returns the size of the embedded struct/union.
|
||||
@ -617,7 +766,7 @@ static SymEntry* ParseUnionDecl (const char* Name)
|
||||
|
||||
if (CurTok.Tok != TOK_LCURLY) {
|
||||
/* Just a forward declaration. */
|
||||
return StructOrUnionForwardDecl (Name, SC_UNION);
|
||||
return ESUForwardDecl (Name, SC_UNION);
|
||||
}
|
||||
|
||||
/* Add a forward declaration for the struct in the current lexical level */
|
||||
@ -722,7 +871,7 @@ static SymEntry* ParseStructDecl (const char* Name)
|
||||
|
||||
if (CurTok.Tok != TOK_LCURLY) {
|
||||
/* Just a forward declaration. */
|
||||
return StructOrUnionForwardDecl (Name, SC_STRUCT);
|
||||
return ESUForwardDecl (Name, SC_STRUCT);
|
||||
}
|
||||
|
||||
/* Add a forward declaration for the struct in the current lexical level */
|
||||
@ -1069,29 +1218,23 @@ static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers)
|
||||
|
||||
case TOK_ENUM:
|
||||
NextToken ();
|
||||
if (CurTok.Tok != TOK_LCURLY) {
|
||||
/* Named enum */
|
||||
if (CurTok.Tok == TOK_IDENT) {
|
||||
/* Find an entry with this name */
|
||||
Entry = FindTagSym (CurTok.Ident);
|
||||
if (Entry) {
|
||||
if (SymIsLocal (Entry) && (Entry->Flags & SC_ENUM) == 0) {
|
||||
Error ("Symbol '%s' is already different kind", Entry->Name);
|
||||
}
|
||||
} else {
|
||||
/* Insert entry into table ### */
|
||||
}
|
||||
/* Skip the identifier */
|
||||
NextToken ();
|
||||
} else {
|
||||
/* Named enum */
|
||||
if (CurTok.Tok == TOK_IDENT) {
|
||||
strcpy (Ident, CurTok.Ident);
|
||||
NextToken ();
|
||||
} else {
|
||||
if (CurTok.Tok != TOK_LCURLY) {
|
||||
Error ("Identifier expected");
|
||||
} else {
|
||||
AnonName (Ident, "enum");
|
||||
}
|
||||
}
|
||||
/* Remember we have an extra type decl */
|
||||
D->Flags |= DS_EXTRA_TYPE;
|
||||
/* Parse the enum decl */
|
||||
ParseEnumDecl ();
|
||||
D->Type[0].C = T_INT;
|
||||
Entry = ParseEnumDecl (Ident);
|
||||
D->Type[0].C |= T_ENUM;
|
||||
SetSymEntry (D->Type, Entry);
|
||||
D->Type[1].C = T_END;
|
||||
break;
|
||||
|
||||
@ -1624,7 +1767,7 @@ void ParseDecl (const DeclSpec* Spec, Declaration* D, declmode_t Mode)
|
||||
/* The return type must not be qualified */
|
||||
if (GetQualifier (RetType) != T_QUAL_NONE && RetType[1].C == T_END) {
|
||||
|
||||
if (GetType (RetType) == T_TYPE_VOID) {
|
||||
if (GetRawType (RetType) == T_TYPE_VOID) {
|
||||
/* A qualified void type is always an error */
|
||||
Error ("function definition has qualified void return type");
|
||||
} else {
|
||||
@ -1916,7 +2059,7 @@ static unsigned ParseArrayInit (Type* T, int AllowFlexibleMembers)
|
||||
long ElementCount = GetElementCount (T);
|
||||
|
||||
/* Special handling for a character array initialized by a literal */
|
||||
if (IsTypeChar (ElementType) &&
|
||||
if (IsRawTypeChar (ElementType) &&
|
||||
(CurTok.Tok == TOK_SCONST || CurTok.Tok == TOK_WCSCONST ||
|
||||
(CurTok.Tok == TOK_LCURLY &&
|
||||
(NextTok.Tok == TOK_SCONST || NextTok.Tok == TOK_WCSCONST)))) {
|
||||
@ -2180,7 +2323,7 @@ static unsigned ParseVoidInit (Type* T)
|
||||
Size = 0;
|
||||
do {
|
||||
ConstExpr (hie1, &Expr);
|
||||
switch (UnqualifiedType (Expr.Type[0].C)) {
|
||||
switch (GetUnderlyingTypeCode (&Expr.Type[0])) {
|
||||
|
||||
case T_SCHAR:
|
||||
case T_UCHAR:
|
||||
@ -2244,7 +2387,7 @@ static unsigned ParseVoidInit (Type* T)
|
||||
static unsigned ParseInitInternal (Type* T, int AllowFlexibleMembers)
|
||||
/* Parse initialization of variables. Return the number of data bytes. */
|
||||
{
|
||||
switch (UnqualifiedType (T->C)) {
|
||||
switch (GetUnderlyingTypeCode (T)) {
|
||||
|
||||
case T_SCHAR:
|
||||
case T_UCHAR:
|
||||
|
@ -452,7 +452,7 @@ void NewFunc (SymEntry* Func)
|
||||
/* Determine if this is a main function in a C99 environment that
|
||||
** returns an int.
|
||||
*/
|
||||
if (IsTypeInt (F_GetReturnType (CurrentFunc)) &&
|
||||
if (IsRawTypeInt (F_GetReturnType (CurrentFunc)) &&
|
||||
IS_Get (&Standard) == STD_C99) {
|
||||
C99MainFunc = 1;
|
||||
}
|
||||
|
@ -132,7 +132,7 @@ void SwitchStatement (void)
|
||||
|
||||
/* Setup the control structure, save the old and activate the new one */
|
||||
SwitchData.Nodes = NewCollection ();
|
||||
SwitchData.ExprType = UnqualifiedType (SwitchExpr.Type[0].C);
|
||||
SwitchData.ExprType = GetUnderlyingTypeCode (&SwitchExpr.Type[0]);
|
||||
SwitchData.Depth = SizeOf (SwitchExpr.Type);
|
||||
SwitchData.DefaultLabel = 0;
|
||||
OldSwitch = Switch;
|
||||
|
@ -165,6 +165,12 @@ struct SymEntry {
|
||||
unsigned Size; /* Size of the union/struct */
|
||||
} S;
|
||||
|
||||
/* Data for enums */
|
||||
struct {
|
||||
struct SymTable* SymTab; /* Member symbol table */
|
||||
const Type* Type; /* Underlying type */
|
||||
} E;
|
||||
|
||||
/* Data for bit fields */
|
||||
struct {
|
||||
unsigned Offs; /* Byte offset into struct */
|
||||
|
@ -551,6 +551,50 @@ static void AddSymEntry (SymTable* T, SymEntry* S)
|
||||
|
||||
|
||||
|
||||
SymEntry* AddEnumSym (const char* Name, const Type* Type, SymTable* Tab)
|
||||
/* Add an enum entry and return it */
|
||||
{
|
||||
/* Do we have an entry with this name already? */
|
||||
SymEntry* Entry = FindSymInTable (TagTab, Name, HashStr (Name));
|
||||
if (Entry) {
|
||||
|
||||
/* We do have an entry. This may be a forward, so check it. */
|
||||
if ((Entry->Flags & SC_TYPEMASK) != SC_ENUM) {
|
||||
/* Existing symbol is not an enum */
|
||||
Error ("Symbol '%s' is already different kind", Name);
|
||||
} else {
|
||||
/* Define the struct size if the underlying type is given. */
|
||||
if (Type != 0) {
|
||||
if (Type !=0 && Entry->V.E.Type != 0) {
|
||||
/* Both are definitions. */
|
||||
Error ("Multiple definition for enum '%s'", Name);
|
||||
}
|
||||
Entry->Type = 0;
|
||||
Entry->V.E.SymTab = Tab;
|
||||
Entry->V.E.Type = Type;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* Create a new entry */
|
||||
Entry = NewSymEntry (Name, SC_ENUM);
|
||||
|
||||
/* Set the enum type data */
|
||||
Entry->Type = 0;
|
||||
Entry->V.E.SymTab = Tab;
|
||||
Entry->V.E.Type = Type;
|
||||
|
||||
/* Add it to the current table */
|
||||
AddSymEntry (TagTab, Entry);
|
||||
}
|
||||
|
||||
/* Return the entry */
|
||||
return Entry;
|
||||
}
|
||||
|
||||
|
||||
|
||||
SymEntry* AddStructSym (const char* Name, unsigned Type, unsigned Size, SymTable* Tab)
|
||||
/* Add a struct/union entry and return it */
|
||||
{
|
||||
@ -649,10 +693,10 @@ SymEntry* AddConstSym (const char* Name, const Type* T, unsigned Flags, long Val
|
||||
/* Create a new entry */
|
||||
Entry = NewSymEntry (Name, Flags);
|
||||
|
||||
/* Enum values are ints */
|
||||
/* We only have integer constants for now */
|
||||
Entry->Type = TypeDup (T);
|
||||
|
||||
/* Set the enum data */
|
||||
/* Set the constant data */
|
||||
Entry->V.ConstVal = Val;
|
||||
|
||||
/* Add the entry to the symbol table */
|
||||
|
@ -146,6 +146,9 @@ unsigned short FindSPAdjustment (const char* Name);
|
||||
|
||||
|
||||
|
||||
SymEntry* AddEnumSym (const char* Name, const Type* Type, SymTable* Tab);
|
||||
/* Add an enum entry and return it */
|
||||
|
||||
SymEntry* AddStructSym (const char* Name, unsigned Type, unsigned Size, SymTable* Tab);
|
||||
/* Add a struct/union entry and return it */
|
||||
|
||||
|
@ -214,9 +214,9 @@ static void DoCompare (const Type* lhs, const Type* rhs, typecmp_t* Result)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the raw left and right types, signs and qualifiers */
|
||||
LeftType = GetType (lhs);
|
||||
RightType = GetType (rhs);
|
||||
/* Get the left and right types, signs and qualifiers */
|
||||
LeftType = GetUnderlyingTypeCode (lhs);
|
||||
RightType = GetUnderlyingTypeCode (rhs);
|
||||
LeftSign = GetSignedness (lhs);
|
||||
RightSign = GetSignedness (rhs);
|
||||
LeftQual = GetQualifier (lhs);
|
||||
@ -229,7 +229,7 @@ static void DoCompare (const Type* lhs, const Type* rhs, typecmp_t* Result)
|
||||
RightType = T_TYPE_PTR;
|
||||
}
|
||||
|
||||
/* If the raw types are not identical, the types are incompatible */
|
||||
/* If the underlying types are not identical, the types are incompatible */
|
||||
if (LeftType != RightType) {
|
||||
SetResult (Result, TC_INCOMPATIBLE);
|
||||
return;
|
||||
|
Loading…
x
Reference in New Issue
Block a user