7. Configuration for declarations
- 7.1. Empty source files
- 7.2. Untagged compound types
- 7.3. Empty declarations
- 7.4. Unifying the tag name space
- 7.5. Extra commas
- 7.6. Implicit
int
- 7.7. Implicit function declarations
- 7.8. Forward enumeration declarations
- 7.9. Variable scope in
for
statements - 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).