Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -284,3 +284,9 @@
```
- `release 7 7152`
- `release 6 6461`
- `note 6` Warning and error messages reported by DMLC now display the tag for
the warning/error kind by default. The old behavior of having the tag
be omitted now requires passing `--no-tags` to DMLC. With this change, the
`-T` flag has become a no-op and will be removed in a future version.
- `note 6` Added the `WARNING` pragma, which allows for the granular
suppression of DMLC warnings for a target line.
48 changes: 46 additions & 2 deletions doc/1.4/language.md
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,8 @@ or, if _`classification`_ is omitted:
</pre>

A DML line will be affected by every `COVERITY` pragma specified in preceding
lines, up until the first line not containing any `COVERITY` pragma. For
lines, up until the first line not containing any `COVERITY` pragma or other
line-based pragma (like `WARNING`). For
example:
```
/*% COVERITY unreachable %*/
Expand All @@ -259,7 +260,50 @@ Any C line corresponding to the call to `some_function(...)` will receive
analysis annotations for `var_deref_model`, `check_return`, and
`copy_paste_error` (with `copy_paste_error` specifically being classified as a
false positive), but not any analysis annotation for `unreachable`, as the empty
line breaks the consecutive specifications of COVERITY pragmas.
line breaks the consecutive specifications of pragmas.

### WARNING pragma
The `WARNING` pragma prevents DMLC from reporting DML warnings of a specified
kind for a particular DML line.

