The user must now specify how they want volatility handled in
WITH statements if they use volatile records or pointers. The "top
type" of the WITH expression is checked for a volatile record or
pointer and an error is generated if the user has not specified how
it should be handled. A new compiler option
$VOLATILE_WITH has been added to allow the user to tell the
compiler what it should do in this situation:
$VOLATILE_WITH 0$ : do not make WITH temps volatile. This will
generate the most efficient code, but may not be "safe."
$VOLATILE_WITH 1$ : make the WITH temp volatile if the top level
record type is volatile. (This is provided for completeness, it is
unclear how useful it would be.)
$VOLATILE_WITH 2$ : make the WITH temp volatile if the top level
record type or pointer to the top level record type is volatile.
This is the safest alternative, at the cost of code efficiency.
When a WITH statement is seen, the $VOLATILE_WITH level currently
in effect will be applied to all WITH result pointers (temps) for
that statement.
Only the "top type" is checked, because it is
unlikely that a user will want the temp volatility to be based on
every level of the whole expression. We go down one level to the
first pointer because the pointer/pointed-to-type misunderstanding
may be commonplace, given the previous ambiguity in volatile
declarations.
If the "top type" in a WITH expression contains a
volatile, you will get the following error message:
VOLATILE RECORD OR POINTER IN WITH EXPRESSION;
$VOLATILE_WITH REQUIRED (895)
If you encounter this error, you should consider what you want to be
volatile, possibly change your type declarations if they are
incorrect, and add the appropriate $VOLATILE_WITH option.
For example, given the original code fragments:
ptr_type = ^ $extnaddr,VOLATILE$ mytype;
...
var l_dptr : ptr_type; {l_dptr is volatile}
...
with ..., l_dptr^ {l_dptr is volatile, l_dptr^ is not}
To generate the safest code, simply insert a $VOLATILE_WITH 2$ option
at some point before the WITH statement. This will cause the
suspicious WITH temp to be volatile; the compiler will generate code
to always reload the temp and all subsequent expressions based on the
temp. With this change, the WITH temp is reloaded on each reference,
and all loads and stores through that pointer are present in the
generated code. To generate more efficient code, carefully examine
the type declarations to be sure you know what you want to be
volatile. In this example, the thing that the user really wants to be
volatile is the record type being pointed to, and the WITH temp (a
pointer to that record type) should not be volatile. This means that
ptr_type should be changed to a pointer to a volatile, and the
$VOLATILE_WITH 0$ option can be used.
For example:
ptr_type = ^ $extnaddr$ v_mytype;
v_mytype = $VOLATILE$ mytype;
...
var l_dptr : ptr_type; {l_dptr^ is volatile}
...
$VOLATILE_WITH 0$
with ..., l_dptr^
With these changes, the WITH temp is not reloaded on each reference,
but all loads and stores into the record are present in the generated
code since the pointed-to record is volatile.
Another alternative is
to remove the suspicious WITH expression from the WITH statement and
expand all references in the WITH body. Depending on the complexity
of the expression and what parts are volatile, the efficiency of the
generated code might be the same as using a WITH.