7. Discard Analysis

  1. 7.1. Discarded function returns
  2. 7.2. Discarded computed values
  3. 7.3. Unused static variables and procedures
  4. 7.4. Discarded expressions
  5. 7.5. Overriding the discard analysis
    1. 7.5.1. Discarding function returns and computed values
    2. 7.5.2. Preserving unused statics

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.