Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Discard reference and identifier -- SIMICS-21584 #237

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
37 changes: 37 additions & 0 deletions RELEASENOTES-1.4.md
Original file line number Diff line number Diff line change
@@ -356,3 +356,40 @@
The bugfix is opt-in, because an immediate bugfix would risk breaking existing builds; the error will only be reported when the flag `--no-compat=broken_unused_types` is passed to DMLC. This flag will be automatically enabled in Simics 8.
- `release 7 7063`
- `release 6 6362`
- `note 6` Added the _discard reference_ '`_`' — a non-value expression
which may be used as an assign target in order to explictly discard the result
of an evaluated expression or return value of a method call (fixes
SIMICS-21584.)

Example usage:
```
_ = any_expression;
_ = throwing_method();
(_, x, _) = method_with_multiple_return_values();
```
- `note 6` '`_`' can no longer be used as the name for arbitrary declarations.
Instead, it is now only permitted in particular contexts, and in these
contexts, '`_`' will affect the declaration in a way suitable for when the
declaration is _unused_ in some particular way. These contexts are:
- Method-local bindings (e.g. variables and input parameters.)

When a method-local binding is given the name '`_`', it will not be added
to scope. This is useful for e.g. unused method parameters.
- Index variables for object arrays

When '`_`' is specified as an index variable, a parameter will not be
created for it, meaning it cannot conflict with any other definition, and
it cannot be referenced in the code in order to get the value of the index
in question. It also isn't considered to conflict with any other
definition that gives the index variable a different name. This is useful
when defining an object array specification which does not depend on the
index.
- Layout member names

When a layout member is given the name '`_`', that member will not be
referencable within DML code, but will still affect the memory
representation of the layout. This is useful to represent e.g. reserved
or padding bytes.

Note that as a consequence of these semantics, any reference to '`_`' in code
will _always_ resolve to the discard reference.
79 changes: 76 additions & 3 deletions doc/1.4/language.md
Original file line number Diff line number Diff line change
@@ -78,9 +78,19 @@ Identifiers

Identifiers in DML are defined as in C; an identifier may begin
with a letter or underscore, followed by any number of letters,
numbers, or underscores. Identifiers that begin with an underscore (`_`)
are reserved by the DML language and standard library and should not
be used.
numbers, or underscores.