Note that most warnings are designed to have an idiomatic way to silence them
without needing to employ the `WARNING` pragma; check the documentation for any
particular warning in Appendix [Messages](messages.html#warning-messages)
before employing the pragma.

The syntax for the `WARNING` pragma is as follows:
<pre>
/*% WARNING <em>tag</em> %*/
</pre>
where _`tag`_ is the tag of the warning kind to suppress; see Appendix
[Messages](messages.html#warning-messages).

A DML line will be affected by every `WARNING` pragma specified in preceding
lines, up until the first line not containing any `WARNING` pragma or other
line-based pragma (like `COVERITY`). For example:
```
param special default -1;
param then_level default 1;

method check(uint32 i) {
/*% WARNING WREDUNDANTLEVEL %*/
/*% WARNING WNEGCONSTCOMP %*/
log info, 1 then then_level: "%s", i == special ? "special" : "regular";
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have no idea how difficult it was to concoct a semi-realistic case where applying a WARNING pragma twice on the same line would be warranted. We don't have enough warning kinds ;)

```
In this case, the two `WARNING` pragmas apply *exclusively* to the `log info`
line. If any line (even an empty line) without a pragma were to be inserted
between the two `WARNING` pragmas, then it would break up the consecutive
specifications of pragmas and only `/*% WARNING WNEGCONSTCOMP %*/` would apply
to the `log info` line.

This example also demonstrates the most compelling kind of use-case for the
pragma. By itself, this snippet would cause DMLC to warn about the `then` being
redundant (`WREDUNDANTLEVEL`) and the `i == special` check being impossible to
satisfy (`WNEGCONSTCOMP`), and yet those pieces of the code can still be
meaningful if used in a context where the definitions of `special` and
`then_level` get overridden. So in this case, the warnings fail to identify
true problems in the code, making it desirable to suppress them.

## The Object Model

Expand Down
17 changes: 10 additions & 7 deletions doc/1.4/running-dmlc.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,14 @@ constant. The parameter will appear in the top-level scope.
Output makefile rules describing dependencies.
</dd><dt>

-T
--no-tags
</dt><dd>

Show tags on warning messages. The tags can be used with
the `--nowarn` and `--warn` options.
Don't display the tag associated with each warning or error message.
The tag identifies the particular kind of warning/error of the message,
which can be used to look up its documentation in Appendix
[Messages](messages.html). The `--nowarn` and `--warn` options as well as the
[`WARNING` pragma](language.html#warning-pragma) also operate on warning tags.
</dd><dt>

-g
Expand Down Expand Up @@ -127,15 +130,15 @@ only used when needed.
-\-warn=*tag*
</dt><dd>

Enable selected warnings. The tags can be found using
the `-T` option.
Enable selected warnings. The tag of a warning will be displayed before the
message body, unless `--no-tags` has been passed to DMLC.
</dd><dt>

-\-nowarn=*tag*
</dt><dd>

Suppress selected warnings. The tags can be found using
the `-T` option.
Suppress selected warnings. The tag of a warning will be displayed before the
message body, unless `--no-tags` has been passed to DMLC.
</dd><dt>

-\-werror
Expand Down
20 changes: 11 additions & 9 deletions py/dml/dmlc.py
Original file line number Diff line number Diff line change
Expand Up @@ -364,12 +364,16 @@ def main(argv):
+ ' dependency generation. Specify multiple times to have multiple'
+ ' targets.')

# <dt>-T</dt>
# <dd>Show tags on warning messages. The tags can be used with
# the <tt>-\-nowarn</tt> and <tt>-\-warn</tt> options.</dd>
# <dt>-\-no-tags</dt>
# <dd>Disables showing the tag associated with each error or warning
# message.</dd>

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we even bother?

parser.add_argument(
'-T', dest='include_tag', action='store_true',
help='show tags on warning messages')
'--no-tags', dest='include_tag', action='store_false',
help='disable tags on error and warning messages')
Comment thread
lwaern-intel marked this conversation as resolved.

# Purely for backwards compatibility
parser.add_argument('-T', action='store_true', dest=argparse.SUPPRESS,
help=argparse.SUPPRESS)

# Deprecated with SIMICS_API > 4.8
parser.add_argument(
Expand All @@ -385,17 +389,15 @@ def main(argv):
help='generate artifacts and C code that allow for easier debugging')

# <dt>-\-warn=<i>tag</i></dt>
# <dd>Enable selected warnings. The tags can be found using
# the <tt>-T</tt> option.</dd>
# <dd>Enable selected warnings.</dd>
parser.add_argument(
'--warn', dest='enabled_warnings', action='append',
metavar='TAG',
default=[],
help='enable warning TAG')

# <dt>-\-nowarn=<i>tag</i></dt>
# <dd>Suppress selected warnings. The tags can be found using
# the <tt>-T</tt> option.</dd>
# <dd>Suppress selected warnings.</dd>
parser.add_argument(
'--nowarn', dest='disabled_warnings', action='append',
metavar='TAG',
Expand Down
21 changes: 13 additions & 8 deletions py/dml/dmlparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -1547,14 +1547,19 @@ def cdecl2_ptr(t):
def cdecl2_vect(t):
'cdecl2 : VECT cdecl2'
if provisional.simics_util_vect not in t.parser.file_info.provisional:
if not breaking_changes.vect_needs_provisional.enabled:
vsite = site(t)
if vsite.dml_version() != (1, 2):
# defensively suppress warning in 1.2, for
# compatibility
report(WEXPERIMENTAL(site(t), 'vect types'))
else:
report(EOLDVECT(site(t)))
# defensively suppress warning in 1.2, for
# compatibility
vsite = site(t)
if vsite.dml_version() != (1, 2):
if not breaking_changes.vect_needs_provisional.enabled:
report(WEXPERIMENTAL(vsite,
"vect types\nTo suppress this "
+ "warning, specify "
+ "'provisional simics_util_vect;' at "
+ "the top of the file, after "
+ "'dml 1.4;'"))
else:
report(EOLDVECT(vsite))
t[0] = ['vect'] + t[2]

@prod_dml12
Expand Down
4 changes: 3 additions & 1 deletion py/dml/globals.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,9 @@ def compat_dml12_int(site):

coverity = False

coverity_pragmas = {}
# the specified pragmas in the model that operate on a subsequent line.
# For the moment, all pragmas are of that sort
line_pragmas = {}

# all warnings are disabled by the --dep flag
ignore_all_warnings = False
Expand Down
40 changes: 39 additions & 1 deletion py/dml/logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
'warning_is_ignored',
'enable_warning',
'set_include_tag',
'site_line_pragmas',
'ErrorContext',

'dollar',
Expand Down Expand Up @@ -66,6 +67,14 @@ def enable_warning(tag):
def warning_is_ignored(tag):
return dml.globals.ignore_all_warnings or ignored_warnings.get(tag, False)

def warning_occurrence_is_ignored(warning):
tag = warning.tag()
if warning_is_ignored(tag):
return True

return any((p == "WARNING" and t == tag
for (p, t) in site_line_pragmas(warning.site)))

class ErrorContext(object):
__slots__ = ('node', 'site')

Expand Down Expand Up @@ -219,7 +228,7 @@ class DMLWarning(LogMessage):

def preprocess(self):
# Don't print anything if the user asked us not to
if warning_is_ignored(self.tag()):
if warning_occurrence_is_ignored(self):
return False
if DMLWarning.next_warning_yields_error:
self.print_site_message(self.site,
Expand Down Expand Up @@ -266,6 +275,35 @@ def log(self):
os.path.normcase(arg.loc()) if isinstance(arg, Site) else arg
for arg in self.args]))

def site_line_pragmas(s):
if s is None or isinstance(s, SimpleSite):
return []

pragmas = []
filename = s.filename()
tgt_lineno = s.lineno

while (filename, tgt_lineno) in dml.globals.line_pragmas:
(start_lineno, inline_pragmas) = dml.globals.line_pragmas[(filename,
tgt_lineno)]
pragmas.extend(reversed(inline_pragmas))

# A minor HACK to handle the case of:
# /*% PRAGMA foo %*/ /*% PRAGMA
# bar %*/
# some_statement
#
# Otherwise 'foo' won't be captured
if (start_lineno + 1 < tgt_lineno
and ((filename, start_lineno + 1)
in dml.globals.line_pragmas)):
tgt_lineno = start_lineno + 1
else:
tgt_lineno = start_lineno

