From 003d47cc8b661cfb8dcfd89ae02eb7e7022e0196 Mon Sep 17 00:00:00 2001 From: acqn Date: Sun, 2 Aug 2020 21:51:32 +0800 Subject: [PATCH] Improved type conversion diagnostic messages. Allowed incompatible pointer assignments with warnings. Fixed Issue #1089. --- src/cc65/assignment.c | 3 +- src/cc65/expr.c | 12 ++++-- src/cc65/typeconv.c | 96 +++++++++++++++++++++++++++++++------------ src/cc65/typeconv.h | 3 ++ 4 files changed, 82 insertions(+), 32 deletions(-) diff --git a/src/cc65/assignment.c b/src/cc65/assignment.c index ed374ef8a..c67ac1ce5 100644 --- a/src/cc65/assignment.c +++ b/src/cc65/assignment.c @@ -78,7 +78,8 @@ static int CopyStruct (ExprDesc* LExpr, ExprDesc* RExpr) /* Check for equality of the structs */ if (TypeCmp (ltype, RExpr->Type) < TC_STRICT_COMPATIBLE) { - Error ("Incompatible types"); + TypeCompatibilityDiagnostic (ltype, RExpr->Type, 1, + "Incompatible types in assignment to '%s' from '%s'"); } /* Do we copy using the primary? */ diff --git a/src/cc65/expr.c b/src/cc65/expr.c index 1d123ce9b..a99f17b55 100644 --- a/src/cc65/expr.c +++ b/src/cc65/expr.c @@ -2242,7 +2242,8 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ /* Make sure, the types are compatible */ if (IsClassInt (Expr->Type)) { if (!IsClassInt (Expr2.Type) && !(IsClassPtr(Expr2.Type) && ED_IsNullPtr(Expr))) { - Error ("Incompatible types"); + TypeCompatibilityDiagnostic (Expr->Type, Expr2.Type, 1, + "Incompatible types comparing '%s' with '%s'"); } } else if (IsClassPtr (Expr->Type)) { if (IsClassPtr (Expr2.Type)) { @@ -2253,10 +2254,12 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ Type* right = Indirect (Expr2.Type); if (TypeCmp (left, right) < TC_QUAL_DIFF && left->C != T_VOID && right->C != T_VOID) { /* Incompatible pointers */ - Error ("Incompatible types"); + TypeCompatibilityDiagnostic (Expr->Type, Expr2.Type, 1, + "Incompatible pointer types comparing '%s' with '%s'"); } } else if (!ED_IsNullPtr (&Expr2)) { - Error ("Incompatible types"); + TypeCompatibilityDiagnostic (Expr->Type, Expr2.Type, 1, + "Comparing pointer type '%s' with '%s'"); } } @@ -3324,7 +3327,8 @@ static void hieQuest (ExprDesc* Expr) /* Result type is void */ ResultType = Expr3.Type; } else { - Error ("Incompatible types"); + TypeCompatibilityDiagnostic (Expr2.Type, Expr3.Type, 1, + "Incompatible types in ternary '%s' with '%s'"); ResultType = Expr2.Type; /* Doesn't matter here */ } diff --git a/src/cc65/typeconv.c b/src/cc65/typeconv.c index e915d7392..c3c1a2528 100644 --- a/src/cc65/typeconv.c +++ b/src/cc65/typeconv.c @@ -55,6 +55,24 @@ +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. */ { @@ -189,6 +207,11 @@ void TypeConversion (ExprDesc* Expr, Type* NewType) printf ("\n"); PrintRawType (stdout, NewType); #endif + int HasWarning = 0; + int HasError = 0; + const char* Msg = 0; + const Type* OldType = Expr->Type; + /* First, do some type checking */ if (IsTypeVoid (NewType) || IsTypeVoid (Expr->Type)) { @@ -199,7 +222,7 @@ void TypeConversion (ExprDesc* Expr, Type* NewType) } /* If Expr is a function, convert it to pointer to function */ - if (IsTypeFunc(Expr->Type)) { + if (IsTypeFunc (Expr->Type)) { Expr->Type = PointerTo (Expr->Type); } @@ -220,15 +243,12 @@ void TypeConversion (ExprDesc* Expr, Type* NewType) } Warning ("Converting pointer to integer without a cast"); } else if (!IsClassInt (Expr->Type) && !IsClassFloat (Expr->Type)) { - Error ("Incompatible types"); + HasError = 1; } - } else if (IsClassFloat (NewType)) { - if (!IsClassFloat (Expr->Type) && !IsClassInt (Expr->Type)) { - Error ("Incompatible types"); + HasError = 1; } - } else if (IsClassPtr (NewType)) { /* Handle conversions to pointer type */ @@ -248,17 +268,19 @@ void TypeConversion (ExprDesc* Expr, Type* NewType) /* Compare the types */ switch (TypeCmp (NewType, Expr->Type)) { - case TC_INCOMPATIBLE: - Error ("Incompatible pointer types at '%s'", (Expr->Sym? Expr->Sym->Name : "Unknown")); - break; + case TC_INCOMPATIBLE: + HasWarning = 1; + Msg = "Incompatible pointer assignment to '%s' from '%s'"; + break; - case TC_QUAL_DIFF: - Error ("Pointer types differ in type qualifiers"); - break; + case TC_QUAL_DIFF: + HasWarning = 1; + Msg = "Pointer assignment to '%s' from '%s' discards qualifiers"; + break; - default: - /* Ok */ - break; + default: + /* Ok */ + break; } } @@ -268,18 +290,28 @@ void TypeConversion (ExprDesc* Expr, Type* NewType) Warning ("Converting integer to pointer without a cast"); } } else { - Error ("Incompatible types"); + HasError = 1; } } else { - - /* Invalid automatic conversion */ - Error ("Incompatible types"); - + /* Invalid automatic conversion */ + HasError = 1; } - /* Do the actual conversion */ - DoConversion (Expr, NewType); + if (Msg == 0) { + Msg = "Converting to '%s' from '%s'"; + } + + if (HasError) { + TypeCompatibilityDiagnostic (NewType, OldType, 1, Msg); + } else { + if (HasWarning) { + TypeCompatibilityDiagnostic (NewType, OldType, 0, Msg); + } + + /* Do the actual conversion */ + DoConversion (Expr, NewType); + } } @@ -301,9 +333,19 @@ void TypeCast (ExprDesc* Expr) /* Read the expression we have to cast */ hie10 (Expr); - /* Convert functions and arrays to "pointer to" object */ - Expr->Type = PtrConversion (Expr->Type); - - /* Convert the value. */ - DoConversion (Expr, NewType); + /* Only allow casts to arithmetic or pointer types, or just changing the + ** qualifiers. + */ + if (TypeCmp (NewType, Expr->Type) >= TC_QUAL_DIFF) { + /* The expression has always the new type */ + ReplaceType (Expr, NewType); + } else if (IsCastType (NewType)) { + /* Convert functions and arrays to "pointer to" object */ + Expr->Type = PtrConversion (Expr->Type); + /* Convert the value */ + DoConversion (Expr, NewType); + } else { + Error ("Arithmetic or pointer type expected but '%s' is used", + GetFullTypeName (NewType)); + } } diff --git a/src/cc65/typeconv.h b/src/cc65/typeconv.h index 8321aded4..5c94069a3 100644 --- a/src/cc65/typeconv.h +++ b/src/cc65/typeconv.h @@ -49,6 +49,9 @@ +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, 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