Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
<!-- Crown Copyright (c) 1998 -->
<HTML>
<HEAD>
<TITLE>
C++ Producer Guide: Configuration
</TITLE>
</HEAD>
<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#0000FF" VLINK="#400080" ALINK="#FF0000">
<H1>C++ Producer Guide</H1>
<H3>March 1998</H3>
<A HREF="token.html"><IMG SRC="../images/next.gif" ALT="next section"></A>
<A HREF="man.html"><IMG SRC="../images/prev.gif" ALT="previous section"></A>
<A HREF="index.html"><IMG SRC="../images/top.gif" ALT="current document"></A>
<A HREF="../index.html"><IMG SRC="../images/home.gif" ALT="TenDRA home page">
</A>
<IMG SRC="../images/no_index.gif" ALT="document index"><P>
<HR>
<DL>
<DT><A HREF="#table"><B>2.2.1</B> - Portability tables</A><DD>
<DT><A HREF="#low"><B>2.2.2</B> - Low level configuration</A><DD>
<DT><A HREF="#scope"><B>2.2.3</B> - Checking scopes</A><DD>
<DT><A HREF="#limits"><B>2.2.4</B> - Implementation limits</A><DD>
<DT><A HREF="#lex"><B>2.2.5</B> - Lexical analysis</A><DD>
<DT><A HREF="#keyword"><B>2.2.6</B> - Keywords</A><DD>
<DT><A HREF="#comment"><B>2.2.7</B> - Comments</A><DD>
<DT><A HREF="#identifier"><B>2.2.8</B> - Identifier names</A><DD>
<DT><A HREF="#int"><B>2.2.9</B> - Integer literals</A><DD>
<DT><A HREF="#char"><B>2.2.10</B> - Character literals and built-in
types</A><DD>
<DT><A HREF="#string"><B>2.2.11</B> - String literals</A><DD>
<DT><A HREF="#escape"><B>2.2.12</B> - Escape sequences</A><DD>
<DT><A HREF="#ppdir"><B>2.2.13</B> - Preprocessing directives</A><DD>
<DT><A HREF="#target-if"><B>2.2.14</B> - Target dependent conditional
inclusion</A><DD>
<DT><A HREF="#include"><B>2.2.15</B> - File inclusion directives</A><DD>
<DT><A HREF="#macro"><B>2.2.16</B> - Macro definitions</A><DD>
<DT><A HREF="#empty"><B>2.2.17</B> - Empty source files</A><DD>
<DT><A HREF="#std"><B>2.2.18</B> - The <CODE>std</CODE> namespace</A><DD>
<DT><A HREF="#linkage"><B>2.2.19</B> - Object linkage</A><DD>
<DT><A HREF="#static"><B>2.2.20</B> - Static identifiers</A><DD>
<DT><A HREF="#decl_none"><B>2.2.21</B> - Empty declarations</A><DD>
<DT><A HREF="#implicit"><B>2.2.22</B> - Implicit <CODE>int</CODE></A><DD>
<DT><A HREF="#longlong"><B>2.2.23</B> - Extended integral types</A><DD>
<DT><A HREF="#bitfield"><B>2.2.24</B> - Bitfield types</A><DD>
<DT><A HREF="#elab"><B>2.2.25</B> - Elaborated type specifiers</A><DD>
<DT><A HREF="#impl_func"><B>2.2.26</B> - Implicit function declarations</A><DD>
<DT><A HREF="#weak"><B>2.2.27</B> - Weak function prototypes</A><DD>
<DT><A HREF="#printf"><B>2.2.28</B> - <CODE>printf</CODE> and <CODE>scanf</CODE>
argument checking</A><DD>
<DT><A HREF="#typedef"><B>2.2.29</B> - Type declarations</A><DD>
<DT><A HREF="#compatible"><B>2.2.30</B> - Type compatibility</A><DD>
<DT><A HREF="#complete"><B>2.2.31</B> - Incomplete types</A><DD>
<DT><A HREF="#conv"><B>2.2.32</B> - Type conversions</A><DD>
<DT><A HREF="#cast"><B>2.2.33</B> - Cast expressions</A><DD>
<DT><A HREF="#ellipsis"><B>2.2.34</B> - Ellipsis functions</A><DD>
<DT><A HREF="#overload"><B>2.2.35</B> - Overloaded functions</A><DD>
<DT><A HREF="#exp"><B>2.2.36</B> - Expressions</A><DD>
<DT><A HREF="#init"><B>2.2.37</B> - Initialiser expressions</A><DD>
<DT><A HREF="#lvalue"><B>2.2.38</B> - Lvalue expressions</A><DD>
<DT><A HREF="#discard"><B>2.2.39</B> - Discarded expressions</A><DD>
<DT><A HREF="#if"><B>2.2.40</B> - Conditional and iteration statements</A><DD>
<DT><A HREF="#switch"><B>2.2.41</B> - Switch statements</A><DD>
<DT><A HREF="#for"><B>2.2.42</B> - For statements</A><DD>
<DT><A HREF="#return"><B>2.2.43</B> - Return statements</A><DD>
<DT><A HREF="#reach"><B>2.2.44</B> - Unreached code analysis</A><DD>
<DT><A HREF="#variable"><B>2.2.45</B> - Variable flow analysis</A><DD>
<DT><A HREF="#hide"><B>2.2.46</B> - Variable hiding</A><DD>
<DT><A HREF="#exception"><B>2.2.47</B> - Exception analysis</A><DD>
<DT><A HREF="#template"><B>2.2.48</B> - Template compilation</A><DD>
<DT><A HREF="#catch_all"><B>2.2.49</B> - Other checks</A><DD>
</DL>
<HR>
<H2>2.2. Compiler configuration</H2>
<P>
This section describes how the C++ producer can be configured to apply
extra static checks or to support various dialects of C++. In all
cases the default behaviour is precisely that specified in the ISO
C++ standard with no extra checks.
</P>
<P>
Certain very basic configuration information is specified using a
<A HREF="#table">portability table</A>, however the primary method
of configuration is by means of <CODE>#pragma</CODE> directives.
These directives may be placed within the program itself, however
it is generally more convenient to group them into a
<A HREF="man.html#start-up">start-up file</A> in order to create a
<A NAME="usr">user-defined compilation profile</A>. The
<CODE>#pragma</CODE> directives recognised by the C++ producer have
one of the equivalent forms:
<PRE>
#pragma TenDRA ....
#pragma TenDRA++ ....
</PRE>
Some of these are common to the C and C++ producers (although often
with differing default behaviour). The C producer will ignore any
<CODE>TenDRA++</CODE> directives, so these may be used in compilation
profiles which are to be used by both producers. In the descriptions
below, the presence of a <CODE>++</CODE> is used to indicate a directive
which is C++ specific; the other directives are common to both producers.
</P>
<P>
Within the description of the <CODE>#pragma</CODE> syntax, <I>on</I>
stands for <CODE>on</CODE>, <CODE>off</CODE> or <CODE>warning</CODE>,
<I>allow</I> stands for <CODE>allow</CODE>, <CODE>disallow</CODE>
or
<CODE>warning</CODE>, <I>string-literal</I> is any string literal,
<I>integer-literal</I> is any integer literal, <I>identifier</I> is
any simple, unqualified identifier name, and <I>type-id</I> is any
type identifier. Other syntactic items are described in the text.
A
<A HREF="pragma1.html">complete grammar</A> for the <CODE>#pragma</CODE>
directives accepted by the C++ producer is given as an annex.
</P>
<HR>
<H3><A NAME="table">2.2.1. Portability tables</A></H3>
<P>
Certain very basic configuration information is read from a file called
a portability table, which may be specified to the producer using
a
<A HREF="man.html#table"><CODE>-n</CODE> option</A>. This information
includes the minimum sizes of the basic integral types, the
<A HREF="#char">sign of plain <CODE>char</CODE></A>, and whether signed
types can be assumed to be symmetric (for example, [-127,127]) or
maximum (for example, [-128,127]).
</P>
<P>
The default portability table values, which are built into the producer,
can be expressed in the form:
<PRE>
char_bits 8
short_bits 16
int_bits 16
long_bits 32
signed_range symmetric
char_type either
ptr_int none
ptr_fn no
non_prototype_checks yes
multibyte 1
</PRE>
This illustrates the syntax for the portability table; note that all
ten entries are required, even though the last four are ignored.
</P>
<HR>
<H3><A NAME="low">2.2.2. Low level configuration</A></H3>
<P>
The simplest level of configuration is to reset the severity level
of a particular error message using:
<PRE>
#pragma TenDRA++ error <I>string-literal on</I>
#pragma TenDRA++ error <I>string-literal allow</I>
</PRE>
The given <I>string-literal</I> should name an error from the
<A HREF="error.html">error catalogue</A>. A severity of <CODE>on</CODE>
or <CODE>disallow</CODE> indicates that the associated diagnostic
message should be an error, which causes the compilation to fail.
A severity of
<CODE>warning</CODE> indicates that the associated diagnostic message
should be a warning, which is printed but allows the compilation to
continue. A severity of <CODE>off</CODE> or <CODE>allow</CODE>
indicates that the associated error should be ignored. Reducing the
severity of any error from its default value, other than via one of
the dialect directives described in this section, results in undefined
behaviour.
</P>
<P>
The next level of configuration is to reset the severity level of
a particular compiler option using:
<PRE>
#pragma TenDRA++ option <I>string-literal on</I>
#pragma TenDRA++ option <I>string-literal allow</I>
</PRE>
The given <I>string-literal</I> should name an option from the option
catalogue. The simplest form of compiler option just sets the severity
level of one or more error messages. Some of these options may require
additional processing to be applied.
<P>
It is possible to link a particular error message to a particular
compiler option using:
<PRE>
#pragma TenDRA++ error <I>string-literal</I> as option <I>string-literal</I>
</PRE>
</P>
<P>
Note that the directive:
<PRE>
#pragma TenDRA++ use error <I>string-literal</I>
</PRE>
can be used to raise a given error at any point in a translation unit
in a similar fashion to the <CODE>#error</CODE> directive. The values
of any parameters for this error are unspecified.
</P>
<P>
The directives just described give the primitive operations on error
messages and compiler options. Many of the remaining directives in
this section are merely higher level ways of expressing these primitives.
</P>
<HR>
<H3><A NAME="scope">2.2.3. Checking scopes</A></H3>
<P>
Most compiler options are scoped. A checking scope may be defined
by enclosing a list of declarations within:
<PRE>
#pragma TenDRA begin
....
#pragma TenDRA end
</PRE>
If the final <CODE>end</CODE> directive is omitted then the scope
ends at the end of the translation unit. Checking scopes may be nested
in the obvious way. A checking scope inherits its initial set of
checks from its enclosing scope (this includes the implicit main checking
scope consisting of the entire input file). Any checks switched on
or off within a scope apply only to the remainder of that scope and
any scope it contains. A particular check can only be set once in
a given scope. The set of applied checks reverts to its previous state
at the end of the scope.
<P>
A checking scope can be named using the directives:
<PRE>
#pragma TenDRA begin name environment <I>identifier</I>
....
#pragma TenDRA end
</PRE>
Checking scope names occupy a namespace distinct from any other namespace
within the translation unit. A named scope defines a set of modifications
to the current checking scope. These modifications may be reapplied
within a different scope using:
<PRE>
#pragma TenDRA use environment <I>identifier</I>
</PRE>
The default behaviour is not to allow checks set in the named checking
scope to be reset in the current scope. This can however be modified
using:
<PRE>
#pragma TenDRA use environment <I>identifier</I> reset <I>allow</I>
</PRE>
</P>
<P>
Another use of a named checking scope is to associate a checking scope
with a named include file directory. This is done using:
<PRE>
#pragma TenDRA directory <I>identifier</I> use environment <I>identifier</I>
</PRE>
where the directory name is one introduced via a
<A HREF="man.html#directory"><CODE>-N</CODE> command-line option</A>.
The effect of this directive, if a <CODE>#include</CODE> directive
is found to resolve to a file from the given directory, is as if the
file was enclosed in directives of the form:
<PRE>
#pragma TenDRA begin
#pragma TenDRA use environment <I>identifier</I> reset allow
....
#pragma TenDRA end
</PRE>
</P>
<P>
The checks applied to the expansion of a macro definition are those
from the scope in which the macro was defined, not that in which it
was expanded. The macro arguments are checked in the scope in which
they are specified, that is to say, the scope in which the macro is
expanded. This enables macro definitions to remain localised with
respect to checking scopes.
</P>
<HR>
<H3><A NAME="limits">2.2.4. Implementation limits</A></H3>
<P>
This table gives the default implementation limits imposed by the
C++ producer for the various implementation quantities listed in Annex
B of the ISO C++ standard, together with the minimum limits allowed
in ISO C and C++. A default limit of <I>none</I> means that the quantity
is limited only by the size of the host machine (either <CODE>ULONG_MAX</CODE>
or until it runs out of memory). A limit of <I>target</I> means that
while no limits is imposed by the C++ front-end, particular target
machines may impose such limits.
</P>
<CENTER>
<TABLE BORDER>
<TR><TH>Quantity identifier</TH>
<TH>Min C limit</TH> <TH>Min C++ limit</TH>
<TH>Default limit</TH>
<TR><TD ALIGN=CENTER>statement_depth</TD>
<TD ALIGN=CENTER>15</TD> <TD ALIGN=CENTER>256</TD>
<TD ALIGN=CENTER>none</TD>
<TR><TD ALIGN=CENTER>hash_if_depth</TD>
<TD ALIGN=CENTER>8</TD> <TD ALIGN=CENTER>256</TD>
<TD ALIGN=CENTER>none</TD>
<TR><TD ALIGN=CENTER>declarator_max</TD>
<TD ALIGN=CENTER>12</TD> <TD ALIGN=CENTER>256</TD>
<TD ALIGN=CENTER>none</TD>
<TR><TD ALIGN=CENTER>paren_depth</TD>
<TD ALIGN=CENTER>32</TD> <TD ALIGN=CENTER>256</TD>
<TD ALIGN=CENTER>none</TD>
<TR><TD ALIGN=CENTER>name_limit</TD>
<TD ALIGN=CENTER>31</TD> <TD ALIGN=CENTER>1024</TD>
<TD ALIGN=CENTER>none</TD>
<TR><TD ALIGN=CENTER>extern_name_limit</TD>
<TD ALIGN=CENTER>6</TD> <TD ALIGN=CENTER>1024</TD>
<TD ALIGN=CENTER>target</TD>
<TR><TD ALIGN=CENTER>external_ids</TD>
<TD ALIGN=CENTER>511</TD> <TD ALIGN=CENTER>65536</TD>
<TD ALIGN=CENTER>target</TD>
<TR><TD ALIGN=CENTER>block_ids</TD>
<TD ALIGN=CENTER>127</TD> <TD ALIGN=CENTER>1024</TD>
<TD ALIGN=CENTER>none</TD>
<TR><TD ALIGN=CENTER>macro_ids</TD>
<TD ALIGN=CENTER>1024</TD> <TD ALIGN=CENTER>65536</TD>
<TD ALIGN=CENTER>none</TD>
<TR><TD ALIGN=CENTER>func_pars</TD>
<TD ALIGN=CENTER>31</TD> <TD ALIGN=CENTER>256</TD>
<TD ALIGN=CENTER>none</TD>
<TR><TD ALIGN=CENTER>func_args</TD>
<TD ALIGN=CENTER>31</TD> <TD ALIGN=CENTER>256</TD>
<TD ALIGN=CENTER>none</TD>
<TR><TD ALIGN=CENTER>macro_pars</TD>
<TD ALIGN=CENTER>31</TD> <TD ALIGN=CENTER>256</TD>
<TD ALIGN=CENTER>none</TD>
<TR><TD ALIGN=CENTER>macro_args</TD>
<TD ALIGN=CENTER>31</TD> <TD ALIGN=CENTER>256</TD>
<TD ALIGN=CENTER>none</TD>
<TR><TD ALIGN=CENTER>line_length</TD>
<TD ALIGN=CENTER>509</TD> <TD ALIGN=CENTER>65536</TD>
<TD ALIGN=CENTER>none</TD>
<TR><TD ALIGN=CENTER>string_length</TD>
<TD ALIGN=CENTER>509</TD> <TD ALIGN=CENTER>65536</TD>
<TD ALIGN=CENTER>none</TD>
<TR><TD ALIGN=CENTER>sizeof_object</TD>
<TD ALIGN=CENTER>32767</TD> <TD ALIGN=CENTER>262144</TD>
<TD ALIGN=CENTER>target</TD>
<TR><TD ALIGN=CENTER>include_depth</TD>
<TD ALIGN=CENTER>8</TD> <TD ALIGN=CENTER>256</TD>
<TD ALIGN=CENTER>256</TD>
<TR><TD ALIGN=CENTER>switch_cases</TD>
<TD ALIGN=CENTER>257</TD> <TD ALIGN=CENTER>16384</TD>
<TD ALIGN=CENTER>none</TD>
<TR><TD ALIGN=CENTER>data_members</TD>
<TD ALIGN=CENTER>127</TD> <TD ALIGN=CENTER>16384</TD>
<TD ALIGN=CENTER>none</TD>
<TR><TD ALIGN=CENTER>enum_consts</TD>
<TD ALIGN=CENTER>127</TD> <TD ALIGN=CENTER>4096</TD>
<TD ALIGN=CENTER>none</TD>
<TR><TD ALIGN=CENTER>nested_class</TD>
<TD ALIGN=CENTER>15</TD> <TD ALIGN=CENTER>256</TD>
<TD ALIGN=CENTER>none</TD>
<TR><TD ALIGN=CENTER>atexit_funcs</TD>
<TD ALIGN=CENTER>32</TD> <TD ALIGN=CENTER>32</TD>
<TD ALIGN=CENTER>target</TD>
<TR><TD ALIGN=CENTER>base_classes</TD>
<TD ALIGN=CENTER>N/A</TD> <TD ALIGN=CENTER>16384</TD>
<TD ALIGN=CENTER>none</TD>
<TR><TD ALIGN=CENTER>direct_bases</TD>
<TD ALIGN=CENTER>N/A</TD> <TD ALIGN=CENTER>1024</TD>
<TD ALIGN=CENTER>none</TD>
<TR><TD ALIGN=CENTER>class_members</TD>
<TD ALIGN=CENTER>N/A</TD> <TD ALIGN=CENTER>4096</TD>
<TD ALIGN=CENTER>none</TD>
<TR><TD ALIGN=CENTER>virtual_funcs</TD>
<TD ALIGN=CENTER>N/A</TD> <TD ALIGN=CENTER>16384</TD>
<TD ALIGN=CENTER>none</TD>
<TR><TD ALIGN=CENTER>virtual_bases</TD>
<TD ALIGN=CENTER>N/A</TD> <TD ALIGN=CENTER>1024</TD>
<TD ALIGN=CENTER>none</TD>
<TR><TD ALIGN=CENTER>static_members</TD>
<TD ALIGN=CENTER>N/A</TD> <TD ALIGN=CENTER>1024</TD>
<TD ALIGN=CENTER>none</TD>
<TR><TD ALIGN=CENTER>friends</TD>
<TD ALIGN=CENTER>N/A</TD> <TD ALIGN=CENTER>4096</TD>
<TD ALIGN=CENTER>none</TD>
<TR><TD ALIGN=CENTER>access_declarations</TD>
<TD ALIGN=CENTER>N/A</TD> <TD ALIGN=CENTER>4096</TD>
<TD ALIGN=CENTER>none</TD>
<TR><TD ALIGN=CENTER>ctor_initializers</TD>
<TD ALIGN=CENTER>N/A</TD> <TD ALIGN=CENTER>6144</TD>
<TD ALIGN=CENTER>none</TD>
<TR><TD ALIGN=CENTER>scope_qualifiers</TD>
<TD ALIGN=CENTER>N/A</TD> <TD ALIGN=CENTER>256</TD>
<TD ALIGN=CENTER>none</TD>
<TR><TD ALIGN=CENTER>external_specs</TD>
<TD ALIGN=CENTER>N/A</TD> <TD ALIGN=CENTER>1024</TD>
<TD ALIGN=CENTER>none</TD>
<TR><TD ALIGN=CENTER>template_pars</TD>
<TD ALIGN=CENTER>N/A</TD> <TD ALIGN=CENTER>1024</TD>
<TD ALIGN=CENTER>none</TD>
<TR><TD ALIGN=CENTER>instance_depth</TD>
<TD ALIGN=CENTER>N/A</TD> <TD ALIGN=CENTER>17</TD>
<TD ALIGN=CENTER>17</TD>
<TR><TD ALIGN=CENTER>exception_handlers</TD>
<TD ALIGN=CENTER>N/A</TD> <TD ALIGN=CENTER>256</TD>
<TD ALIGN=CENTER>none</TD>
<TR><TD ALIGN=CENTER>exception_specs</TD>
<TD ALIGN=CENTER>N/A</TD> <TD ALIGN=CENTER>256</TD>
<TD ALIGN=CENTER>none</TD>
</TABLE>
</CENTER>
<P>
It is possible to impose lower limits on most of the quantities listed
above by means of the directive:
<PRE>
#pragma TenDRA++ option value <I>string-literal integer-literal</I>
</PRE>
where <I>string-literal</I> gives one of the quantity identifiers
listed above and <I>integer-literal</I> gives the limit to be imposed.
An error is reported if the quantity exceeds this limit (note however
that checks have not yet been implemented for all of the quantities
listed). Note that the <A HREF="#identifier"><CODE>name_limit</CODE></A>
and
<A HREF="#include"><CODE>include_depth</CODE></A> implementation limits
can be set using dedicated directives.
</P>
<P>
The maximum number of errors allowed before the producer bails out
can be set using the directive:
<PRE>
#pragma TenDRA++ set error limit <I>integer-literal</I>
</PRE>
The default value is 32.
<P>
<HR>
<H3><A NAME="lex">2.2.5. Lexical analysis</A></H3>
<P>
During lexical analysis, a source file which is not empty should end
in a newline character. It is possible to relax this constraint using
the directive:
<PRE>
#pragma TenDRA no nline after file end <I>allow</I>
</PRE>
</P>
<HR>
<H3><A NAME="keyword">2.2.6. Keywords</A></H3>
<P>
In several places in this section it is described how to introduce
keywords for TenDRA language extensions. By default, no such extra
keywords are defined. There are also low-level directives for defining
and undefining keywords. The directive:
<PRE>
#pragma TenDRA++ keyword <I>identifier</I> for keyword <I>identifier</I>
</PRE>
can be used to introduce a keyword (the first identifier) standing
for the standard C++ keyword given by the second identifier. The
directive:
<PRE>
#pragma TenDRA++ keyword <I>identifier</I> for operator <I>operator</I>
</PRE>
can similarly be used to introduce a keyword giving an alternative
representation for the given operator or punctuator, as, for example,
in:
<PRE>
#pragma TenDRA++ keyword and for operator &&
</PRE>
Finally the directive:
<PRE>
#pragma TenDRA++ undef keyword <I>identifier</I>
</PRE>
can be used to undefine a keyword.
</P>
<HR>
<H3><A NAME="comment">2.2.7. Comments</A></H3>
<P>
C-style comments do not nest. The directive:
<PRE>
#pragma TenDRA nested comment analysis <I>on</I>
</PRE>
enables a check for the characters <CODE>/*</CODE> within C-style
comments.
</P>
<HR>
<H3><A NAME="identifier">2.2.8. Identifier names</A></H3>
<P>
During lexical analysis, each character in the source file has an
associated look-up value which is used to determine whether the character
can be used in an identifier name, is a white space character etc.
These values are stored in a simple look-up table. It is possible
to set the look-up value using:
<PRE>
#pragma TenDRA++ character <I>character-literal</I> as <I>character-literal</I> allow
</PRE>
which sets the look-up for the first character to be the default look-up
for the second character. The form:
<PRE>
#pragma TenDRA++ character <I>character-literal</I> disallow
</PRE>
sets the look-up of the character to be that of an invalid character.
The forms:
<PRE>
#pragma TenDRA++ character <I>string-literal</I> as <I>character-literal</I> allow
#pragma TenDRA++ character <I>string-literal</I> disallow
</PRE>
can be used to modify the look-up values for the set of characters
given by the string literal. For example:
<PRE>
#pragma TenDRA character '$' as 'a' allow
#pragma TenDRA character '\r' as ' ' allow
</PRE>
allows <CODE>$</CODE> to be used in identifier names (like <CODE>a</CODE>)
and carriage return to be a white space character. The former is
a common dialect feature and can also be controlled by the directive:
<PRE>
#pragma TenDRA dollar as ident <I>allow</I>
</PRE>
</P>
<P>
The maximum number of characters allowed in an identifier name can
be set using the directives:
<PRE>
#pragma TenDRA set name limit <I>integer-literal</I>
#pragma TenDRA++ set name limit <I>integer-literal</I> warning
</PRE>
This length is given by the <CODE>name_limit</CODE> implementation
quantity
<A HREF="#limits">mentioned above</A>. Identifiers which exceed this
length raise an error or a warning, but are not truncated.
</P>
<HR>
<H3><A NAME="int">2.2.9. Integer literals</A></H3>
<P>
The rules for finding the type of an integer literal can be described
using directives of the form:
<PRE>
#pragma TenDRA integer literal <I>literal-spec</I>
</PRE>
where:
<PRE>
<I>literal-spec</I> :
<I>literal-base literal-suffix<SUB>opt</SUB> literal-type-list</I>
<I>literal-base</I> :
octal
decimal
hexadecimal
<I>literal-suffix</I> :
unsigned
long
unsigned long
long long
unsigned long long
<I>literal-type-list</I> :
* <I>literal-type-spec</I>
<I>integer-literal literal-type-spec</I> | <I>literal-type-list</I>
? <I>literal-type-spec</I> | <I>literal-type-list</I>
<I>literal-type-spec</I> :
: <I>type-id</I>
* <I>allow<SUB>opt</SUB></I> : <I>identifier</I>
* * <I>allow<SUB>opt</SUB></I> :
</PRE>
Each directive gives a literal base and suffix, describing the form
of an integer literal, and a list of possible types for literals of
this form. This list gives a mapping from the value of the literal
to the type to be used to represent the literal. There are three
cases for the literal type; it may be a given integral type, it may
be calculated using a given <A HREF="lib.html#literal">literal type
token</A>, or it may cause an error to be raised. There are also
three cases for describing a literal range; it may be given by values
less than or equal to a given integer literal, it may be given by
values which are guaranteed to fit into a given integral type, or
it may be match any value. For example:
<PRE>
#pragma token PROC ( VARIETY c ) VARIETY l_i # ~lit_int
#pragma TenDRA integer literal decimal 32767 : int | ** : l_i
</PRE>
describes how to find the type of a decimal literal with no suffix.
Values less that or equal to 32767 have type <CODE>int</CODE>; larger
values have target dependent type calculated using the token
<CODE>~lit_int</CODE>. Introducing a <CODE>warning</CODE> into the
directive will cause a warning to be printed if the token is used
to calculate the value.
</P>
<P>
Note that this scheme extends that implemented by the C producer,
because of the need for more accurate information in the C++ producer.
For example, the specification above does not fully express the ISO
rule that the type of a decimal integer is the first of the types
<CODE>int</CODE>, <CODE>long</CODE> and <CODE>unsigned long</CODE>
which it fits into (it only expresses the first step). However with
the C++ extensions it is possible to write:
<PRE>
#pragma token PROC ( VARIETY c ) VARIETY l_i # ~lit_int
#pragma TenDRA integer literal decimal ? : int | ? : long |\
? : unsigned long | ** : l_i
</PRE>
</P>
<HR>
<H3><A NAME="char">2.2.10. Character literals and built-in types</A></H3>
<P>
By default, a simple character literal has type <CODE>int</CODE> in
C and type <CODE>char</CODE> in C++. The type of such literals can
be controlled using the directive:
<PRE>
#pragma TenDRA++ set character literal : <I>type-id</I>
</PRE>
The type of a wide character literal is given by the implementation
defined type <CODE>wchar_t</CODE>. By default, the definition of
this type is taken from the target machine's <CODE><stddef.h></CODE>
C header (note that in ISO C++, <CODE>wchar_t</CODE> is actually a
keyword, but its underlying representation must be the same as in
C). This definition can be overridden in the producer by means of
the directive:
<PRE>
#pragma TenDRA set wchar_t : <I>type-id</I>
</PRE>
for an integral type <I>type-id</I>. Similarly, the definitions of
the other implementation dependent integral types which arise naturally
within the language - the type of the difference of two pointers,
<CODE>ptrdiff_t</CODE>, and the type of the <CODE>sizeof</CODE>
operator, <CODE>size_t</CODE> - given in the <CODE><stddef.h></CODE>
header can be overridden using the directives:
<PRE>
#pragma TenDRA set ptrdiff_t : <I>type-id</I>
#pragma TenDRA set size_t : <I>type-id</I>
</PRE>
These directives are useful when targeting a specific machine on which
the definitions of these types are known; while they may not affect
the code generated they can cut down on spurious conversion warnings.
Note that although these types are built into the producer they are
not visible to the user unless an appropriate header is included (with
the exception of the keyword <CODE>wchar_t</CODE> in ISO C++), however
the directives:
<PRE>
#pragma TenDRA++ type <I>identifier</I> for <I>type-name</I>
</PRE>
can be used to make these types visible. They are equivalent to a
<CODE>typedef</CODE> declaration of <I>identifier</I> as the given
built-in type, <CODE>ptrdiff_t</CODE>, <CODE>size_t</CODE> or
<CODE>wchar_t</CODE>.
</P>
<P>
Whether plain <CODE>char</CODE> is signed or unsigned is implementation
dependent. By default the implementation is determined by the definition
of the <A HREF="lib.html#arith"><CODE>~char</CODE> token</A>, however
this can be overridden in the producer either by means of the
<A HREF="#table">portability table</A> or by the directive:
<PRE>
#pragma TenDRA character <I>character-sign</I>
</PRE>
where <I>character-sign</I> can be <CODE>signed</CODE>,
<CODE>unsigned</CODE> or <CODE>either</CODE> (the default). Again
this directive is useful primarily when targeting a specific machine
on which the signedness of <CODE>char</CODE> is known.
</P>
<HR>
<H3><A NAME="string">2.2.11. String literals</A></H3>
<P>
By default, character string literals have type <CODE>char [n]</CODE>
in C and older dialects of C++, but type <CODE>const char [n]</CODE>
in ISO C++. Similarly wide string literals have type <CODE>wchar_t
[n]</CODE>
or <CODE>const wchar_t [n]</CODE>. Whether string literals are
<CODE>const</CODE> or not can be controlled using the two directives:
<PRE>
#pragma TenDRA++ set string literal : const
#pragma TenDRA++ set string literal : no const
</PRE>
In the case where literals are <CODE>const</CODE>, the array-to-pointer
conversion is allowed to cast away the <CODE>const</CODE> to allow
for a degree of backwards compatibility. The status of this deprecated
conversion can be controlled using the directive:
<PRE>
#pragma TenDRA writeable string literal <I>allow</I>
</PRE>
(yes, I know that that should be <CODE>writable</CODE>). Note that
this directive has a slightly different meaning in the C producer.
</P>
<P>
Adjacent string literals tokens of similar types (either both character
string literals or both wide string literals) are concatenated at
an early stage in parser, however it is unspecified what happens if
a character string literal token is adjacent to a wide string literal
token. By default this gives an error, but the directive:
<PRE>
#pragma TenDRA unify incompatible string literal <I>allow</I>
</PRE>
can be used to enable the strings to be concatenated to give a wide
string literal.
</P>
<P>
If a <CODE>'</CODE> or <CODE>"</CODE> character does not have
a matching closing quote on the same line then it is undefined whether
an implementation should report an unterminated string or treat the
quote as a single unknown character. By default, the C++ producer
treats this as an unterminated string, but this behaviour can be controlled
using the directive:
<PRE>
#pragma TenDRA unmatched quote <I>allow</I>
</PRE>
</P>
<HR>
<H3><A NAME="escape">2.2.12. Escape sequences</A></H3>
<P>
By default, if the character following the <CODE>\</CODE> in an escape
sequence is not one of those listed in the ISO C or C++ standards
then an error is given. This behaviour, which is left unspecified
by the standards, can be controlled by the directive:
<PRE>
#pragma TenDRA unknown escape <I>allow</I>
</PRE>
The result is that the <CODE>\</CODE> in unknown escape sequences
is ignored, so that <CODE>\z</CODE> is interpreted as <CODE>z</CODE>,
for example. Individual escape sequences can be enabled or disabled
using the directives:
<PRE>
#pragma TenDRA++ escape <I>character-literal</I> as <I>character-literal</I> allow
#pragma TenDRA++ escape <I>character-literal</I> disallow
</PRE>
so that, for example:
<PRE>
#pragma TenDRA++ escape 'e' as '\033' allow
#pragma TenDRA++ escape 'a' disallow
</PRE>
sets <CODE>\e</CODE> to be the ASCII escape character and disables
the alert character <CODE>\a</CODE>.
</P>
<P>
By default, if the value of a character, given for example by a
<CODE>\x</CODE> escape sequence, does not fit into its type then an
error is given. This implementation dependent behaviour can however
be controlled by the directive:
<PRE>
#pragma TenDRA character escape overflow <I>allow</I>
</PRE>
the value being converted to its type in the normal way.
</P>
<HR>
<H3><A NAME="ppdir">2.2.13. Preprocessing directives</A></H3>
<P>
Non-standard preprocessing directives can be controlled using the
directives:
<PRE>
#pragma TenDRA directive <I>ppdir allow</I>
#pragma TenDRA directive <I>ppdir</I> (ignore) <I>allow</I>
</PRE>
where <I>ppdir</I> can be <CODE>assert</CODE>, <CODE>file</CODE>,
<CODE>ident</CODE>, <CODE>import</CODE> (C++ only),
<CODE>include_next</CODE> (C++ only), <CODE>unassert</CODE>,
<CODE>warning</CODE> (C++ only) or <CODE>weak</CODE>. The second form
causes the directive to be processed but ignored (note that there is no
<CODE>(ignore) disallow</CODE> form). The treatment of other unknown
preprocessing directives can be controlled using:
<PRE>
#pragma TenDRA unknown directive <I>allow</I>
</PRE>
Cases where the token following the <CODE>#</CODE> in a preprocessing
directive is not an identifier can be controlled using:
<PRE>
#pragma TenDRA no directive/nline after ident <I>allow</I>
</PRE>
When permitted, unknown preprocessing directives are ignored.
</P>
<P>
By default, unknown <CODE>#pragma</CODE> directives are ignored without
comment, however this behaviour can be modified using the directive:
<PRE>
#pragma TenDRA unknown pragma <I>allow</I>
</PRE>
Note that any unknown <CODE>#pragma TenDRA</CODE> directives always
give an error.
</P>
<P>
Older preprocessors allowed text after <CODE>#else</CODE> and
<CODE>#endif</CODE> directives. The following directive can be used
to enable such behaviour:
<PRE>
#pragma TenDRA text after directive <I>allow</I>
</PRE>
Such text after a directive is ignored.
</P>
<P>
Some older preprocessors have problems with white space in preprocessing
directives - whether at the start of the line, before the initial
<CODE>#</CODE>, or between the <CODE>#</CODE> and the directive identifier.
Such white space can be detected using the directives:
<PRE>
#pragma TenDRA indented # directive <I>allow</I>
#pragma TenDRA indented directive after # <I>allow</I>
</PRE>
respectively.
</P>
<HR>
<H3><A NAME="target-if">2.2.14. Target dependent conditional inclusion</A></H3>
<P>
One of the effects of trying to compile code in a target independent
manner is that it is not always possible to completely evaluate the
condition in a <CODE>#if</CODE> directive. Thus the conditional inclusion
needs to be preserved until the installer phase. This can only be
done if the target dependent <CODE>#if</CODE> is more structured than
is normally required for preprocessing directives. There are two cases;
in the first, where the <CODE>#if</CODE> appears in a statement, it
is treated as if it were a <CODE>if</CODE> statement with braces including
its branches; that is:
<PRE>
#if cond
true_statements
#else
false_statements
#endif
</PRE>
maps to:
<PRE>
if ( cond ) {
true_statements
} else {
false_statements
}
</PRE>
In the second case, where the <CODE>#if</CODE> appears in a list of
declarations, normally gives an error. The can however be overridden
by the directive:
<PRE>
#pragma TenDRA++ conditional declaration <I>allow</I>
</PRE>
which causes both branches of the <CODE>#if</CODE> to be analysed.
</P>
<HR>
<H3><A NAME="include">2.2.15. File inclusion directives</A></H3>
<P>
There is a maximum depth of nested <CODE>#include</CODE>
directives allowed by the C++ producer. This depth is given by the
<CODE>include_depth</CODE> implementation quantity
<A HREF="#limits">mentioned above</A>. Its value is fairly small
in order to detect recursive inclusions. The maximum depth can be
set using:
<PRE>
#pragma TenDRA includes depth <I>integer-literal</I>
</PRE>
</P>
<P>
A further check, for full pathnames in <CODE>#include</CODE> directives
(which may not be portable), can be enabled using the directive:
<PRE>
#pragma TenDRA++ complete file includes <I>allow</I>
</PRE>
</P>
<HR>
<H3><A NAME="macro">2.2.16. Macro definitions</A></H3>
<P>
By default, multiple consistent definitions of a macro are allowed.
This behaviour can be controlled using the directive:
<PRE>
#pragma TenDRA extra macro definition <I>allow</I>
</PRE>
The ISO C/C++ rules for determining whether two macro definitions
are consistent are fairly restrictive. A more relaxed rule allowing
for consistent renaming of macro parameters can be enabled using:
<PRE>
#pragma TenDRA weak macro equality <I>allow</I>
</PRE>
</P>
<P>
In the definition of macros with parameters, a <CODE>#</CODE> in the
replacement list must be followed by a parameter name, indicating
the stringising operation. This behaviour can be controlled by the
directive:
<PRE>
#pragma TenDRA no ident after # <I>allow</I>
</PRE>
which allows a <CODE>#</CODE> which is not followed by a parameter
name to be treated as a normal preprocessing token.
</P>
<P>
In a list of macro arguments, the effect of a sequence of preprocessing
tokens which otherwise resembles a preprocessing directive is undefined.
The C++ producer treats such directives as normal sequences of preprocessing
tokens, but can be made to report such behaviour using:
<PRE>
#pragma TenDRA directive as macro argument <I>allow</I>
</PRE>
</P>
<HR>
<H3><A NAME="empty">2.2.17. Empty source files</A></H3>
<P>
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:
<PRE>
#pragma TenDRA no external declaration <I>allow</I>
</PRE>
</P>
<HR>
<H3><A NAME="std">2.2.18. The <CODE>std</CODE> namespace</A></H3>
<P>
Several classes declared in the <CODE>std</CODE> namespace arise naturally
as part of the C++ language specification. These are as follows:
<PRE>
std::type_info // type of typeid construct
std::bad_cast // thrown by dynamic_cast construct
std::bad_typeid // thrown by typeid construct
std::bad_alloc // thrown by new construct
std::bad_exception // used in exception specifications
</PRE>
The definitions of these classes are found, when needed, by looking
up the appropriate class name in the <CODE>std</CODE> namespace.
Depending on the context, an error may be reported if the class is
not found. It is possible to modify the namespace which is searched
for these classes using the directive:
<PRE>
#pragma TenDRA++ set std namespace : <I>scope-name</I>
</PRE>
where <I>scope-name</I> can be an identifier giving a namespace name
or <CODE>::</CODE>, indicating the global namespace.
</P>
<HR>
<H3><A NAME="linkage">2.2.19. Object linkage</A></H3>
<P>
If an object is declared with both external and internal linkage in
the same translation unit then, by default, an error is given. This
behaviour can be changed using the directive:
<PRE>
#pragma TenDRA incompatible linkage <I>allow</I>
</PRE>
When incompatible linkages are allowed, whether the resultant identifier
has external or internal linkage can be set using one of the directives:
<PRE>
#pragma TenDRA linkage resolution : off
#pragma TenDRA linkage resolution : (external) <I>on</I>
#pragma TenDRA linkage resolution : (internal) <I>on</I>
</PRE>
</P>
<P>
It is possible to declare objects with external linkage in a block.
C leaves it undefined whether declarations of the same object in different
blocks, such as:
<PRE>
void f ()
{
extern int a ;
....
}
void g ()
{
extern double a ;
....
}
</PRE>
are checked for compatibility. However in C++ the one definition
rule implies that such declarations are indeed checked for compatibility.
The status of this check can be set using the directive:
<PRE>
#pragma TenDRA unify external linkage <I>on</I>
</PRE>
Note that it is not possible in ISO C or C++ to declare objects or
functions with internal linkage in a block. While <CODE>static</CODE>
object definitions in a block have a specific meaning, there is no
real reason why <CODE>static</CODE> functions should not be declared
in a block. This behaviour can be enabled using the directive:
<PRE>
#pragma TenDRA block function static <I>allow</I>
</PRE>
</P>
<P>
Inline functions have external linkage by default in ISO C++, but
internal linkage in older dialects. The default linkage can be set
using the directive:
<PRE>
#pragma TenDRA++ inline linkage <I>linkage-spec</I>
</PRE>
where <I>linkage-spec</I> can be <CODE>external</CODE> or
<CODE>internal</CODE>. Similarly <CODE>const</CODE> objects have
internal linkage by default in C++, but external linkage in C. The
default linkage can be set using the directive:
<PRE>
#pragma TenDRA++ const linkage <I>linkage-spec</I>
</PRE>
</P>
<P>
Older dialects of C treated all identifiers with external linkage
as if they had been declared <CODE>volatile</CODE> (i.e. by being
conservative in optimising such values). This behaviour can be enabled
using the directive:
<PRE>
#pragma TenDRA external volatile_t
</PRE>
</P>
<P>
It is possible to set the default language linkage using the directive:
<PRE>
#pragma TenDRA++ external linkage <I>string-literal</I>
</PRE>
This is equivalent to enclosing the rest of the current checking scope
in:
<PRE>
extern <I>string-literal</I> {
....
}
</PRE>
It is unspecified what happens if such a directive is used within
an explicit linkage specification and does not nest correctly. This
directive is particularly useful when used in a <A HREF="#scope">named
environment</A> associated with an include directory. For example,
it can be used to express the fact that all the objects declared in
headers included from that directory have C linkage.
</P>
<P>
A change in ISO C++ relative to older dialects is that the language
linkage of a function now forms part of the function type. For example:
<PRE>
extern "C" int f ( int ) ;
int ( *pf ) ( int ) = f ; // error
</PRE>
The directive:
<PRE>
#pragma TenDRA++ external function linkage <I>on</I>
</PRE>
can be used to control whether function types with differing language
linkages, but which are otherwise compatible, are considered compatible
or not.
</P>
<HR>
<H3><A NAME="static">2.2.20. Static identifiers</A></H3>
<P>
By default, objects and functions with internal linkage are mapped
to tags without external names in the output TDF capsule. Thus such
names are not available to the installer and it needs to make up internal
names to represent such objects in its output. This is not desirable
in such operations as profiling, where a meaningful internal name
is needed to make sense of the output. The directive:
<PRE>
#pragma TenDRA preserve <I>identifier-list</I>
</PRE>
can be used to preserve the names of the given list of identifiers
with internal linkage. This is done using the <CODE>static_name_def</CODE>
TDF construct. The form:
<PRE>
#pragma TenDRA preserve *
</PRE>
will preserve the names of all identifiers with internal linkage in
this way.
</P>
<HR>
<H3><A NAME="decl_none">2.2.21. Empty declarations</A></H3>
<P>
ISO C++ requires every declaration or member declaration to introduce
one or more names into the program. The directive:
<PRE>
#pragma TenDRA unknown struct/union <I>allow</I>
</PRE>
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 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:
<PRE>
#pragma TenDRA extra ; <I>allow</I>
</PRE>
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.
</P>
<HR>
<H3><A NAME="implicit">2.2.22. Implicit <CODE>int</CODE></A></H3>
<P>
The C "implicit <CODE>int</CODE>" rule, whereby a type of
<CODE>int</CODE>
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:
<PRE>
#pragma TenDRA++ implicit int type <I>allow</I>
</PRE>
Partial relaxations of this rules are allowed. The directive:
<PRE>
#pragma TenDRA++ implicit int type for const/volatile <I>allow</I>
</PRE>
will allow for implicit <CODE>int</CODE> when the list of type specifiers
contains a cv-qualifier. Similarly the directive:
<PRE>
#pragma TenDRA implicit int type for function return <I>allow</I>
</PRE>
will allow for implicit <CODE>int</CODE> 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:
<PRE>
#pragma TenDRA implicit int type for external declaration <I>allow</I>
</PRE>
The four cases can be demonstrated in the following example:
<PRE>
extern a ; // implicit int
const b = 1 ; // implicit const int
f () // implicit function return
{
return 2 ;
}
c = 3 ; // error: not allowed in C++
</PRE>
</P>
<HR>
<H3><A NAME="longlong">2.2.23. Extended integral types</A></H3>
<P>
The <CODE>long long</CODE> integral types are not part of ISO C or
C++ by default, however support for them can be enabled using the
directive:
<PRE>
#pragma TenDRA longlong type <I>allow</I>
</PRE>
This support includes allowing <CODE>long long</CODE> in type specifiers
and allowing <CODE>LL</CODE> and <CODE>ll</CODE> as integer literal
suffixes.
</P>
<P>
There is a further directive given by the two cases:
<PRE>
#pragma TenDRA set longlong type : long long
#pragma TenDRA set longlong type : long
</PRE>
which can be used to control the implementation of the <CODE>long
long</CODE> types. Either they can be mapped to the
<A HREF="lib.html#arith">default representation</A>, which is guaranteed
to contain at least 64 bits, or they can be mapped to the corresponding
<CODE>long</CODE> types.
</P>
<P>
Because these <CODE>long long</CODE> types are not an intrinsic part
of C++ the implementation does not integrate them into the language
as fully as is possible. This is to prevent the presence or otherwise
of
<CODE>long long</CODE> types affecting the semantics of code which
does not use them. For example, it would be possible to extend the
rules for the types of integer literals, integer promotion types and
arithmetic types to say that if the given value does not fit into
the standard integral types then the extended types are tried. This
has not been done, although these rules could be implemented by changing
the definitions of the <A HREF="lib.html#arith">standard tokens</A>
used to determine these types. By default, only the rules for arithmetic
types involving a <CODE>long long</CODE> operand and for <CODE>LL</CODE>
integer literals mention <CODE>long long</CODE> types.
</P>
<HR>
<H3><A NAME="bitfield">2.2.24. Bitfield types</A></H3>
<P>
The C++ rules on bitfield types differ slightly from the C rules.
Firstly any integral or enumeration type is allowed in a bitfield,
and secondly the bitfield width may exceed the underlying type size
(the extra bits being treated as padding). These properties can be
controlled using the directives:
<PRE>
#pragma TenDRA extra bitfield int type <I>allow</I>
#pragma TenDRA bitfield overflow <I>allow</I>
</PRE>
respectively.
</P>
<HR>
<H3><A NAME="elab">2.2.25. Elaborated type specifiers</A></H3>
<P>
In elaborated type specifiers, the class key (<CODE>class</CODE>,
<CODE>struct</CODE>, <CODE>union</CODE> or <CODE>enum</CODE>) should
agree with any previous declaration of the type (except that <CODE>class</CODE>
and <CODE>struct</CODE> are interchangeable). This requirement can
be relaxed using the directive:
<PRE>
#pragma TenDRA ignore struct/union/enum tag <I>on</I>
</PRE>
</P>
<P>
In ISO C and C++ it is not possible to give a forward declaration
of an enumeration type. This constraint can be relaxed using the
directive:
<PRE>
#pragma TenDRA forward enum declaration <I>allow</I>
</PRE>
Until the end of its definition, an enumeration type is treated as
an incomplete type (as with class types). In enumeration definitions,
and a couple of other contexts where comma-separated lists are required,
the directive:
<PRE>
#pragma TenDRA extra , <I>allow</I>
</PRE>
can be used to allow a trailing comma at the end of the list.
</P>
<P>
The directive:
<PRE>
#pragma TenDRA complete struct/union analysis <I>on</I>
</PRE>
can be used to enable a check that every class or union has been completed
within each translation unit in which it is declared.
</P>
<HR>
<H3><A NAME="impl_func">2.2.26. Implicit function declarations</A></H3>
<P>
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:
<PRE>
#pragma TenDRA implicit function declaration <I>on</I>
</PRE>
Such implicitly declared functions have C linkage and type
<CODE>int ( ... )</CODE>.
</P>
<HR>
<H3><A NAME="weak">2.2.27. Weak function prototypes</A></H3>
<P>
The C producer supports a concept, weak prototypes, whereby type checking
can be applied to the arguments of a non-prototype function. This
checking can be enabled using the directive:
<PRE>
#pragma TenDRA weak prototype analysis <I>on</I>
</PRE>
The concept of weak prototypes is not applicable to C++, where all
functions are prototyped. The C++ producer does allow the syntax
for explicit weak prototype declarations, but treats them as if they
were normal prototypes. These declarations are denoted by means of
a keyword,
<CODE>WEAK</CODE> say, introduced by the directive:
<PRE>
#pragma TenDRA keyword <I>identifier</I> for weak
</PRE>
preceding the <CODE>(</CODE> of the function declarator. The directives:
<PRE>
#pragma TenDRA prototype <I>allow</I>
#pragma TenDRA prototype (weak) <I>allow</I>
</PRE>
which can be used in the C producer to warn of prototype or weak prototype
declarations, are similarly ignored by the C++ producer.
</P>
<P>
The C producer also allows the directives:
<PRE>
#pragma TenDRA argument <I>type-id</I> as <I>type-id</I>
#pragma TenDRA argument <I>type-id</I> as ...
#pragma TenDRA extra ... <I>allow</I>
#pragma TenDRA incompatible promoted function argument <I>allow</I>
</PRE>
which control the compatibility of function types. These directives
are ignored by the C++ producer (some of them would make sense in
the context of C++ but would over-complicate function overloading).
</P>
<HR>
<H3><A NAME="printf">2.2.28. <CODE>printf</CODE> and <CODE>scanf</CODE>
argument checking</A></H3>
<P>
The C producer includes a number of checks that the arguments in a
call to a function in the <CODE>printf</CODE> or <CODE>scanf</CODE>
families match the given format string. The check is implemented
by using the directives:
<PRE>
#pragma TenDRA type <I>identifier</I> for ... printf
#pragma TenDRA type <I>identifier</I> for ... scanf
</PRE>
to introduce a type representing a <CODE>printf</CODE> or <CODE>scanf</CODE>
format string. For most purposes this type is treated as <CODE>const
char *</CODE>, but when it appears in a function declaration it alerts
the producer that any extra arguments passed to that function should
match the format string passed as the corresponding argument. The
TenDRA API headers conditionally declare <CODE>printf</CODE>,
<CODE>scanf</CODE> and similar functions in something like the form:
<PRE>
#ifdef __NO_PRINTF_CHECKS
typedef const char *__printf_string ;
#else
#pragma TenDRA type __printf_string for ... printf
#endif
int printf ( __printf_string, ... ) ;
int fprintf ( FILE *, __printf_string, ... ) ;
int sprintf ( char *, __printf_string, ... ) ;
</PRE>
These declarations can be skipped, effectively disabling this check,
by defining the <CODE>__NO_PRINTF_CHECKS</CODE> macro.
</P>
<P>
<IMG SRC="../images/warn.gif" ALT="warning">
These <CODE>printf</CODE> and <CODE>scanf</CODE> format string checks
have not yet been implemented in the C++ producer due to presence
of an alternative, type checked, I/O package - namely
<CODE><iostream></CODE>. The format string types are simply
treated as <CODE>const char *</CODE>.
</P>
<HR>
<H3><A NAME="typedef">2.2.29. Type declarations</A></H3>
<P>
C does not allow multiple definitions of a <CODE>typedef</CODE> name,
whereas C++ allows multiple consistent definitions. This behaviour
can be controlled using the directive:
<PRE>
#pragma TenDRA extra type definition <I>allow</I>
</PRE>
</P>
<HR>
<H3><A NAME="compatible">2.2.30. Type compatibility</A></H3>
<P>
The directive:
<PRE>
#pragma TenDRA incompatible type qualifier <I>allow</I>
</PRE>
allows objects to be redeclared with different cv-qualifiers (normally
such redeclarations would be incompatible). The composite type is
qualified using the join of the cv-qualifiers in the various redeclarations.
</P>
<P>
The directive:
<PRE>
#pragma TenDRA compatible type : <I>type-id</I> == <I>type-id</I> : <I>allow
</I>
</PRE>
asserts that the given two types are compatible. Currently the only
implemented version is <CODE>char * == void *</CODE> which enables
<CODE>char *</CODE> to be used as a generic pointer as it was in older
dialects of C.
</P>
<HR>
<H3><A NAME="complete">2.2.31. Incomplete types</A></H3>
<P>
Some dialects of C allow incomplete arrays as member types. These
are generally used as a place-holder at the end of a structure to
allow for the allocation of an arbitrarily sized array. Support for
this feature can be enabled using the directive:
<PRE>
#pragma TenDRA incomplete type as object type <I>allow</I>
</PRE>
</P>
<HR>
<H3><A NAME="conv">2.2.32. Type conversions</A></H3>
<P>
There are a number of directives which allow various classes of type
conversion to be checked. The directives:
<PRE>
#pragma TenDRA conversion analysis (int-int explicit) <I>on</I>
#pragma TenDRA conversion analysis (int-int implicit) <I>on</I>
</PRE>
will check for unsafe explicit or implicit conversions between arithmetic
types. Similarly conversions between pointers and arithmetic types
can be checked using:
<PRE>
#pragma TenDRA conversion analysis (int-pointer explicit) <I>on</I>
#pragma TenDRA conversion analysis (int-pointer implicit) <I>on</I>
</PRE>
or equivalently:
<PRE>
#pragma TenDRA conversion analysis (pointer-int explicit) <I>on</I>
#pragma TenDRA conversion analysis (pointer-int implicit) <I>on</I>
</PRE>
Conversions between pointer types can be checked using:
<PRE>
#pragma TenDRA conversion analysis (pointer-pointer explicit) <I>on</I>
#pragma TenDRA conversion analysis (pointer-pointer implicit) <I>on</I>
</PRE>
</P>
<P>
There are some further variants which can be used to enable useful
sets of conversion checks. For example:
<PRE>
#pragma TenDRA conversion analysis (int-int) <I>on</I>
</PRE>
enables both implicit and explicit arithmetic conversion checks.
The directives:
<PRE>
#pragma TenDRA conversion analysis (int-pointer) <I>on</I>
#pragma TenDRA conversion analysis (pointer-int) <I>on</I>
#pragma TenDRA conversion analysis (pointer-pointer) <I>on</I>
</PRE>
are equivalent to their corresponding explicit forms (because the
implicit forms are illegal by default). The directive:
<PRE>
#pragma TenDRA conversion analysis <I>on</I>
</PRE>
is equivalent to the four directives just given. It enables checks
on implicit and explicit arithmetic conversions, explicit arithmetic
to pointer conversions and explicit pointer conversions.
</P>
<P>
The default settings for these checks are determined by the implicit
and explicit conversions allowed in C++. Note that there are differences
between the conversions allowed in C and C++. For example, an arithmetic
type can be converted implicitly to an enumeration type in C, but
not in C++. The directive:
<PRE>
#pragma TenDRA conversion analysis (int-enum implicit) <I>on</I>
</PRE>
can be used to control the status of this conversion. The level of
severity for an error message arising from such a conversion is the
maximum of the severity set by this directive and that set by the
<CODE>int-int implicit</CODE> directive above.
</P>
<P>
The implicit pointer conversions described above do not include conversions
to and from the generic pointer <CODE>void *</CODE>, which have their
own controlling directives. A pointer of type <CODE>void *</CODE>
can be converted implicitly to another pointer type in C but not in
C++; this is controlled by the directive:
<PRE>
#pragma TenDRA++ conversion analysis (void*-pointer implicit) <I>on</I>
</PRE>
The reverse conversion, from a pointer type to <CODE>void *</CODE>
is allowed in both C and C++, and has a controlling directive:
<PRE>
#pragma TenDRA++ conversion analysis (pointer-void* implicit) <I>on</I>
</PRE>
</P>
<P>
In ISO C and C++, a function pointer can only be cast to other function
pointers, not to object pointers or <CODE>void *</CODE>. Many dialects
however allow function pointers to be cast to and from other pointers.
This behaviour can be controlled using the directive:
<PRE>
#pragma TenDRA function pointer as pointer <I>allow</I>
</PRE>
which causes function pointers to be treated in the same way as all
other pointers.
</P>
<P>
The integer conversion checks described above only apply to unsafe
conversions. A simple-minded check for shortening conversions is
not adequate, as is shown by the following example:
<PRE>
char a = 1, b = 2 ;
char c = a + b ;
</PRE>
the sum <CODE>a + b</CODE> is evaluated as an <CODE>int</CODE> which
is then shortened to a <CODE>char</CODE>. Any check which does not
distinguish this sort of "safe" shortening conversion from
unsafe shortening conversions such as:
<PRE>
int a = 1, b = 2 ;
char c = a + b ;
</PRE>
is not likely to be very useful. The producer therefore associates
two types with each integral expression; the first is the normal,
representation type and the second is the underlying, semantic type.
Thus in the first example, the representation type of <CODE>a + b</CODE>
is <CODE>int</CODE>, but semantically it is still a <CODE>char</CODE>.
The conversion analysis is based on the semantic types.
</P>
<P>
<IMG SRC="../images/warn.gif" ALT="warning">
The C producer supports a directive:
<PRE>
#pragma TenDRA keyword <I>identifier</I> for type representation
</PRE>
whereby a keyword can be introduced which can be used to explicitly
declare a type with given representation and semantic components.
Unfortunately this makes the <A HREF="parse.html">C++ grammar</A>
ambiguous, so it has not yet been implemented in the C++ producer.
</P>
<P>
It is possible to allow individual conversions by means of conversion
tokens. A <A HREF="token.html">procedure token</A> which takes one
rvalue expression program parameter and returns an rvalue expression,
such as:
<PRE>
#pragma token PROC ( EXP : t : ) EXP : s : conv #
</PRE>
can be regarded as mapping expressions of type <CODE>t</CODE> to expressions
of type <CODE>s</CODE>. The directive:
<PRE>
#pragma TenDRA conversion <I>identifier-list</I> allow
</PRE>
can be used to nominate such a token as a conversion token. That
is to say, if the conversion, whether explicit or implicit, from <CODE>t</CODE>
to <CODE>s</CODE> cannot be done by other means, it is done by applying
the token <CODE>conv</CODE>, so:
<PRE>
t a ;
s b = a ; // maps to conv ( a )
</PRE>
Note that, unlike conversion functions, conversion tokens can be applied
to any types.
</P>
<HR>
<H3><A NAME="cast">2.2.33. Cast expressions</A></H3>
<P>
ISO C++ introduces the constructs <CODE>static_cast</CODE>,
<CODE>const_cast</CODE> and <CODE>reinterpret_cast</CODE>, which can
be used in various contexts where an old style explicit cast would
previously have been used. By default, an explicit cast can perform
any combination of the conversions performed by these three constructs.
To aid migration to the new style casts the directives:
<PRE>
#pragma TenDRA++ explicit cast as <I>cast-state allow</I>
#pragma TenDRA++ explicit cast <I>allow</I>
</PRE>
where <I>cast-state</I> is defined as follows:
<PRE>
<I>cast-state</I> :
static_cast
const_cast
reinterpret_cast
static_cast | <I>cast-state</I>
const_cast | <I>cast-state</I>
reinterpret_cast | <I>cast-state</I>
</PRE>
can be used to restrict the conversions which can be performed using
explicit casts. The first form sets the interpretation of explicit
cast to be combinations of the given constructs; the second resets
the interpretation to the default. For example:
<PRE>
#pragma TenDRA++ explicit cast as static_cast | const_cast allow
</PRE>
means that conversions requiring <CODE>reinterpret_cast</CODE> (the
most unportable conversions) will not be allowed to be performed using
explicit casts, but will have to be given as a <CODE>reinterpret_cast</CODE>
construct. Changing <CODE>allow</CODE> to <CODE>warning</CODE> will
also cause a warning to be issued for every explicit cast expression.
</P>
<HR>
<H3><A NAME="ellipsis">2.2.34. Ellipsis functions</A></H3>
<P>
The directive:
<PRE>
#pragma TenDRA ident ... <I>allow</I>
</PRE>
may be used to enable or disable the use of <CODE>...</CODE> as a
primary expression in a function defined with ellipsis. The type
of such an expression is implementation defined. This expression
is used in the definition of the <A HREF="lib.html#ellipsis"><CODE>va_start
</CODE>
macro</A> in the <CODE><stdarg.h></CODE> header. This header
automatically enables this switch.
</P>
<HR>
<H3><A NAME="overload">2.2.35. Overloaded functions</A></H3>
<P>
Older dialects of C++ did not report ambiguous overloaded function
resolutions, but instead resolved the call to the first of the most
viable candidates to be declared. This behaviour can be controlled
using the directive:
<PRE>
#pragma TenDRA++ ambiguous overload resolution <I>allow</I>
</PRE>
There are occasions when the resolution of an overloaded function
call is not clear. The directive:
<PRE>
#pragma TenDRA++ overload resolution <I>allow</I>
</PRE>
can be used to report the resolution of any such call (whether explicit
or implicit) where there is more than one viable candidate.
</P>
<P>
An interesting consequence of compiling C++ in a target independent
manner is that certain overload resolutions can only be determined
at install-time. For example, in:
<PRE>
int f ( int ) ;
int f ( unsigned int ) ;
int f ( long ) ;
int f ( unsigned long ) ;
int a = f ( sizeof ( int ) ) ; // which f?
</PRE>
the type of the <CODE>sizeof</CODE> operator, <CODE>size_t</CODE>,
is target dependent, but its promotion must be one of the types
<CODE>int</CODE>, <CODE>unsigned int</CODE>, <CODE>long</CODE> or
<CODE>unsigned long</CODE>. Thus the call to <CODE>f</CODE> always
has a unique resolution, but what it is is target dependent. The
equivalent directives:
<PRE>
#pragma TenDRA++ conditional overload resolution <I>allow</I>
#pragma TenDRA++ conditional overload resolution (complete) <I>allow</I>
</PRE>
can be used to warn about such target dependent overload resolutions.
By default, such resolutions are only allowed if there is a unique
resolution for each possible implementation of the argument types
(note that, for simplicity, the possibility of <CODE>long long</CODE>
implementation types is ignored). The directive:
<PRE>
#pragma TenDRA++ conditional overload resolution (incomplete) <I>allow</I>
</PRE>
can be used to allow target dependent overload resolutions which only
have resolutions for some of the possible implementation types (if
one of the <CODE>f</CODE> declarations above was removed, for example).
If the implementation does not match one of these types then an install-time
error is given.
</P>
<P>
There are restrictions on the set of candidate functions involved
in a target dependent overload resolution. Most importantly, it should
be possible to bring their return types to a common type, as if by
a series of <CODE>?:</CODE> operations. This common type is the type
of the target dependent call. By this means, target dependent types
are prevented from propagating further out into the program. Note
that since sets of overloaded functions usually have the same semantics,
this does not usually present a problem.
</P>
<HR>
<H3><A NAME="exp">2.2.36. Expressions</A></H3>
<P>
The directive:
<PRE>
#pragma TenDRA operator precedence analysis <I>on</I>
</PRE>
can be used to enable a check for expressions where the operator precedence
is not necessarily what might be expected. The intended precedence
can be clarified by means of explicit parentheses. The precedence
levels checked are as follows:
<OL>
<LI><CODE>&&</CODE> versus <CODE>||</CODE>.
<LI><CODE><<</CODE> and <CODE>>></CODE> versus binary
<CODE>+</CODE> and <CODE>-</CODE>.
<LI>Binary <CODE>&</CODE> versus binary <CODE>+</CODE>, <CODE>-</CODE>,
<CODE>==</CODE>, <CODE>!=</CODE>, <CODE>></CODE>, <CODE>>=</CODE>,
<CODE><</CODE> and <CODE><=</CODE>.
<LI><CODE>^</CODE> versus binary <CODE>&</CODE>, <CODE>+</CODE>,
<CODE>-</CODE>, <CODE>==</CODE>, <CODE>!=</CODE>, <CODE>></CODE>,
<CODE>>=</CODE>, <CODE><</CODE> and <CODE><=</CODE>.
<LI><CODE>|</CODE> versus binary <CODE>^</CODE>, <CODE>&</CODE>,
<CODE>+</CODE>, <CODE>-</CODE>, <CODE>==</CODE>, <CODE>!=</CODE>,
<CODE>></CODE>, <CODE>>=</CODE>, <CODE><</CODE> and <CODE><=
</CODE>.
</OL>
Also checked are expressions such as <CODE>a < b < c</CODE>
which do not have their normal mathematical meaning. For example,
in:
<PRE>
d = a << b + c ; // precedence is a << ( b + c )
</PRE>
the precedence is counter-intuitive, although strangely enough, it
isn't in:
<PRE>
cout << b + c ; // precedence is cout << ( b + c )
</PRE>
</P>
<P>
Other dubious arithmetic operations can be checked for using the directive:
<PRE>
#pragma TenDRA integer operator analysis <I>on</I>
</PRE>
This includes checks for operations, such as division by a negative
value, which are implementation dependent, and those such as testing
whether an unsigned value is less than zero, which serve no purpose.
Similarly the directive:
<PRE>
#pragma TenDRA++ pointer operator analysis <I>on</I>
</PRE>
checks for dubious pointer operations. This includes very simple
bounds checking for arrays and checking that only the simple literal
<CODE>0</CODE>
is used in null pointer constants:
<PRE>
char *p = 1 - 1 ; // valid, but weird
</PRE>
</P>
<P>
The directive:
<PRE>
#pragma TenDRA integer overflow analysis <I>on</I>
</PRE>
is used to control the treatment of overflows in the evaluation of
integer constant expressions. This includes the detection of division
by zero.
</P>
<HR>
<H3><A NAME="init">2.2.37. Initialiser expressions</A></H3>
<P>
C, but not C++, only allows constant expressions in static initialisers.
The directive:
<PRE>
#pragma TenDRA variable initialization <I>allow</I>
</PRE>
can be enable support for C++-style dynamic initialisers. Conversely,
it can be used in C++ to detect such dynamic initialisers.
</P>
<P>
In older dialects of C it was not possible to initialise an automatic
variable of structure or union type. This can be checked for using
the directive:
<PRE>
#pragma TenDRA initialization of struct/union (auto) <I>allow</I>
</PRE>
</P>
<P>
The directive:
<PRE>
#pragma TenDRA++ complete initialization analysis <I>on</I>
</PRE>
can be used to check aggregate initialisers. The initialiser should
be fully bracketed (i.e. with no elision of braces), and should have
an entry for each member of the structure or array.
</P>
<HR>
<H3><A NAME="lvalue">2.2.38. Lvalue expressions</A></H3>
<P>
C++ defines the results of several operations to be lvalues, whereas
they are rvalues in C. The directive:
<PRE>
#pragma TenDRA conditional lvalue <I>allow</I>
</PRE>
is used to apply the C++ rules for lvalues in conditional (<CODE>?:</CODE>)
expressions.
</P>
<P>
Older dialects of C++ allowed <CODE>this</CODE> to be treated as an
lvalue. It is possible to enable support for this dialect feature
using the directive:
<PRE>
#pragma TenDRA++ this lvalue <I>allow</I>
</PRE>
however it is recommended that programs using this feature should
be modified.
</P>
<HR>
<H3><A NAME="discard">2.2.39. Discarded expressions</A></H3>
<P>
The directive:
<PRE>
#pragma TenDRA discard analysis <I>on</I>
</PRE>
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:
<PRE>
#pragma TenDRA discard analysis (function return) <I>on</I>
</PRE>
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:
<PRE>
#pragma TenDRA discard analysis (value) <I>on</I>
</PRE>
checks for other expressions which are not used. Finally, the directive:
<PRE>
#pragma TenDRA discard analysis (static) <I>on</I>
</PRE>
checks for variables with internal linkage which are defined but not
used.
</P>
<P>
An unused function return or other expression can be asserted to be
deliberately discarded by explicitly casting it to <CODE>void</CODE>
or, equivalently, preceding it by a keyword introduced using the directive:
<PRE>
#pragma TenDRA keyword <I>identifier</I> for discard value
</PRE>
A static variable can be asserted to be deliberately unused by including
it in list of identifiers in a directive of the form:
<PRE>
#pragma TenDRA suspend static <I>identifier-list</I>
</PRE>
</P>
<HR>
<H3><A NAME="if">2.2.40. Conditional and iteration statements</A></H3>
<P>
The directive:
<PRE>
#pragma TenDRA const conditional <I>allow</I>
</PRE>
can be used to enable a check for constant expressions used in conditional
contexts. A literal constant is allowed in the condition of a <CODE>while
</CODE>, <CODE>for</CODE> or <CODE>do</CODE> statement to allow for
such common constructs as:
<PRE>
while ( true ) {
// while statement body
}
</PRE>
and target dependent constant expressions are allowed in the condition
of an <CODE>if</CODE> statement, but otherwise constant conditions
are reported according to the status of this check.
</P>
<P>
The common error of writing <CODE>=</CODE> rather than <CODE>==</CODE>
in conditions can be detected using the directive:
<PRE>
#pragma TenDRA assignment as bool <I>allow</I>
</PRE>
which can be used to disallow such assignment expressions in contexts
where a boolean is expected. The error message can be suppressed
by enclosing the assignment within parentheses.
</P>
<P>
Another common error associated with iteration statements, particularly
with certain <A HREF="style.html">heretical</A> brace styles, is the
accidental insertion of an extra semicolon as in:
<PRE>
for ( init ; cond ; step ) ;
{
// for statement body
}
</PRE>
The directive:
<PRE>
#pragma TenDRA extra ; after conditional <I>allow</I>
</PRE>
can be used to enable a check for such suspicious empty iteration
statement bodies (it actually checks for <CODE>;{</CODE>).
</P>
<HR>
<H3><A NAME="switch">2.2.41. Switch statements</A></H3>
<P>
A <CODE>switch</CODE> statement is said to be exhaustive if its control
statement is guaranteed to take one of the values of its
<CODE>case</CODE> labels, or if it has a <CODE>default</CODE> label.
The TenDRA C and C++ producers allow a <CODE>switch</CODE> statement
to be asserted to be exhaustive using the syntax:
<PRE>
switch ( cond ) EXHAUSTIVE {
// switch statement body
}
</PRE>
where <CODE>EXHAUSTIVE</CODE> is either the directive:
<PRE>
#pragma TenDRA exhaustive
</PRE>
or a keyword introduced using:
<PRE>
#pragma TenDRA keyword <I>identifier</I> for exhaustive
</PRE>
Knowing whether a <CODE>switch</CODE> statement is exhaustive or not
means that checks relying on flow analysis (including variable usage
checks) can be applied more precisely.
</P>
<P>
In certain circumstances it is possible to deduce whether a
<CODE>switch</CODE> statement is exhaustive or not. For example,
the directive:
<PRE>
#pragma TenDRA enum switch analysis <I>on</I>
</PRE>
enables a check on <CODE>switch</CODE> statements on values of enumeration
type. Such statements should be exhaustive, either explicitly by
using the <CODE>EXHAUSTIVE</CODE> keyword or declaring a
<CODE>default</CODE> label, or implicitly by having a <CODE>case</CODE>
label for each enumerator. Conversely, the value of each <CODE>case</CODE>
label should equal the value of an enumerator. For the purposes of
this check, boolean values are treated as if they were declared using
an enumeration type of the form:
<PRE>
enum bool { false = 0, true = 1 } ;
</PRE>
</P>
<P>
A common source of errors in <CODE>switch</CODE> statements is the
fall-through from one <CODE>case</CODE> or <CODE>default</CODE>
statement to the next. A check for this can be enabled using:
<PRE>
#pragma TenDRA fall into case <I>allow</I>
</PRE>
<CODE>case</CODE> or <CODE>default</CODE> labels where fall-through
from the previous statement is intentional can be marked by preceding
them by a keyword, <CODE>FALL_THRU</CODE> say, introduced using the
directive:
<PRE>
#pragma TenDRA keyword <I>identifier</I> for fall into case
</PRE>
</P>
<HR>
<H3><A NAME="for">2.2.42. For statements</A></H3>
<P>
In ISO C++ the scope of a variable declared in a for-init-statement
is the body of the <CODE>for</CODE> statement; in older dialects it
extended to the end of the enclosing block. So:
<PRE>
for ( int i = 0 ; i < 10 ; i++ ) {
// for statement body
}
return i ; // OK in older dialects, error in ISO C++
</PRE>
This behaviour is controlled by the directive:
<PRE>
#pragma TenDRA++ for initialization block <I>on</I>
</PRE>
a state of <CODE>on</CODE> corresponding to the ISO rules and
<CODE>off</CODE> to the older rules. Perhaps most useful is the
<CODE>warning</CODE> state which implements the old rules but gives
a warning if a variable declared in a for-init-statement is used outside
the corresponding <CODE>for</CODE> statement body. A program which
does not give such warnings should compile correctly under either
set of rules.
</P>
<HR>
<H3><A NAME="return">2.2.43. Return statements</A></H3>
<P>
In C, but not in C++, it is possible to have a <CODE>return</CODE>
statement without an expression in a function which does not return
<CODE>void</CODE>. It is possible to enable this behaviour using
the directive:
<PRE>
#pragma TenDRA incompatible void return <I>allow</I>
</PRE>
Note that this check includes the implicit <CODE>return</CODE> caused
by falling off the end of a function. The effect of such a
<CODE>return</CODE> statement is undefined. The C++ rule that falling
off the end of <CODE>main</CODE> is equivalent to returning a value
of 0 overrides this check.
</P>
<HR>
<H3><A NAME="reach">2.2.44. Unreached code analysis</A></H3>
<P>
The directive:
<PRE>
#pragma TenDRA unreachable code <I>allow</I>
</PRE>
enables a flow analysis check to detect unreachable code. It is possible
to assert that a statement is reached or not reached by preceding
it by a keyword introduced by one of the directives:
<PRE>
#pragma TenDRA keyword <I>identifier</I> for set reachable
#pragma TenDRA keyword <I>identifier</I> for set unreachable
</PRE>
</P>
<P>
The fact that certain functions, such as <CODE>exit</CODE>, do not
return a value can be exploited in the flow analysis routines. The
equivalent directives:
<PRE>
#pragma TenDRA bottom <I>identifier</I>
#pragma TenDRA++ type <I>identifier</I> for bottom
</PRE>
can be used to introduce a <CODE>typedef</CODE> declaration for the
type, bottom, returned by such functions. The TenDRA API headers
declare
<CODE>exit</CODE> and similar functions in this way, for example:
<PRE>
#pragma TenDRA bottom __bottom
__bottom exit ( int ) ;
__bottom abort ( void ) ;
</PRE>
The bottom type is compatible with <CODE>void</CODE> in function declarations
to allow such functions to be redeclared in their conventional form.
</P>
<HR>
<H3><A NAME="variable">2.2.45. Variable flow analysis</A></H3>
<P>
The directive:
<PRE>
#pragma TenDRA variable analysis <I>on</I>
</PRE>
enables checks on the uses of automatic variables and function parameters.
These checks detect:
<OL>
<LI>If a variable is not used in its scope.
<LI>If the value of a variable is used before it has been assigned
to.
<LI>If a variable is assigned to twice without an intervening use.
<LI>If a variable is assigned to twice without an intervening sequence
point.
</OL>
as illustrated by the variables <CODE>a</CODE>, <CODE>b</CODE>,
<CODE>c</CODE> and <CODE>d</CODE> respectively in:
<PRE>
void f ()
{
int a ; // a never used
int b ;
int c = b ; // b not initialised
c = 0 ; // c assigned to twice
int d = 0 ;
d = ++d ; // d assigned to twice
}
</PRE>
The second, and more particularly the third, of these checks requires
some fairly sophisticated flow analysis, so any hints which can be
picked up from <A HREF="#switch">exhaustive <CODE>switch</CODE>
statements</A> etc. is likely to increase the accuracy of the errors
detected.
</P>
<P>
In a non-static member function the various non-static data members
are analysed as if they were automatic variables. It is checked that
each member is initialised in a constructor. A common source of initialisation
problems in a constructor is that the base classes and members are
initialised in the canonical order of virtual bases, non-virtual direct
bases and members in the order of their declaration, rather than in
the order in which their initialisers appear in the constructor definition.
Therefore a check that the initialisers appear in the canonical order
is also applied.
</P>
<P>
It is possible to change the state of a variable during the variable
analysis using the directives:
<PRE>
#pragma TenDRA set <I>expression</I>
#pragma TenDRA discard <I>expression</I>
</PRE>
The first asserts that the variable given by the <I>expression</I>
has been assigned to; the second asserts that the variable is not
used. An alternative way of expressing this is by means of keywords:
<PRE>
SET ( <I>expression</I> )
DISCARD ( <I>expression</I> )
</PRE>
introduced using the directives.
<PRE>
#pragma TenDRA keyword <I>identifier</I> for set
#pragma TenDRA keyword <I>identifier</I> for discard variable
</PRE>
respectively. These expressions can appear in expression statements
and as the first argument of a comma expression.
</P>
<P>
<IMG SRC="../images/warn.gif" ALT="warning">
The variable flow analysis checks have not yet been completely implemented.
They may not detect errors in certain circumstances and for extremely
convoluted code may occasionally give incorrect errors.
</P>
<HR>
<H3><A NAME="hide">2.2.46. Variable hiding</A></H3>
<P>
The directive:
<PRE>
#pragma TenDRA variable hiding analysis <I>on</I>
</PRE>
can be used to enable a check for hiding of other variables and, in
member functions, data members, by local variable declarations.
</P>
<HR>
<H3><A NAME="exception">2.2.47. Exception analysis</A></H3>
<P>
The ISO C++ rules do not require exception specifications to be checked
statically. This is to facilitate the integration of large systems
where a single change in an exception specification could have ramifications
throughout the system. However it is often useful to apply such checks,
which can be enabled using the directive:
<PRE>
#pragma TenDRA++ throw analysis <I>on</I>
</PRE>
This detects any potentially uncaught exceptions and other exception
problems. In the error messages arising from this check, an uncaught
exception of type <CODE>...</CODE> means that an uncaught exception
of an unknown type (arising, for example, from a function without
an exception specification) may be thrown. For example:
<PRE>
void f ( int ) throw ( int ) ;
void g ( int ) throw ( long ) ;
void h ( int ) ;
void e () throw ( int )
{
f ( 1 ) ; // OK
g ( 2 ) ; // uncaught 'long' exception
h ( 3 ) ; // uncaught '...' exception
}
</PRE>
</P>
<HR>
<H3><A NAME="template">2.2.48. Template compilation</A></H3>
<P>
The C++ producer makes the distinction between exported templates,
which may be used in one module and defined in another, and non-exported
templates, which must be defined in every module in which they are
used. As in the ISO C++ standard, the <CODE>export</CODE> keyword
is used to distinguish between the two cases. In the past, different
compilers have had different template compilation models; either all
templates were exported or no templates were exported. The latter
is easily emulated - if the <CODE>export</CODE> keyword is not used
then no templates will be exported. To emulate the former behaviour
the directive:
<PRE>
#pragma TenDRA++ implicit export template <I>on</I>
</PRE>
can be used to treat all templates as if they had been declared using
the <CODE>export</CODE> keyword.
</P>
<P>
<IMG SRC="../images/warn.gif" ALT="warning">
The automatic instantiation of exported templates has not yet been
implemented correctly. It is intended that such instantiations will
be generated during <A HREF="link.html">intermodule analysis</A>
(where they conceptually belong). At present it is necessary to work
round this using explicit instantiations.
</P>
<HR>
<H3><A NAME="catch_all">2.2.49. Other checks</A></H3>
<P>
Several checks of varying utility have been implemented in the C++
producer but do not as yet have individual directives controlling
their use. These can be enabled <I>en masse</I> using the directive:
<PRE>
#pragma TenDRA++ catch all <I>allow</I>
</PRE>
It is intended that this directive will be phased out as these checks
are assigned controlling directives. It is possible to achieve finer
control over these checks by enabling their individual error messages
<A HREF="#low">as described above</A>.
</P>
<HR>
<P><I>Part of the <A HREF="../index.html">TenDRA Web</A>.<BR>Crown
Copyright © 1998.</I></P>
</BODY>
</HTML>