Improved type conversion diagnostic messages.

Allowed incompatible pointer assignments with warnings.
Fixed Issue #1089.
This commit is contained in:
acqn
2020-08-02 21:51:32 +08:00
committed by Oliver Schmidt
parent d841bbe498
commit 003d47cc8b
4 changed files with 82 additions and 32 deletions

View File

@@ -78,7 +78,8 @@ static int CopyStruct (ExprDesc* LExpr, ExprDesc* RExpr)
/* Check for equality of the structs */ /* Check for equality of the structs */
if (TypeCmp (ltype, RExpr->Type) < TC_STRICT_COMPATIBLE) { 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? */ /* Do we copy using the primary? */

View File

@@ -2242,7 +2242,8 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */
/* Make sure, the types are compatible */ /* Make sure, the types are compatible */
if (IsClassInt (Expr->Type)) { if (IsClassInt (Expr->Type)) {
if (!IsClassInt (Expr2.Type) && !(IsClassPtr(Expr2.Type) && ED_IsNullPtr(Expr))) { 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)) { } else if (IsClassPtr (Expr->Type)) {
if (IsClassPtr (Expr2.Type)) { if (IsClassPtr (Expr2.Type)) {
@@ -2253,10 +2254,12 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */
Type* right = Indirect (Expr2.Type); Type* right = Indirect (Expr2.Type);
if (TypeCmp (left, right) < TC_QUAL_DIFF && left->C != T_VOID && right->C != T_VOID) { if (TypeCmp (left, right) < TC_QUAL_DIFF && left->C != T_VOID && right->C != T_VOID) {
/* Incompatible pointers */ /* Incompatible pointers */
Error ("Incompatible types"); TypeCompatibilityDiagnostic (Expr->Type, Expr2.Type, 1,
"Incompatible pointer types comparing '%s' with '%s'");
} }
} else if (!ED_IsNullPtr (&Expr2)) { } 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 */ /* Result type is void */
ResultType = Expr3.Type; ResultType = Expr3.Type;
} else { } else {
Error ("Incompatible types"); TypeCompatibilityDiagnostic (Expr2.Type, Expr3.Type, 1,
"Incompatible types in ternary '%s' with '%s'");
ResultType = Expr2.Type; /* Doesn't matter here */ ResultType = Expr2.Type; /* Doesn't matter here */
} }

View File

@@ -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) 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. */
{ {
@@ -189,6 +207,11 @@ void TypeConversion (ExprDesc* Expr, Type* NewType)
printf ("\n"); printf ("\n");
PrintRawType (stdout, NewType); PrintRawType (stdout, NewType);
#endif #endif
int HasWarning = 0;
int HasError = 0;
const char* Msg = 0;
const Type* OldType = Expr->Type;
/* First, do some type checking */ /* First, do some type checking */
if (IsTypeVoid (NewType) || IsTypeVoid (Expr->Type)) { 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 Expr is a function, convert it to pointer to function */
if (IsTypeFunc(Expr->Type)) { if (IsTypeFunc (Expr->Type)) {
Expr->Type = PointerTo (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"); Warning ("Converting pointer to integer without a cast");
} else if (!IsClassInt (Expr->Type) && !IsClassFloat (Expr->Type)) { } else if (!IsClassInt (Expr->Type) && !IsClassFloat (Expr->Type)) {
Error ("Incompatible types"); HasError = 1;
} }
} else if (IsClassFloat (NewType)) { } else if (IsClassFloat (NewType)) {
if (!IsClassFloat (Expr->Type) && !IsClassInt (Expr->Type)) { if (!IsClassFloat (Expr->Type) && !IsClassInt (Expr->Type)) {
Error ("Incompatible types"); HasError = 1;
} }
} else if (IsClassPtr (NewType)) { } else if (IsClassPtr (NewType)) {
/* Handle conversions to pointer type */ /* Handle conversions to pointer type */
@@ -248,17 +268,19 @@ void TypeConversion (ExprDesc* Expr, Type* NewType)
/* Compare the types */ /* Compare the types */
switch (TypeCmp (NewType, Expr->Type)) { switch (TypeCmp (NewType, Expr->Type)) {
case TC_INCOMPATIBLE: case TC_INCOMPATIBLE:
Error ("Incompatible pointer types at '%s'", (Expr->Sym? Expr->Sym->Name : "Unknown")); HasWarning = 1;
break; Msg = "Incompatible pointer assignment to '%s' from '%s'";
break;
case TC_QUAL_DIFF: case TC_QUAL_DIFF:
Error ("Pointer types differ in type qualifiers"); HasWarning = 1;
break; Msg = "Pointer assignment to '%s' from '%s' discards qualifiers";
break;
default: default:
/* Ok */ /* Ok */
break; break;
} }
} }
@@ -268,18 +290,28 @@ void TypeConversion (ExprDesc* Expr, Type* NewType)
Warning ("Converting integer to pointer without a cast"); Warning ("Converting integer to pointer without a cast");
} }
} else { } else {
Error ("Incompatible types"); HasError = 1;
} }
} else { } else {
/* Invalid automatic conversion */
/* Invalid automatic conversion */ HasError = 1;
Error ("Incompatible types");
} }
/* Do the actual conversion */ if (Msg == 0) {
DoConversion (Expr, NewType); 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 */ /* Read the expression we have to cast */
hie10 (Expr); hie10 (Expr);
/* Convert functions and arrays to "pointer to" object */ /* Only allow casts to arithmetic or pointer types, or just changing the
Expr->Type = PtrConversion (Expr->Type); ** qualifiers.
*/
/* Convert the value. */ if (TypeCmp (NewType, Expr->Type) >= TC_QUAL_DIFF) {
DoConversion (Expr, NewType); /* 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));
}
} }

View File

@@ -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); void TypeConversion (ExprDesc* Expr, 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