pragmas.reverse()
return pragmas

class Site(metaclass=abc.ABCMeta):
__slots__ = ()
@abc.abstractmethod
Expand Down
7 changes: 7 additions & 0 deletions py/dml/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -1991,6 +1991,13 @@ class EDISCARDREF(DMLError):
fmt = ("'_' can only be used as an assignment target "
+ "(to discard some value)")

class EWARNING(DMLError):
"""
An invalid warning tag was specified in a WARNING pragma.
"""
version = "1.4"
fmt = "Not a valid warning tag: '%s'"

#
# WARNINGS (keep these as few as possible)
#
Expand Down
28 changes: 3 additions & 25 deletions py/dml/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from pathlib import Path

import dml.globals
from .logging import ICE, SimpleSite
from .logging import ICE, SimpleSite, site_line_pragmas

__all__ = (
'NoOutput',
Expand Down Expand Up @@ -185,30 +185,8 @@ def coverity_marker(event, classification=None, site=None):
def coverity_markers(markers, site=None):
site_with_loc = site is not None and not isinstance(site, SimpleSite)
if dml.globals.coverity and site_with_loc:
custom_markers = []
filename = site.filename()
tgt_lineno = site.lineno

while (filename, tgt_lineno) in dml.globals.coverity_pragmas:
(start_lineno,
inline_markers) = dml.globals.coverity_pragmas[(filename,
tgt_lineno)]
custom_markers.extend(reversed(inline_markers))

# A minor HACK to handle the case of:
# /*% COVERITY foo %*/ /*% COVERITY
# bar %*/
# some_statement
#
# Otherwise 'foo' won't be captured
if (start_lineno + 1 < tgt_lineno
and ((filename, start_lineno + 1)
in dml.globals.coverity_pragmas)):
tgt_lineno = start_lineno + 1
else:
tgt_lineno = start_lineno

custom_markers.reverse()
custom_markers = [d for (p, d) in site_line_pragmas(site)
if p == "COVERITY"]
markers = custom_markers + markers

if dml.globals.coverity and markers:
Expand Down
39 changes: 24 additions & 15 deletions py/dml/toplevel.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,10 @@ def scan_statements(filename, site, stmts):
# For the moment, we ban usages of * inside pragmas to not make multiple usages
# of pragmas ruin everything. In the future if we introduce pragmas that may
# want to contain * we need to be smarter about this.
pragma_re = re.compile(r'/\*%\s*([^\s*]+)\s*(?:\s([^*\s][^*]*))?%\*/')
pragma_re = re.compile(r'/\*%\s*([^\s*]+)\s*(?:\s([^*\s][^*]*?))?\s*%\*/')

pragma_coverity_data_re = re.compile(r'^(\S+)\s*(?:\s(\S[\s\S]*))?$')
warning_coverity_data_re = re.compile(r'^(\S+)$')

def check_bidi(filename, filestr):
for m in bidi_re.finditer(filestr):
Expand Down Expand Up @@ -226,25 +228,32 @@ def parse_pragma(filename, start_lineno, end_lineno, pragma, data):
None,
"COVERITY pragma must specify event to suppress, "
+ "and optionally classification"))
else:
return ('COVERITY',
(filename, start_lineno, end_lineno + 1, data.groups()))
return None
data = data.groups()
elif pragma == 'WARNING':
data = data and warning_coverity_data_re.match(data)
if data is None:
report(ESYNTAX(SimpleSite(f"{filename}:{start_lineno}"),
None,
"WARNING pragma must specify warning to suppress"))
return None
data = data.group(1)
else:
report(EPRAGMA(SimpleSite(f"{filename}:{start_lineno}"), pragma))
return None

def process_pragma(t):
(pragma, data) = t
if pragma == 'COVERITY':
(filename, start_lineno, end_lineno, data) = data
# The first COVERITY pragma we encounter for a given end_lineno is
# the only one whose starting line may differ.
(dml.globals.coverity_pragmas
.setdefault((filename, end_lineno), (start_lineno, []))
[1].append(data))
else:
raise ICE(f'unknown pragma: {pragma}')
return (pragma, filename, start_lineno, end_lineno + 1, data)

def process_pragma(t):
(pragma, filename, start_lineno, tgt_lineno, data) = t
if pragma == 'WARNING':
if not is_warning_tag(data):
report(EWARNING(SimpleSite(f'{filename}:{start_lineno}:1'), data))
return None

(dml.globals.line_pragmas
.setdefault((filename, tgt_lineno), (start_lineno, []))
[1].append((pragma, data)))

def parse_file(dml_filename):
try:
Expand Down
11 changes: 11 additions & 0 deletions test/1.4/errors/T_EWARNING.dml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
© 2026 Intel Corporation
SPDX-License-Identifier: MPL-2.0
*/
dml 1.4;

/// ERROR EWARNING
/*% WARNING EAFTER %*/
/// ERROR EWARNING
/*% WARNING WHATEVER %*/
device test;
Loading