7. Discard Analysis
- 7.1. Discarded function returns
- 7.2. Discarded computed values
- 7.3. Unused static variables and procedures
- 7.4. Discarded expressions
- 7.5. Overriding the discard analysis
A couple of examples of what might be termed discard analysis
have already been described - discarded (unused) local variables and discarded (unused) assignments to local variables (see section 5.6.4 and 5.6.5). The checker can perform three more types of discard analysis: discarded function returns, discarded computations and unused static variables and procedures. These three tests may be controlled as a group using:
#pragma TenDRA discard analysis status
where status is on
, warning
or off
.
In addition, each of the component tests may be switched on and off independently using pragmas of the form:
#pragma TenDRA discard analysis (function return) status #pragma TenDRA discard analysis (value) status #pragma TenDRA discard analysis (static) status
There are also equivalent command line options to tcc of the form -X:test=state
, where test can be discard_all
, discard_func_ret
, discard_value
or unused_static
, and state can be check
, warn
or dont
. These checks are all switched off in the default mode.
Detailed descriptions of the individual checks follow in sections 5.8.1 - 5.8.3. Section 5.9 describes the facilities for fine-tuning the discard analysis.
7.1. Discarded function returns
Functions which return a value which is not used form the commonest instances of discarded values. For example, in:
#include <stdio.h> int main () { puts ( "hello" ); return ( 0 ); }
the function, puts
, returns an int
value, indicating whether an error has occurred, which is ignored.
7.2. Discarded computed values
A rarer instance of a discarded object, and one which is almost always an error, is where a value is computed but not used. For example, in:
int f ( int n ) { int r = 4; if ( n == 3 ) { r == 5; } return ( r ); }
the value r == 5
is computed but not used. This is actually because it is a misprint for r = 5
.
7.3. Unused static variables and procedures
The final example of discarded values, which perhaps more properly belongs with the variable analysis tests mentioned above, is for static objects which are unused in the source module in which they are defined. Of course this means that they are unused in the entire program. Such objects can usually be removed.
7.4. Discarded expressions
The directive:
#pragma TenDRA discard analysis on
can be used to enable a check for values which are calculated but not used. There are three checks controlled by this directive, each of which can be controlled independently. The directive:
#pragma TenDRA discard analysis (function return) on
checks for functions which return a value which is not used. The check needs to be enabled for both the declaration and the call of the function in order for a discarded function return to be reported. Discarded returns for overloaded operator functions are never reported. The directive:
#pragma TenDRA discard analysis (value) on
checks for other expressions which are not used. Finally, the directive:
#pragma TenDRA discard analysis (static) on
checks for variables with internal linkage which are defined but not used.
An unused function return or other expression can be asserted to be deliberately discarded by explicitly casting it to void
or, equivalently, preceding it by a keyword introduced using the directive:
#pragma TenDRA keyword identifier for discard value
A static variable can be asserted to be deliberately unused by including it in list of identifiers in a directive of the form:
#pragma TenDRA suspend static identifier-list
7.5. Overriding the discard analysis
As with the variable analysis, certain constructs may be used to provide the checker with extra information about a program, to convey the programmer's intentions more clearly.
7.5.1. Discarding function returns and computed values
Unwanted function returns and, more rarely, discarded computed values, may be actively ignored to indicate to the discard analysis that the value is being discarded deliberately. This can be done using the traditional method of casting the value to void
:
( void ) puts ( "hello" );
or by introducing a keyword, IGNORE
say, for discarding a value. This is done using a pragma of the form:
#pragma TenDRA keyword IGNORE for discard value
The example discarded value then becomes:
IGNORE puts ( "hello" );
Of course it is necessary to introduce a definition of IGNORE
for conventional compilers in order to maintain compilability. A suitable definition might be:
#ifdef __TenDRA__ #pragma TenDRA keyword IGNORE for discard value #else #define IGNORE ( void ) #endif
7.5.2. Preserving unused statics
Occasionally unused static values are introduced deliberately into programs. The fact that the static variables or procedures x
, y
and z
are deliberately unused may be indicated by introducing the pragma:
#pragma TenDRA suspend static x y z
at the outer level after the definition of all three objects.