<a id="discard-identifier"/>
Identifiers that begin with an underscore (`_`) are reserved by the DML language
and standard library and should not be used, with the exception of the single
underscore `_`; this is considered to be the *discard identifier*, and is only
permitted as the name of a declaration in specific contexts, where it gives the
declaration special semantics. Currently, these contexts are:
* Method-local bindings, e.g. [local variables](#local-statements) &mdash;
see that section for more information.
* Index parameters for object arrays. See the documentation for the
[`object` template](dml-builtins.html#object) for more information.
* As the name of one or more members of a [layout type](#layouts).

</dd><dt>

@@ -1471,6 +1481,7 @@ typedef struct { <em>member declarations</em> } <em>name</em>;

Layouts
</dt><dd>
<a id="layouts"/>

A layout is similar to a struct in many ways. The important
difference is that there is a well-defined mapping between a layout
@@ -1505,6 +1516,24 @@ integer members (and arrays of similar) are translated
to endian integers (or arrays of such) of similar size,
with endianness matching the layout. Layout and endian integer
members are accessed normally.

The *discard identifer* "\_" may be used as the name of any number of members
within a layout, making these *anonymous*. Anonymous layout members cannot be
referenced within DML code, but will still influence the underlying memory
representation of the layout in the same way as regular members.
This is useful to represent reserved or padding bytes, or bytes that the device
otherwise doesn't study or manipulate.

Note that when a compound initializer is given for a variable of layout type,
an initializer must still be given for each anonymous member:
```
local layout "little-endian" { uint32 x; uint32 _; uint32 y} = {1,0,2};
```
... unless designated initializers are used, in which case anonymous members
can (and must) be omitted:
```
local layout "little-endian" { uint32 x; uint32 _; uint32 y} = {.x = 1, .y = 2};
```
</dd><dt>

Bitfields
@@ -3175,6 +3204,24 @@ local (bool a, int i) = m();
In the absence of explicit initializer expressions, a default
"all zero" initializer will be applied to each declared object.

The *discard identifier* "\_" may be used as an identifier for local variables,
as well as other method-local bindings such as the method parameters, the bound
identifier in `foreach`/`#foreach`/`#select` statements, and message component
parameters of [hook-bound after statements](#hook-bound-after-statements).
Any method-local binding named "\_" *will not be added to scope.* This is useful
for when a method parameter is unused, or if you perform a method call where
only a subset of returned values are of interest:
```
local (bool a, int _) = m();
// No conflicts since "_" is not added to scope
local (bool a, int _, float _) = returns_three_vals();
```

An alternative to this pattern is to leverage the [discard
reference](#discard-reference) ``` local bool a; (a, _, _) =
returns_three_vals(); ``` ... which does not require you to specify the types of
the discarded values, may require multiple lines.

### Session Statements
<pre>
session <em>type</em> <em>identifier</em> [= <em>initializer</em>];
@@ -4063,6 +4110,32 @@ independent method callback(int i, void *aux) {
}
```

### The Discard Reference (`_`)
<a id="discard-reference"/>
```
_
```

The discard reference *`_`* is an expression without any run-time representation
that may be used as the target of an assignment in order to explicitly discard
the result of an evaluated expression or return value of a method call.

Example usage:
```
// Evaluate an expression and explicitly discard its result.
// Can be relevant to e.g. suppress Coverity's CHECKED_RETURN checker
_ = nonthrowing_single_return_method();

// Calls to methods that throw or have multiple return values require a target
// for each return value. `_` can be used to discard return values not of
// interest.
_ = throwing_method();
(_, x, _) = method_with_multiple_return_values();
```

The discard reference is related to the [discard
identifier](#discard-identifier), and have some use-cases in common.

### New Expressions

<pre>
15 changes: 14 additions & 1 deletion lib/1.4/dml-builtins.dml
Original file line number Diff line number Diff line change
@@ -508,12 +508,25 @@ which cannot be overridden:
single field inside a register array, the value is the empty list.

* Each array has an *individual index parameter*, to make it possible
to refer to both inner and outer indexes when arrays are nested
to refer to both inner and outer indices when arrays are nested
(cf. the `indices` parameter, above). The parameter name is
specified in the array declaration; for instance, the declaration
`register regs[i < 4][j < 11];` defines two index parameters, `i` and `j`.
In this case, the `indices` parameter is `[i, j]`.

"\_" is also allowed as the name of one or more index parameters. If
used, then it *won't* result in corresponding parameter definitions for those
indices; in other words, if an index variable is named "\_", then it can't be
accessed by that name (however, the `indices` parameter is unaffected and
could be used instead.) It's also allowed to have an object array
specification name an index parameter "\_" even if some other object array
specification uses a different name (which *will* be given a corresponding
parameter definition.) This is useful if a specific object array
specification doesn't need to make use of some particular indices; or if the
specification needs to support that the naming of the index variable may vary
depending on what other specifications of the same object array are present
in the device model.

The `object` template provides the non-overridable method `cancel_after()`,
which cancels all pending events posted using `after` which are associated with
the object (any events associated with subobjects are unaffected).
2 changes: 2 additions & 0 deletions py/dml/ast.py
Original file line number Diff line number Diff line change
@@ -48,13 +48,15 @@ def __setstate__(self, data):
'case_dml12',
'cast',
'cdecl',
'cdecl_maybe_discarded',
'compound',
'conditional',
'constant',
'continue',
'default',
'default_dml12',
'delete',
'discard',
'dml',
'dml_typedef',
'dowhile',
Loading