From ef5ca74e943b55cbf9f112b2f96a4f02e923f2c0 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 21 Dec 2025 16:15:33 -0500 Subject: [PATCH] Tests: Better handle multiline statements in t_dist_warn_coverage --- src/V3Fork.cpp | 4 +- src/V3SenExprBuilder.h | 9 +- test_regress/t/t_dist_warn_coverage.py | 166 ++++++++++++++++--------- 3 files changed, 116 insertions(+), 63 deletions(-) diff --git a/src/V3Fork.cpp b/src/V3Fork.cpp index 53e8cac0c..3c494b963 100644 --- a/src/V3Fork.cpp +++ b/src/V3Fork.cpp @@ -673,8 +673,8 @@ class ForkVisitor final : public VNVisitor { if (nodep->access().isWriteOrRW() && (!nodep->isClassHandleValue() || nodep->user2())) { nodep->v3warn( E_LIFETIME, - "Invalid reference: Process might outlive variable `" - << varp->name() << "`.\n" + "Invalid reference: Process might outlive variable " + << varp->prettyNameQ() << ".\n" << varp->warnMore() << "... Suggest use it as read-only to initialize a local copy at the " "beginning of the process, or declare it as static. It is also " diff --git a/src/V3SenExprBuilder.h b/src/V3SenExprBuilder.h index ddedc20ed..ddbfbbba9 100644 --- a/src/V3SenExprBuilder.h +++ b/src/V3SenExprBuilder.h @@ -126,9 +126,12 @@ private: // Add post update if it does not exist yet if (m_hasPostUpdate.emplace(*exprp).second) { if (!isSupportedDType(exprp->dtypep())) { - exprp->v3warn(E_UNSUPPORTED, - "Unsupported: Cannot detect changes on expression of complex type" - " (see combinational cycles reported by UNOPTFLAT)"); + exprp->v3warn( + E_UNSUPPORTED, + "Unsupported: Cannot detect changes on expression of complex type " + << exprp->dtypep()->prettyDTypeNameQ() << "\n" + << exprp->warnMore() + << "... May be caused by combinational cycles reported with UNOPTFLAT"); return prevp; } diff --git a/test_regress/t/t_dist_warn_coverage.py b/test_regress/t/t_dist_warn_coverage.py index 8d35ab603..0e601d4f0 100755 --- a/test_regress/t/t_dist_warn_coverage.py +++ b/test_regress/t/t_dist_warn_coverage.py @@ -18,82 +18,115 @@ Suppressed = {} for s in [ # Cannot hit, and comment as to why # Instead of adding here, consider adding a LCOV_EXCL_LINE/START/STOP to the sources on the message - ' exited with ', # Is hit; driver.py filters out - ' loading non-variable', # Instead 'storing to parameter' or syntax error + 'exited with', # Is hit; driver.py filters out + 'loading non-variable', # Instead 'storing to parameter' or syntax error + 'does not allow ' + ' in the middle of literal', # Is covered, this parser misses it due to quote 'Assigned pin is neither input nor output', # Instead earlier error 'Define missing argument \'', # Instead get Define passed too many arguments 'Define or directive not defined: `', # Instead V3ParseImp will warn - 'Expecting define formal arguments. Found: ', # Instead define syntax error - 'Syntax error: Range \':\', \'+:\' etc are not allowed in the instance ', # Instead get syntax error + 'Expecting define formal arguments. Found:', # Instead define syntax error + 'Syntax error: Range \':\', \'+:\' etc are not allowed in the instance', # Instead get syntax error 'dynamic new() not expected in this context (expected under an assign)', # Instead get syntax error # Not yet analyzed - '--pipe-filter protocol error, unexpected: ', + '$VERILATOR_ROOT needs to be in environment', + '--pipe-filter protocol error, unexpected:', '--pipe-filter returned bad status', - 'Array initialization has too few elements, need element ', + '--pipe-filter: stdin/stdout closed before pipe opened', + '--pipe-filter: write to closed file', + 'Array initialization has too few elements, need element', + 'Assigning >32 bit to unranged parameter (defaults to 32 bits)', 'Assignment pattern with no members', - 'Can\'t find varpin scope of ', - 'Can\'t read annotation file: ', + 'Can\'t find varpin scope of', + 'Can\'t read annotation file:', 'Can\'t resolve module reference: \'', - 'Can\'t write file: ', - 'Expected data type, not a ', + 'Can\'t write file:', + 'Circular logic when ordering code (non-cutable edge loop)', + 'Expected data type, not a', 'Extern declaration\'s scope is not a defined class', - 'File not found: ', + 'File not found:', 'Format to $display-like function must have constant format string', - 'Forward typedef used as class/package does not resolve to class/package: ', - 'Illegal +: or -: select; type already selected, or bad dimension: ', - 'Illegal bit or array select; type already selected, or bad dimension: ', - 'Illegal range select; type already selected, or bad dimension: ', - 'Interface port declaration ', - 'Modport item is not a function/task: ', - 'Modport item is not a variable: ', + 'Forward typedef used as class/package does not resolve to class/package:', + 'Illegal +: or -: select; type already selected, or bad dimension:', + 'Illegal bit or array select; type already selected, or bad dimension:', + 'Illegal range select; type already selected, or bad dimension:', + 'Instance pin connected by name with empty reference:', + 'Interface port declaration', + 'Invalid reference: Process might outlive variable', + 'Modport item is not a function/task:', + 'Modport item is not a variable:', 'Modport not referenced as .', - 'Modport not referenced from underneath an interface: ', - 'Non-interface used as an interface: ', - 'Parameter type pin value isn\'t a type: Param ', - 'Parameter type variable isn\'t a type: Param ', + 'Modport not referenced from underneath an interface:', + 'Need $SYSTEMC_INCLUDE in environment or when Verilator configured,', + 'Non-interface used as an interface:', + 'Parameter type pin value isn\'t a type: Param', + 'Parameter type variable isn\'t a type: Param', 'Pattern replication value of 0 is not legal.', 'Signals inside functions/tasks cannot be marked forceable', 'Slice size cannot be zero.', - 'Slices of arrays in assignments have different unpacked dimensions, ', - 'String of ', - 'Symbol matching ', + 'Slices of arrays in assignments have different unpacked dimensions,', + 'String of', + 'Symbol matching', 'Unexpected connection to arrayed port', 'Unsized numbers/parameters not allowed in streams.', - 'Unsupported RHS tristate construct: ', + 'Unsupported (or syntax error): Foreach on this array\'s construct', + 'Unsupported LHS node type in array assignment', + 'Unsupported RHS tristate construct:', 'Unsupported or syntax error: Unsized range in instance or other declaration', 'Unsupported pullup/down (weak driver) construct.', - 'Unsupported tristate port expression: ', + 'Unsupported tristate construct (not in propagation graph):', + 'Unsupported tristate port expression:', + 'Unsupported/unknown built-in queue method', 'Unsupported: $bits for queue', 'Unsupported: &&& expression', 'Unsupported: 4-state numbers in this context', + 'Unsupported: Assignments with signal strength with LHS of type:', 'Unsupported: Bind with instance list', - 'Unsupported: Concatenation to form ', + 'Unsupported: Cannot detect changes on expression of complex type', + 'Unsupported: Cast to', + 'Unsupported: Concatenation to form', + 'Unsupported: Creating tristate signal not underneath a module:', + 'Unsupported: Default value on module inout/ref/constref:', 'Unsupported: Modport empty expression', 'Unsupported: Modport export with prototype', 'Unsupported: Modport import with prototype', + 'Unsupported: Non-constant default value in missing argument', + 'Unsupported: Non-constant index when passing interface to module', 'Unsupported: Only one PSL clock allowed per assertion', - 'Unsupported: Per-bit array instantiations ', - 'Unsupported: Public functions with >64 bit outputs; ', - 'Unsupported: Replication to form ', + 'Unsupported: Per-bit array instantiations', + 'Unsupported: Public functions with >64 bit outputs;', + 'Unsupported: Public functions with return > 64 bits wide.', + 'Unsupported: Release statement argument is too complex array select', + 'Unsupported: Replication to form', + 'Unsupported: Shifting of by over 32-bit number isn\'t supported.', 'Unsupported: Size-changing cast on non-basic data type', 'Unsupported: Slice of non-constant bounds', + 'Unsupported: Stream operation on a variable of a type', 'Unsupported: Unclocked assertion', + 'Unsupported: Using --protect-ids with public function', 'Unsupported: Verilog 1995 deassign', - 'Unsupported: Verilog 1995 gate primitive: ', + 'Unsupported: Verilog 1995 gate primitive:', 'Unsupported: [] dimensions', 'Unsupported: \'default :/\' constraint', 'Unsupported: \'{} .* patterns', 'Unsupported: assertion items in clocking blocks', - 'Unsupported: don\'t know how to deal with ', + 'Unsupported: don\'t know how to deal with', + 'Unsupported: extern constraint definition with class-in-class', 'Unsupported: extern forkjoin', 'Unsupported: extern task', 'Unsupported: modport export', 'Unsupported: no_inline for tasks', + 'Unsupported: non-const assert directive type expression', 'Unsupported: property port \'local\'', + 'Unsupported: randsequence production function variable', 'Unsupported: repeat event control', - 'Unsupported: static cast to ', + 'Unsupported: static cast to', 'Unsupported: super', 'Unsupported: with[] stream expression', + 'expected non-complex non-double', + 'is not an unpacked array, but is in an unpacked array context', + 'loading other than unpacked-array variable', + 'loading other than unpacked/associative-array variable', ]: Suppressed[s] = True @@ -106,7 +139,8 @@ def read_messages(): continue with open(filename, 'r', encoding="utf8") as fh: lineno = 0 - read_next = None + statement = "" + statement_lineno = 0 excl = False excl_next = False @@ -118,36 +152,52 @@ def read_messages(): if re.match(r'^\s*/\*', line): continue excl = excl_next + # print(('C ' if (statement != "") else 'L') + line) + if 'LCOV_EXCL_START' in line: excl = True excl_next = True if 'LCOV_EXCL_STOP' in line: excl_next = False # Reenables coverage on next line, not this one - if re.search(r'\b(v3error|v3warn|v3fatal|BBUNSUP)\b\($', line): - if 'LCOV_EXCL_LINE' not in line: - read_next = True + if 'LCOV_EXCL_LINE' in line: + excl = True + if excl: + statement = "" continue - m = re.search(r'.*\b(v3error|v3warn|v3fatal|BBUNSUP)\b(.*)', line) + + line = re.sub(r'\\n', '', line) + line = re.sub(r'\s+//.*', '', line) + line = line.rstrip() + + m = re.search(r'\b((v3error|v3warn|v3fatal|BBUNSUP)\b.*)', line) if m: - line = m.group(2) - if 'LCOV_EXCL_LINE' not in line: - read_next = True - if read_next: - read_next = False - if 'LCOV_EXCL_LINE' in line: - continue - if excl: - continue - if "\\" in line: # \" messes up next part - continue - m = re.search(r'"([^"]*)"', line) - if m: - msg = m.group(1) - fileline = filename + ":" + str(lineno) - # print("FFFF " + fileline + ": " + msg + " LL " + line) - Messages[msg] = {} - Messages[msg]['fileline'] = fileline - Messages[msg]['line'] = origline + statement = m.group(1) + statement_lineno = lineno + + if statement == "": + continue + statement += line + + if ');' not in statement: + continue # Keep reading lines until get end of statement + + if '\\"' in statement: + continue # Parser messes these up + + # print("SSS " + statement) + + m = re.search(r'"([^"]*)"', statement) + if m: + msg = m.group(1) + msg = re.sub(r'\s+$', '', msg) + msg = re.sub(r'^\s+', '', msg) + fileline = filename + ":" + str(statement_lineno) + # print("FFFF " + fileline + ": " + msg + " LL " + statement) + Messages[msg] = {} + Messages[msg]['fileline'] = fileline + Messages[msg]['line'] = statement + + statement = "" print("Number of messages = " + str(len(Messages)))