Merge pull request #2345 from acqn/PtrFix

[cc65] Fixed regression on comparison to null pointer
This commit is contained in:
Bob Andrews 2024-01-11 16:50:49 +01:00 committed by GitHub
commit 28f892bb3c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 130 additions and 16 deletions

View File

@ -1991,7 +1991,7 @@ void hie10 (ExprDesc* Expr)
if (ED_IsConstAbs (Expr)) {
/* Constant numeric expression */
Expr->IVal = !Expr->IVal;
} else if (ED_IsAddrExpr (Expr)) {
} else if (ED_IsEntityAddr (Expr)) {
/* Address != NULL, so !Address == 0 */
ED_MakeConstBool (Expr, 0);
} else {
@ -2445,8 +2445,8 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */
}
/* Check for numeric constant operands */
if ((ED_IsAddrExpr (Expr) && ED_IsNullPtr (&Expr2)) ||
(ED_IsNullPtr (Expr) && ED_IsAddrExpr (&Expr2))) {
if ((ED_IsEntityAddr (Expr) && ED_IsNullPtr (&Expr2)) ||
(ED_IsNullPtr (Expr) && ED_IsEntityAddr (&Expr2))) {
/* Object addresses are inequal to null pointer */
Expr->IVal = (Tok != TOK_EQ);
@ -2477,8 +2477,8 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */
pop (ltype);
}
} else if (ED_IsAddrExpr (Expr) &&
ED_IsAddrExpr (&Expr2) &&
} else if (ED_IsEntityAddr (Expr) &&
ED_IsEntityAddr (&Expr2) &&
Expr->Sym == Expr2.Sym) {
/* Evaluate the result for static addresses */
@ -3944,10 +3944,10 @@ static void hieQuest (ExprDesc* Expr)
NextToken ();
/* Parse second expression. Remember for later if it is a NULL pointer
** expression, then load it into the primary.
** constant expression, then load it into the primary.
*/
ExprWithCheck (hie0, &Expr2);
Expr2IsNULL = ED_IsNullPtr (&Expr2);
Expr2IsNULL = ED_IsNullPtrConstant (&Expr2);
if (!IsTypeVoid (Expr2.Type) &&
ED_YetToLoad (&Expr2) &&
(!ConstantCond || !ED_IsConst (&Expr2))) {
@ -3991,10 +3991,10 @@ static void hieQuest (ExprDesc* Expr)
ConsumeColon ();
/* Parse third expression. Remember for later if it is a NULL pointer
** expression, then load it into the primary.
** constant expression, then load it into the primary.
*/
ExprWithCheck (hieQuest, &Expr3);
Expr3IsNULL = ED_IsNullPtr (&Expr3);
Expr3IsNULL = ED_IsNullPtrConstant (&Expr3);
if (!IsTypeVoid (Expr3.Type) &&
ED_YetToLoad (&Expr3) &&
(!ConstantCond || !ED_IsConst (&Expr3))) {

View File

@ -255,7 +255,7 @@ int ED_IsConstTrue (const ExprDesc* Expr)
{
/* Non-zero arithmetics and objects addresses are boolean true */
return (ED_IsConstAbsInt (Expr) && Expr->IVal != 0) ||
(ED_IsAddrExpr (Expr));
ED_IsEntityAddr (Expr);
}
@ -331,12 +331,41 @@ int ED_IsZPInd (const ExprDesc* Expr)
int ED_IsNullPtr (const ExprDesc* Expr)
/* Return true if the given expression is a NULL pointer constant */
/* Return true if the given expression is a null pointer.
** Note: A null pointer constant converted to a pointer type is a null pointer.
*/
{
return (Expr->Flags & (E_MASK_LOC|E_MASK_RTYPE)) ==
(E_LOC_NONE|E_RTYPE_RVAL) &&
Expr->IVal == 0 &&
IsClassInt (Expr->Type);
return ED_IsConstAbs (Expr) &&
Expr->IVal == 0 &&
(IsClassInt (Expr->Type) || IsTypePtr (Expr->Type));
}
int ED_IsNullPtrConstant (const ExprDesc* Expr)
/* Return true if the given expression is a null pointer constant.
** Note: An integer constant expression with value 0, or such an
** expression cast to void* is a null pointer constant. However, a
** null pointer constant converted to a pointer type is just a null
** pointer, not necessarily a constant in ISO C.
*/
{
return ED_IsConstAbs (Expr) &&
Expr->IVal == 0 &&
(IsClassInt (Expr->Type) ||
(IsTypePtr (Expr->Type) && IsTypeVoid (Expr->Type + 1) &&
GetQualifier (Expr->Type + 1) == T_QUAL_NONE));
}
int ED_IsEntityAddr (const ExprDesc* Expr)
/* Return true if the expression denotes the address of an object or function.
*/
{
return ED_IsAddrExpr (Expr) &&
Expr->Sym != 0 &&
(IsClassPtr (Expr->Type) || IsTypeFunc (Expr->Type));
}

View File

@ -582,7 +582,21 @@ int ED_IsZPInd (const ExprDesc* Expr);
/* Return true if the expression is located on the zeropage */
int ED_IsNullPtr (const ExprDesc* Expr);
/* Return true if the given expression is a NULL pointer constant */
/* Return true if the given expression is a null pointer.
** Note: A null pointer constant converted to a pointer type is a null pointer.
*/
int ED_IsNullPtrConstant (const ExprDesc* Expr);
/* Return true if the given expression is a null pointer constant.
** Note: An integer constant expression with value 0, or such an
** expression cast to void* is a null pointer constant. However, a
** null pointer constant converted to a pointer type is just a null
** pointer, not necessarily a constant in ISO C.
*/
int ED_IsEntityAddr (const ExprDesc* Expr);
/* Return true if the expression denotes the address of an object or function.
*/
int ED_IsBool (const ExprDesc* Expr);
/* Return true if the expression can be treated as a boolean, that is, it can

71
test/val/nullptr.c Normal file
View File

@ -0,0 +1,71 @@
/* Bug # - Pointer compared to null pointer constant */
#include <stdio.h>
unsigned failures;
struct S {
char a[4];
} *p;
#define TEST_NULL(E) \
do { \
a = (E) == 0 && !(E); \
if (!a) \
{ \
++failures; \
printf("failed: " #E " should be null\n"); \
} \
} while(0);
#define TEST_NON_NULL(E) \
do { \
a = (E) != 0 && !!(E) && (E); \
if (!a) \
{ \
++failures; \
printf("failed: " #E " should be non-null\n"); \
} \
} while(0);
int main()
{
int a;
/* Null pointer constant (per ISO C) compared equal to null pointer constant */
TEST_NULL((void*)0)
/* Null pointer compared equal to null pointer constant */
TEST_NULL((char*)0)
/* Null pointer obtained with -> */
TEST_NULL(((struct S*)0)->a)
/* Null pointer obtained with -> */
TEST_NULL(p->a)
/* Null pointer obtained with cast and -> */
TEST_NULL(((struct S*)(a = 0))->a)
/* Null pointer obtained with cast and -> */
TEST_NULL((a = 0, ((struct S*)a)->a))
/* Non-null pointer obtained with cast and -> */
TEST_NON_NULL(((struct S*)(long)(a = 0x1234))->a)
/* Non-null pointer obtained with cast and -> */
TEST_NON_NULL((a = 0x1234, ((struct S*)a)->a))
/* Non-null pointer obtained with cast and -> */
TEST_NON_NULL(((struct S*)&a)->a)
/* Non-null pointer obtained with cast and -> */
TEST_NON_NULL(((struct S*)&main)->a)
if (failures != 0)
{
printf("failures: %u\n", failures);
}
return failures;
}