Merge pull request #2084 from bbbradsmith/numerical_constant_errors-int
Numerical constant errors and improvements (integer)
This commit is contained in:
@@ -754,6 +754,8 @@ Here is a description of all the command line options:
|
|||||||
Warn about unused function parameters.
|
Warn about unused function parameters.
|
||||||
<tag><tt/unused-var/</tag>
|
<tag><tt/unused-var/</tag>
|
||||||
Warn about unused variables.
|
Warn about unused variables.
|
||||||
|
<tag><tt/const-overflow/</tag>
|
||||||
|
Warn if numerical constant conversion implies overflow. (Disabled by default.)
|
||||||
</descrip>
|
</descrip>
|
||||||
|
|
||||||
The full list of available warning names can be retrieved by using the
|
The full list of available warning names can be retrieved by using the
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ IntStack WarnUnusedLabel = INTSTACK(1); /* - unused labels */
|
|||||||
IntStack WarnUnusedParam = INTSTACK(1); /* - unused parameters */
|
IntStack WarnUnusedParam = INTSTACK(1); /* - unused parameters */
|
||||||
IntStack WarnUnusedVar = INTSTACK(1); /* - unused variables */
|
IntStack WarnUnusedVar = INTSTACK(1); /* - unused variables */
|
||||||
IntStack WarnUnusedFunc = INTSTACK(1); /* - unused functions */
|
IntStack WarnUnusedFunc = INTSTACK(1); /* - unused functions */
|
||||||
|
IntStack WarnConstOverflow = INTSTACK(0); /* - overflow conversion of numerical constants */
|
||||||
|
|
||||||
/* Map the name of a warning to the intstack that holds its state */
|
/* Map the name of a warning to the intstack that holds its state */
|
||||||
typedef struct WarnMapEntry WarnMapEntry;
|
typedef struct WarnMapEntry WarnMapEntry;
|
||||||
@@ -102,6 +103,7 @@ static WarnMapEntry WarnMap[] = {
|
|||||||
{ &WarnUnusedLabel, "unused-label" },
|
{ &WarnUnusedLabel, "unused-label" },
|
||||||
{ &WarnUnusedParam, "unused-param" },
|
{ &WarnUnusedParam, "unused-param" },
|
||||||
{ &WarnUnusedVar, "unused-var" },
|
{ &WarnUnusedVar, "unused-var" },
|
||||||
|
{ &WarnConstOverflow, "const-overflow" },
|
||||||
};
|
};
|
||||||
|
|
||||||
Collection DiagnosticStrBufs;
|
Collection DiagnosticStrBufs;
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ extern IntStack WarnUnusedLabel; /* - unused labels */
|
|||||||
extern IntStack WarnUnusedParam; /* - unused parameters */
|
extern IntStack WarnUnusedParam; /* - unused parameters */
|
||||||
extern IntStack WarnUnusedVar; /* - unused variables */
|
extern IntStack WarnUnusedVar; /* - unused variables */
|
||||||
extern IntStack WarnUnusedFunc; /* - unused functions */
|
extern IntStack WarnUnusedFunc; /* - unused functions */
|
||||||
|
extern IntStack WarnConstOverflow; /* - overflow conversion of numerical constants */
|
||||||
|
|
||||||
/* Forward */
|
/* Forward */
|
||||||
struct StrBuf;
|
struct StrBuf;
|
||||||
|
|||||||
@@ -39,6 +39,8 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
/* common */
|
/* common */
|
||||||
#include "chartype.h"
|
#include "chartype.h"
|
||||||
@@ -151,6 +153,11 @@ static const struct Keyword {
|
|||||||
#define IT_ULONG 0x08
|
#define IT_ULONG 0x08
|
||||||
|
|
||||||
|
|
||||||
|
/* Internal type for numeric constant scanning.
|
||||||
|
** Size must be explicit for cross-platform uniformity.
|
||||||
|
*/
|
||||||
|
typedef uint32_t scan_t;
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* code */
|
/* code */
|
||||||
@@ -521,7 +528,8 @@ static void NumericConst (void)
|
|||||||
int IsFloat;
|
int IsFloat;
|
||||||
char C;
|
char C;
|
||||||
unsigned DigitVal;
|
unsigned DigitVal;
|
||||||
unsigned long IVal; /* Value */
|
scan_t IVal; /* Scanned value. */
|
||||||
|
int Overflow;
|
||||||
|
|
||||||
/* Get the pp-number first, then parse on it */
|
/* Get the pp-number first, then parse on it */
|
||||||
CopyPPNumber (&Src);
|
CopyPPNumber (&Src);
|
||||||
@@ -575,6 +583,7 @@ static void NumericConst (void)
|
|||||||
/* Since we now know the correct base, convert the input into a number */
|
/* Since we now know the correct base, convert the input into a number */
|
||||||
SB_SetIndex (&Src, Index);
|
SB_SetIndex (&Src, Index);
|
||||||
IVal = 0;
|
IVal = 0;
|
||||||
|
Overflow = 0;
|
||||||
while ((C = SB_Peek (&Src)) != '\0' && (Base <= 10 ? IsDigit (C) : IsXDigit (C))) {
|
while ((C = SB_Peek (&Src)) != '\0' && (Base <= 10 ? IsDigit (C) : IsXDigit (C))) {
|
||||||
DigitVal = HexVal (C);
|
DigitVal = HexVal (C);
|
||||||
if (DigitVal >= Base) {
|
if (DigitVal >= Base) {
|
||||||
@@ -582,9 +591,17 @@ static void NumericConst (void)
|
|||||||
SB_Clear (&Src);
|
SB_Clear (&Src);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
IVal = (IVal * Base) + DigitVal;
|
/* Test result of adding digit for overflow. */
|
||||||
|
if (((scan_t)(IVal * Base + DigitVal) / Base) != IVal) {
|
||||||
|
Overflow = 1;
|
||||||
|
}
|
||||||
|
IVal = IVal * Base + DigitVal;
|
||||||
SB_Skip (&Src);
|
SB_Skip (&Src);
|
||||||
}
|
}
|
||||||
|
if (Overflow) {
|
||||||
|
Error ("Numerical constant \"%s\" too large for internal %d-bit representation",
|
||||||
|
SB_GetConstBuf (&Src), (int)(sizeof(IVal)*CHAR_BIT));
|
||||||
|
}
|
||||||
|
|
||||||
/* Distinguish between integer and floating point constants */
|
/* Distinguish between integer and floating point constants */
|
||||||
if (!IsFloat) {
|
if (!IsFloat) {
|
||||||
|
|||||||
@@ -55,7 +55,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void DoConversion (ExprDesc* Expr, const Type* NewType)
|
static void DoConversion (ExprDesc* Expr, const Type* NewType, int Explicit)
|
||||||
/* Emit code to convert the given expression to a new type. */
|
/* Emit code to convert the given expression to a new type. */
|
||||||
{
|
{
|
||||||
const Type* OldType;
|
const Type* OldType;
|
||||||
@@ -128,6 +128,7 @@ static void DoConversion (ExprDesc* Expr, const Type* NewType)
|
|||||||
** internally already represented by a long.
|
** internally already represented by a long.
|
||||||
*/
|
*/
|
||||||
if (NewBits <= OldBits) {
|
if (NewBits <= OldBits) {
|
||||||
|
long OldVal = Expr->IVal;
|
||||||
|
|
||||||
/* Cut the value to the new size */
|
/* Cut the value to the new size */
|
||||||
Expr->IVal &= (0xFFFFFFFFUL >> (32 - NewBits));
|
Expr->IVal &= (0xFFFFFFFFUL >> (32 - NewBits));
|
||||||
@@ -139,6 +140,10 @@ static void DoConversion (ExprDesc* Expr, const Type* NewType)
|
|||||||
Expr->IVal |= shl_l (~0UL, NewBits);
|
Expr->IVal |= shl_l (~0UL, NewBits);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((OldVal != Expr->IVal) && IS_Get (&WarnConstOverflow) && !Explicit) {
|
||||||
|
Warning ("Implicit conversion of constant overflows %d-bit destination", NewBits);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do the integer constant <-> absolute address conversion if necessary */
|
/* Do the integer constant <-> absolute address conversion if necessary */
|
||||||
@@ -283,7 +288,7 @@ void TypeConversion (ExprDesc* Expr, const Type* NewType)
|
|||||||
/* Both types must be complete */
|
/* Both types must be complete */
|
||||||
if (!IsIncompleteESUType (NewType) && !IsIncompleteESUType (Expr->Type)) {
|
if (!IsIncompleteESUType (NewType) && !IsIncompleteESUType (Expr->Type)) {
|
||||||
/* Do the actual conversion */
|
/* Do the actual conversion */
|
||||||
DoConversion (Expr, NewType);
|
DoConversion (Expr, NewType, 0);
|
||||||
} else {
|
} else {
|
||||||
/* We should have already generated error elsewhere so that we
|
/* We should have already generated error elsewhere so that we
|
||||||
** could just silently fail here to avoid excess errors, but to
|
** could just silently fail here to avoid excess errors, but to
|
||||||
@@ -330,7 +335,7 @@ void TypeCast (ExprDesc* Expr)
|
|||||||
ReplaceType (Expr, NewType);
|
ReplaceType (Expr, NewType);
|
||||||
} else if (IsCastType (Expr->Type)) {
|
} else if (IsCastType (Expr->Type)) {
|
||||||
/* Convert the value. The result has always the new type */
|
/* Convert the value. The result has always the new type */
|
||||||
DoConversion (Expr, NewType);
|
DoConversion (Expr, NewType, 1);
|
||||||
} else {
|
} else {
|
||||||
TypeCompatibilityDiagnostic (NewType, Expr->Type, 1,
|
TypeCompatibilityDiagnostic (NewType, Expr->Type, 1,
|
||||||
"Cast to incompatible type '%s' from '%s'");
|
"Cast to incompatible type '%s' from '%s'");
|
||||||
|
|||||||
7
test/err/huge-integer-constant.c
Normal file
7
test/err/huge-integer-constant.c
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
/* too big for internal integer representation */
|
||||||
|
unsigned long huge = 4294967296;
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
20
test/err/integer-const-overflow.c
Normal file
20
test/err/integer-const-overflow.c
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/* Integer constant overflow warnings. */
|
||||||
|
|
||||||
|
/* Warnings as errors. */
|
||||||
|
#pragma warn(error,on)
|
||||||
|
|
||||||
|
/* Warn on const overflow */
|
||||||
|
#pragma warn(const-overflow,on)
|
||||||
|
|
||||||
|
unsigned char a = 256;
|
||||||
|
signed char b = 128;
|
||||||
|
unsigned char c = -129;
|
||||||
|
unsigned short int d = 0x00010000;
|
||||||
|
unsigned short int e = 0x80000000;
|
||||||
|
signed short int f = 32768L;
|
||||||
|
signed short int g = -32769L;
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -20,3 +20,4 @@
|
|||||||
#define SIZEOF_LONG_32BIT
|
#define SIZEOF_LONG_32BIT
|
||||||
#define UNSIGNED_CHARS
|
#define UNSIGNED_CHARS
|
||||||
#define UNSIGNED_BITFIELDS
|
#define UNSIGNED_BITFIELDS
|
||||||
|
#define INTEGER_CONSTANT_MAX_32BIT
|
||||||
|
|||||||
@@ -4,6 +4,14 @@
|
|||||||
!!LICENCE!! own, freely distributeable for non-profit. read CPYRIGHT.LCC
|
!!LICENCE!! own, freely distributeable for non-profit. read CPYRIGHT.LCC
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* INTEGER_CONSTANT_MAX_32BIT
|
||||||
|
** This suppresses constants longer than 32-bit, which are now an error:
|
||||||
|
** https://github.com/cc65/cc65/pull/2084
|
||||||
|
** Because cc65's internal representation is implicitly/explicitly
|
||||||
|
** 32-bit in many places, values larger than this aren't representable,
|
||||||
|
** but also can't be checked for overflow once accepted.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
struct defs {
|
struct defs {
|
||||||
@@ -62,7 +70,12 @@ long pow2(long n) {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
long d[39], o[39], x[39];
|
#ifndef INTEGER_CONSTANT_MAX_32BIT
|
||||||
|
#define CTCOUNT 39
|
||||||
|
#else
|
||||||
|
#define CTCOUNT 36
|
||||||
|
#endif
|
||||||
|
long d[CTCOUNT], o[CTCOUNT], x[CTCOUNT];
|
||||||
|
|
||||||
#ifndef NO_OLD_FUNC_DECL
|
#ifndef NO_OLD_FUNC_DECL
|
||||||
s241(pd0)
|
s241(pd0)
|
||||||
@@ -212,13 +225,15 @@ int s241(struct defs *pd0) {
|
|||||||
d[33] = 1073741823; o[33] = 07777777777; x[33] = 0x3fffffff;
|
d[33] = 1073741823; o[33] = 07777777777; x[33] = 0x3fffffff;
|
||||||
d[34] = 1073741824; o[34] = 010000000000; x[34] = 0x40000000;
|
d[34] = 1073741824; o[34] = 010000000000; x[34] = 0x40000000;
|
||||||
d[35] = 4294967295; o[35] = 037777777777; x[35] = 0xffffffff;
|
d[35] = 4294967295; o[35] = 037777777777; x[35] = 0xffffffff;
|
||||||
|
#if CTCOUNT > 36
|
||||||
d[36] = 4294967296; o[36] = 040000000000; x[36] = 0x100000000;
|
d[36] = 4294967296; o[36] = 040000000000; x[36] = 0x100000000;
|
||||||
d[37] = 68719476735; o[37] = 0777777777777; x[37] = 0xfffffffff;
|
d[37] = 68719476735; o[37] = 0777777777777; x[37] = 0xfffffffff;
|
||||||
d[38] = 68719476736; o[38] = 01000000000000; x[38] = 0x1000000000;
|
d[38] = 68719476736; o[38] = 01000000000000; x[38] = 0x1000000000;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* WHEW! */
|
/* WHEW! */
|
||||||
|
|
||||||
for (j=0; j<39; j++){
|
for (j=0; j<CTCOUNT; j++){
|
||||||
if ( g[j] != d[j]
|
if ( g[j] != d[j]
|
||||||
|| d[j] != o[j]
|
|| d[j] != o[j]
|
||||||
|| o[j] != x[j]) {
|
|| o[j] != x[j]) {
|
||||||
|
|||||||
Reference in New Issue
Block a user