From 4a3896538409ec6a186bbabbd3f94e9dec7e70b4 Mon Sep 17 00:00:00 2001 From: acqn Date: Thu, 25 Mar 2021 13:32:46 +0800 Subject: [PATCH] Warnings on discarding pointer qualifiers always. Added new -W options to turn on/off warnings on certain pointer conversion cases: - pointer-sign: to a pointer type differing in pointee signedness. Default on. - pointer-types: to a pointer type incompatible. Default on. --- src/cc65/error.c | 4 ++++ src/cc65/error.h | 2 ++ src/cc65/typecmp.c | 8 ++++++++ src/cc65/typecmp.h | 1 + src/cc65/typeconv.c | 38 +++++++++++++++++++++----------------- 5 files changed, 36 insertions(+), 17 deletions(-) diff --git a/src/cc65/error.c b/src/cc65/error.c index feb43565d..ec665b319 100644 --- a/src/cc65/error.c +++ b/src/cc65/error.c @@ -68,6 +68,8 @@ IntStack WarningsAreErrors = INTSTACK(0); /* Treat warnings as errors */ /* Warn about: */ IntStack WarnConstComparison= INTSTACK(1); /* - constant comparison results */ IntStack WarnNoEffect = INTSTACK(1); /* - statements without an effect */ +IntStack WarnPointerSign = INTSTACK(1); /* - pointer conversion to pointer differing in signedness */ +IntStack WarnPointerTypes = INTSTACK(1); /* - pointer conversion to incompatible pointer type */ IntStack WarnRemapZero = INTSTACK(1); /* - remapping character code zero */ IntStack WarnStructParam = INTSTACK(0); /* - structs passed by val */ IntStack WarnUnknownPragma = INTSTACK(1); /* - unknown #pragmas */ @@ -87,6 +89,8 @@ static WarnMapEntry WarnMap[] = { { &WarnConstComparison, "const-comparison" }, { &WarningsAreErrors, "error" }, { &WarnNoEffect, "no-effect" }, + { &WarnPointerSign, "pointer-sign" }, + { &WarnPointerTypes, "pointer-types" }, { &WarnRemapZero, "remap-zero" }, { &WarnStructParam, "struct-param" }, { &WarnUnknownPragma, "unknown-pragma" }, diff --git a/src/cc65/error.h b/src/cc65/error.h index 898793651..a7592b366 100644 --- a/src/cc65/error.h +++ b/src/cc65/error.h @@ -64,6 +64,8 @@ extern IntStack WarnEnable; /* Enable warnings */ extern IntStack WarningsAreErrors; /* Treat warnings as errors */ /* Warn about: */ extern IntStack WarnConstComparison; /* - constant comparison results */ +extern IntStack WarnPointerSign; /* - pointer conversion to pointer differing in signedness */ +extern IntStack WarnPointerTypes; /* - pointer conversion to incompatible pointer type */ extern IntStack WarnNoEffect; /* - statements without an effect */ extern IntStack WarnRemapZero; /* - remapping character code zero */ extern IntStack WarnStructParam; /* - structs passed by val */ diff --git a/src/cc65/typecmp.c b/src/cc65/typecmp.c index 7aae7fefe..567ab4e87 100644 --- a/src/cc65/typecmp.c +++ b/src/cc65/typecmp.c @@ -143,6 +143,7 @@ static void SetResult (typecmp_t* Result, typecmpcode_t Val) if (Val < Result->C) { if (Result->Indirections > 0) { if (Val >= TC_STRICT_COMPATIBLE) { + /* Arrays etc. */ Result->C = Val; } else if (Result->Indirections == 1) { /* C Standard allows implicit conversion as long as one side is @@ -150,10 +151,17 @@ static void SetResult (typecmp_t* Result, typecmpcode_t Val) */ if ((Result->F & TCF_MASK_VOID_PTR) != 0) { Result->C = TC_VOID_PTR; + } else if (Val == TC_SIGN_DIFF) { + /* Special treatment with pointee signedness difference */ + Result->C = TC_PTR_SIGN_DIFF; } else { + /* Incompatible */ Result->C = TC_PTR_INCOMPATIBLE; } } else { + /* Pointer-to-pointer types must have compatible pointte types, + ** or they are just incompatible. + */ Result->C = TC_PTR_INCOMPATIBLE; } } else { diff --git a/src/cc65/typecmp.h b/src/cc65/typecmp.h index e1ca699cf..367df5245 100644 --- a/src/cc65/typecmp.h +++ b/src/cc65/typecmp.h @@ -52,6 +52,7 @@ typedef enum { TC_INCOMPATIBLE, /* Distinct types */ TC_SIGN_DIFF, /* Signedness differs */ + TC_PTR_SIGN_DIFF, /* Pointee signedness differs */ TC_PTR_INCOMPATIBLE, /* Distinct pointer types */ TC_VOID_PTR, /* Non-void and void pointers */ TC_STRICT_COMPATIBLE, /* Strict compatibility according to the C Standard */ diff --git a/src/cc65/typeconv.c b/src/cc65/typeconv.c index d75d13cd1..91a1f022d 100644 --- a/src/cc65/typeconv.c +++ b/src/cc65/typeconv.c @@ -190,7 +190,6 @@ void TypeConversion (ExprDesc* Expr, const Type* NewType) #endif /* First, do some type checking */ typecmp_t Result = TYPECMP_INITIALIZER; - int HasWarning = 0; int HasError = 0; const char* Msg = 0; const Type* OldType = Expr->Type; @@ -232,19 +231,28 @@ void TypeConversion (ExprDesc* Expr, const Type* NewType) ** - both point to the same types, or ** - the rhs pointer is a void pointer, or ** - the lhs pointer is a void pointer. + ** Note: We additionally allow converting function pointers to and from + ** void pointers, just with warnings. */ - if (Result.C <= TC_PTR_INCOMPATIBLE || - (Result.F & TCF_INCOMPATIBLE_QUAL) != 0) - { - HasWarning = 1; - Msg = "Incompatible pointer conversion to '%s' from '%s'"; - /* Use the pointer type in the diagnostic */ - OldType = Expr->Type; - } else if ((Result.F & TCF_PTR_QUAL_DIFF) != 0) { - HasWarning = 1; - Msg = "Pointer conversion to '%s' from '%s' discards qualifiers"; - /* Use the pointer type in the diagnostic */ - OldType = Expr->Type; + if (Result.C == TC_PTR_SIGN_DIFF) { + /* Specific warning for pointee signedness difference */ + if (IS_Get (&WarnPointerSign)) { + TypeCompatibilityDiagnostic (NewType, Expr->Type, + 0, "Pointer conversion to '%s' from '%s' changes pointee signedness"); + } + } else if ((Result.C <= TC_PTR_INCOMPATIBLE || + (Result.F & TCF_INCOMPATIBLE_QUAL) != 0)) { + /* Incompatible pointee types or qualifiers */ + if (IS_Get (&WarnPointerTypes)) { + TypeCompatibilityDiagnostic (NewType, Expr->Type, + 0, "Incompatible pointer conversion to '%s' from '%s'"); + } + } + + if ((Result.F & TCF_PTR_QUAL_DIFF) != 0) { + /* Discarding qualifiers is a bad thing and we always warn */ + TypeCompatibilityDiagnostic (NewType, Expr->Type, + 0, "Pointer conversion to '%s' from '%s' discards qualifiers"); } } else if (IsClassInt (Expr->Type)) { @@ -269,10 +277,6 @@ void TypeConversion (ExprDesc* Expr, const Type* NewType) if (HasError) { TypeCompatibilityDiagnostic (NewType, OldType, 1, Msg); } else { - if (HasWarning) { - TypeCompatibilityDiagnostic (NewType, OldType, 0, Msg); - } - /* Both types must be complete */ if (!IsIncompleteESUType (NewType) && !IsIncompleteESUType (Expr->Type)) { /* Do the actual conversion */