7. Configuration for declarations

  1. 7.1. Empty source files
  2. 7.2. Untagged compound types
  3. 7.3. Empty declarations
  4. 7.4. Unifying the tag name space
  5. 7.5. Extra commas
  6. 7.6. Implicit int
  7. 7.7. Implicit function declarations
  8. 7.8. Forward enumeration declarations
  9. 7.9. Variable scope in for statements
  10. 7.10. Anonymous unions

7.1. Empty source files

ISO C requires that a translation unit should contain at least one declaration. C++ and older dialects of C allow translation units which contain no declarations. This behaviour can be controlled using the directive:

#pragma TenDRA no external declaration allow

The ISO standard states that each source file should contain at least one declaration or definition. Source files which contain no external declarations or definitions are flagged as errors by the checker in default mode. The severity of the error may be altered using:

#pragma TenDRA no external declaration permit

where the options for permit are allow (no errors raised), warning or disallow.

7.2. Untagged compound types

ISO C++ requires every declaration or member declaration to introduce one or more names into the program. The directive:

#pragma TenDRA unknown struct/union allow

can be used to relax one particular instance of this rule, by allowing anonymous class definitions (recall that anonymous unions are objects, not types, in C++ and so are not covered by this rule).

The ISO C standard states that a declaration must declare at least a declarator, a tag or the members of an enumeration. The checker detects such declarations and, by default, raises an error. The severity of the errors can be altered by:

#pragma TenDRA unknown struct/union permit

where permit may be allow to allow code such as:

struct {
	int i;
	int j;
};

through without errors (statements such as this occur in some system headers) or disallow to restore the default behaviour.

7.3. Empty declarations

The C++ grammar also allows a solitary semicolon as a declaration or member declaration; however such a declaration does not introduce a name and so contravenes the rule above. The rule can be relaxed in this case using the directive:

#pragma TenDRA extra ; allow

Note that the C++ grammar explicitly allows for an extra semicolon following an inline member function definition, but that semicolons following other function definitions are actually empty declarations of the form above. A solitary semicolon in a statement is interpreted as an empty expression statement rather than an empty declaration statement.

Some dialects of C allow extra semicolons at the external declaration and definition level in contravention of the ISO C standard. For example, the program:

int f ()
{
    return ( 0 );
};

is not ISO compliant. The checker enforces the ISO rules by default, but the errors raised may be reduced to warning or suppressed entirely using:

#pragma TenDRA extra ; permit

with permit as warning or allow. The disallow options restores the default behaviour.

7.4. Unifying the tag name space

Each object in the tag name space is associated with a classification (struct, union or enum) of the type to which it refers. If such a tag is used, it must be preceded by the correct classification, otherwise the checker produces an error by default. However, the pragma:

#pragma TenDRA ignore struct/union/enum tag status

may be used to change the severity of the error. The options for status are: on (allows a tag to be used with any of the three classifications, the correct classification being inferred from the type definition), warning or off.

7.5. Extra commas

The ISO C standard does not allow extra commas in enumeration type declarations e.g.

enum e = { red , orange , yellow , };

The extra comma at the end of the declaration is flagged as an error by default, but this behaviour may be changed by using:

#pragma TenDRA extra , permit

where permit has the usual allow, disallow and warning options.

7.6. Implicit int

The C "implicit int" rule, whereby a type of int is inferred in a list of type or declaration specifiers which does not contain a type name, has been removed in ISO C++, although it was supported in older dialects of C++. This check is controlled by the directive:

#pragma TenDRA++ implicit int type allow

Partial relaxations of this rules are allowed. The directive:

#pragma TenDRA++ implicit int type for const/volatile allow

will allow for implicit int when the list of type specifiers contains a cv-qualifier. Similarly the directive:

#pragma TenDRA implicit int type for function return allow

will allow for implicit int in the return type of a function definition (this excludes constructors, destructors and conversion functions, where special rules apply). A function definition is the only kind of declaration in ISO C where a declaration specifier is not required. Older dialects of C allowed declaration specifiers to be omitted in other cases. Support for this behaviour can be enabled using:

#pragma TenDRA implicit int type for external declaration allow

The four cases can be demonstrated in the following example:

extern a ;	// implicit int
const b = 1 ;	// implicit const int

f ()	// implicit function return
{
	return 2 ;
}

c = 3 ;	// error: not allowed in C++

Older C dialects allow external variables to be specified without a type, the type int being inferred. Thus, for example:

a, b;

is equivalent to:

int a, b;

By default these inferred declarations are not permitted, though tdfc2's behaviour can be modified using:

#pragma TenDRA implicit int type for external declaration permit

where permit is allow, warning or disallow.

A more common feature, allowed by the ISO C standard, but considered bad style by some, is the inference of an int return type for functions defined in the form:

f ( int n )
{
    ....
}

the checker's treatment of such functions can be determined using:

#pragma TenDRA implicit int type for function return permit

where permit can be allow, warning or disallow.

7.7. Implicit function declarations

C, but not C++, allows calls to undeclared functions, the function being declared implicitly. It is possible to enable support for implicit function declarations using the directive:

#pragma TenDRA implicit function declaration on

Such implicitly declared functions have C linkage and type int ( ... ).

7.8. Forward enumeration declarations

The ISO C Standard (Section 6.5.2.3) states that the first introduction of an enumeration tag shall declare the constants associated with that tag. This rule is enforced by the checker in default mode, however it can be relaxed using the pragma:

#pragma TenDRA forward enum declaration permit

where replacing permit by allow permits the declaration and use of an enumeration tag before the declaration of its associated enumeration constants. A disallow variant which restores the default behaviour is also available.

7.9. Variable scope in for statements

In ISO C++ the scope of a variable declared in a for-init-statement is the body of the for statement; in older dialects it extended to the end of the enclosing block. So:

for ( int i = 0 ; i < 10 ; i++ ) {
	// for statement body
}
return i ;	// OK in older dialects, error in ISO C++

This behaviour is controlled by the directive:

#pragma TenDRA++ for initialization block on

a state of on corresponding to the ISO rules and off to the older rules. Perhaps most useful is the warning state which implements the old rules but gives a warning if a variable declared in a for-init-statement is used outside the corresponding for statement body. A program which does not give such warnings should compile correctly under either set of rules.

7.10. Anonymous unions

A union declared without introducing a tag or identifier is termed an anonymous union. Members populate the scope where the union itself is declared. For example, this may be a surrounding struct, or a block:

union {
	int a;
	int b;
};
a = 5;

The ISO C Standard (Section 6.5.2.1) states that a union declaration must contain a tag or identifier. Several compilers permit this as an extension to C, and the later C11 standard formalises this as a required feature. Permissibility may be controlled using the pragma:

#pragma TenDRA anonymous union permit

where replacing permit by allow permits the declaration of an anonymous union, and warning will allow the declaration but produce a warning. A disallow variant which restores the default behaviour is also available.

By default anonymous unions are dissallowed for C.

Anonymous unions are required to be supported by C++, and setting this pragma has no effect. For C++, an anonymous union cannot have private or protected members or member functions (in addition, no union can have static data members).