From 245dd0a3f44202e3d8cff1273c0ea942caadcba6 Mon Sep 17 00:00:00 2001 From: Stephen Heumann Date: Tue, 3 Jan 2023 18:56:46 -0600 Subject: [PATCH] Add lint check for implicit conversions that change a constant's value. This occurs when the constant value is out of range of the type being assigned to. This is likely indicative of an error, or of code that assumes types have larger ranges than they do in ORCA/C (e.g. 32-bit int). This intentionally does not report cases where a value is assigned to a signed type but is within the range of the corresponding unsigned type, or vice versa. These may be done intentionally, e.g. setting an unsigned value to "-1" or setting a signed value using a hex constant with the high bit set. Also, only conversions to 8-bit or 16-bit integer types are currently checked. --- CC.rez | 2 +- CCommon.pas | 1 + Expression.pas | 41 +++++++++++++++++++++++++++++++++++++++++ Scanner.pas | 5 +++-- cc.notes | 4 ++++ 5 files changed, 50 insertions(+), 3 deletions(-) diff --git a/CC.rez b/CC.rez index 3c02b36..543aa4d 100644 --- a/CC.rez +++ b/CC.rez @@ -11,5 +11,5 @@ resource rVersion(1) { verUS, /* Region code */ "ORCA/C", /* Short version number */ "Copyright 1997, Byte Works, Inc.\n" /* Long version number */ - "Updated 2022" + "Updated 2023" }; diff --git a/CCommon.pas b/CCommon.pas index 0a00b22..c9292dd 100644 --- a/CCommon.pas +++ b/CCommon.pas @@ -95,6 +95,7 @@ const lintC99Syntax = $0040; {check for syntax that C99 disallows} lintReturn = $0080; {flag issues with how functions return} lintUnused = $0100; {check for unused variables} + lintConstantRange = $0200; {check for out-of-range constants} {bit masks for GetLInfo flags} {----------------------------} diff --git a/Expression.pas b/Expression.pas index d29b06e..3bec4e3 100644 --- a/Expression.pas +++ b/Expression.pas @@ -610,6 +610,41 @@ var baseType1,baseType2: baseTypeEnum; {temp variables (for speed)} kind1,kind2: typeKind; {temp variables (for speed)} + + procedure CheckConstantRange(t1: typePtr; value: longint); + + { Check for situations where an implicit conversion will } + { change the value of a constant. } + { } + { Note: This currently only addresses conversions to 8-bit } + { or 16-bit integer types, and intentionally does not } + { distinguish between signed and unsigned types. } + + var + min,max: longint; {min/max allowed values} + + begin {CheckConstantRange} + if t1^.cType = ctBool then begin + min := 0; + max := 1; + end {if} + else if t1^.baseType in [cgByte,cgUByte] then begin + min := -128; + max := 255; + end {else if} + else if t1^.baseType in [cgWord,cgUWord] then begin + min := -32768; + max := 65536; + end {else if} + else begin + min := -maxint4-1; + max := maxint4; + end; {else} + if (value < min) or (value > max) then + Error(186); + end; {CheckConstantRange} + + begin {AssignmentConversion} kind1 := t1^.kind; kind2 := t2^.kind; @@ -630,6 +665,9 @@ else if kind2 in case kind1 of scalarType: begin + if ((lint & lintConstantRange) <> 0) then + if isConstant then + CheckConstantRange(t1, value); baseType1 := t1^.baseType; if baseType1 in [cgReal,cgDouble,cgComp] then baseType1 := cgExtended; @@ -701,6 +739,9 @@ else if kind2 in enumType: begin if kind2 = scalarType then begin + if ((lint & lintConstantRange) <> 0) then + if isConstant then + CheckConstantRange(intPtr, value); baseType2 := t2^.baseType; if baseType2 in [cgString,cgVoid] then Error(47) diff --git a/Scanner.pas b/Scanner.pas index 4fab662..26060e9 100644 --- a/Scanner.pas +++ b/Scanner.pas @@ -202,7 +202,7 @@ const {----} defaultName = '13:ORCACDefs:Defaults.h'; {default include file name} maxErr = 10; {max errors on one line} - maxLint = 185; {maximum lint error code} + maxLint = 186; {maximum lint error code} type errorType = record {record of a single error} @@ -801,6 +801,7 @@ if list or (numErr <> 0) then begin 183: msg := @'array index out of bounds'; 184: msg := @'segment exceeds bank size'; 185: msg := @'lint: unused variable: '; + 186: msg := @'lint: implicit conversion changes value of constant'; otherwise: Error(57); end; {case} if extraStr <> nil then begin @@ -4530,7 +4531,7 @@ strictMode := false; {...with extensions} {error codes for lint messages} {if changed, also change maxLint} lintErrors := - [51,104,105,110,124,125,128,129,130,147,151,152,153,154,155,170,185]; + [51,104,105,110,124,125,128,129,130,147,151,152,153,154,155,170,185,186]; spaceStr := ' '; {strings used in stringization} quoteStr := '"'; diff --git a/cc.notes b/cc.notes index 8adb1ad..64b4ad5 100644 --- a/cc.notes +++ b/cc.notes @@ -761,6 +761,10 @@ If #pragma lint bit 7 (a value of 128) is set, ORCA/C detects some situations wh If #pragma lint bit 8 (a value of 256) is set, ORCA/C checks for variables that are declared but never subsequently used. This covers local variables in functions, as well as file-scope static variables. +* Checking for implicit conversions that change the value of a constant: + +If #pragma lint bit 9 (a value of 512) is set, ORCA/C checks for certain situations where an implicit conversion will change the value of a constant. Implicit conversions occur in assignments, where the value of the expression is converted to the type of the location being assigned to. They also occur in some related situations like initializers and return statements. This lint check identifies cases where a constant is used in such a situation, but its value is outside the range of the type it is converted to, and therefore the value will be changed by the implicit conversion. This may be indicative of a programming error, or of code written with the assumption that types have larger ranges than they do in ORCA/C. This check currently only identifies cases where out-of-range integer values are converted to an 8-bit or 16-bit integer type. + #pragma extensions ------------------