From f2c2d73f36d7aaef90ded549143d1ee0c4d4a9f5 Mon Sep 17 00:00:00 2001
From: Zachary Snow <zach@zachjs.com>
Date: Mon, 14 Jun 2021 15:32:01 -0400
Subject: sv: fix up end label checking

- disallow [gen]blocks with an end label but not begin label
- check validity of module end label
- fix memory leak of package name and end label
- fix memory leak of module end label
---
 frontends/verilog/verilog_parser.y         | 25 ++++++++++++++++++-------
 tests/simple/matching_end_labels.sv        | 29 +++++++++++++++++++++++++++++
 tests/verilog/block_end_label_only.ys      |  9 +++++++++
 tests/verilog/block_end_label_wrong.ys     |  9 +++++++++
 tests/verilog/gen_block_end_label_only.ys  |  9 +++++++++
 tests/verilog/gen_block_end_label_wrong.ys |  9 +++++++++
 tests/verilog/module_end_label.ys          | 15 +++++++++++++++
 7 files changed, 98 insertions(+), 7 deletions(-)
 create mode 100644 tests/simple/matching_end_labels.sv
 create mode 100644 tests/verilog/block_end_label_only.ys
 create mode 100644 tests/verilog/block_end_label_wrong.ys
 create mode 100644 tests/verilog/gen_block_end_label_only.ys
 create mode 100644 tests/verilog/gen_block_end_label_wrong.ys
 create mode 100644 tests/verilog/module_end_label.ys

diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y
index 1a76d0dea..120a8bca3 100644
--- a/frontends/verilog/verilog_parser.y
+++ b/frontends/verilog/verilog_parser.y
@@ -235,6 +235,16 @@ static void rewriteAsMemoryNode(AstNode *node, AstNode *rangeNode)
 	node->children.push_back(rangeNode);
 }
 
+static void checkLabelsMatch(const char *element, const std::string *before, const std::string *after)
+{
+	if (!before && after)
+		frontend_verilog_yyerror("%s missing where end label (%s) was given.",
+			element, after->c_str() + 1);
+	if (before && after && *before != *after)
+		frontend_verilog_yyerror("%s (%s) and end label (%s) don't match.",
+			element, before->c_str() + 1, after->c_str() + 1);
+}
+
 %}
 
 %define api.prefix {frontend_verilog_yy}
@@ -457,7 +467,6 @@ module:
 		port_counter = 0;
 		mod->str = *$4;
 		append_attr(mod, $1);
-		delete $4;
 	} module_para_opt module_args_opt ';' module_body TOK_ENDMODULE opt_label {
 		if (port_stubs.size() != 0)
 			frontend_verilog_yyerror("Missing details for module port `%s'.",
@@ -465,7 +474,10 @@ module:
 		SET_AST_NODE_LOC(ast_stack.back(), @2, @$);
 		ast_stack.pop_back();
 		log_assert(ast_stack.size() == 1);
+		checkLabelsMatch("Module name", $4, $11);
 		current_ast_mod = NULL;
+		delete $4;
+		delete $11;
 		exitTypeScope();
 	};
 
@@ -583,9 +595,10 @@ package:
 		append_attr(mod, $1);
 	} ';' package_body TOK_ENDPACKAGE opt_label {
 		ast_stack.pop_back();
-		if ($4 != NULL && $9 != NULL && *$4 != *$9)
-			frontend_verilog_yyerror("Package name (%s) and end label (%s) don't match.", $4->c_str()+1, $9->c_str()+1);
+		checkLabelsMatch("Package name", $4, $9);
 		current_ast_mod = NULL;
+		delete $4;
+		delete $9;
 		exitTypeScope();
 	};
 
@@ -2526,8 +2539,7 @@ behavioral_stmt:
 			node->str = *$4;
 	} behavioral_stmt_list TOK_END opt_label {
 		exitTypeScope();
-		if ($4 != NULL && $8 != NULL && *$4 != *$8)
-			frontend_verilog_yyerror("Begin label (%s) and end label (%s) don't match.", $4->c_str()+1, $8->c_str()+1);
+		checkLabelsMatch("Begin label", $4, $8);
 		AstNode *node = ast_stack.back();
 		// In SystemVerilog, unnamed blocks with block item declarations
 		// create an implicit hierarchy scope
@@ -2863,8 +2875,7 @@ gen_block:
 		ast_stack.push_back(node);
 	} module_gen_body TOK_END opt_label {
 		exitTypeScope();
-		if ($3 != NULL && $7 != NULL && *$3 != *$7)
-			frontend_verilog_yyerror("Begin label (%s) and end label (%s) don't match.", $3->c_str()+1, $7->c_str()+1);
+		checkLabelsMatch("Begin label", $3, $7);
 		delete $3;
 		delete $7;
 		SET_AST_NODE_LOC(ast_stack.back(), @1, @7);
diff --git a/tests/simple/matching_end_labels.sv b/tests/simple/matching_end_labels.sv
new file mode 100644
index 000000000..09182ebcf
--- /dev/null
+++ b/tests/simple/matching_end_labels.sv
@@ -0,0 +1,29 @@
+module top(
+    output reg [7:0]
+    out1, out2, out3, out4
+);
+    initial begin
+        begin : blk1
+            reg x;
+            x = 1;
+        end
+        out1 = blk1.x;
+        begin : blk2
+            reg x;
+            x = 2;
+        end : blk2
+        out2 = blk2.x;
+    end
+    if (1) begin
+        if (1) begin : blk3
+            reg x;
+            assign x = 3;
+        end
+        assign out3 = blk3.x;
+        if (1) begin : blk4
+            reg x;
+            assign x = 4;
+        end : blk4
+        assign out4 = blk4.x;
+    end
+endmodule
diff --git a/tests/verilog/block_end_label_only.ys b/tests/verilog/block_end_label_only.ys
new file mode 100644
index 000000000..5db1c7879
--- /dev/null
+++ b/tests/verilog/block_end_label_only.ys
@@ -0,0 +1,9 @@
+logger -expect error "Begin label missing where end label \(incorrect_name\) was given\." 1
+read_verilog -sv <<EOF
+module top;
+initial
+    begin
+        $display("HI");
+    end : incorrect_name
+endmodule
+EOF
diff --git a/tests/verilog/block_end_label_wrong.ys b/tests/verilog/block_end_label_wrong.ys
new file mode 100644
index 000000000..47dbbe32f
--- /dev/null
+++ b/tests/verilog/block_end_label_wrong.ys
@@ -0,0 +1,9 @@
+logger -expect error "Begin label \(correct_name\) and end label \(incorrect_name\) don't match\." 1
+read_verilog -sv <<EOF
+module top;
+initial
+    begin : correct_name
+        $display("HI");
+    end : incorrect_name
+endmodule
+EOF
diff --git a/tests/verilog/gen_block_end_label_only.ys b/tests/verilog/gen_block_end_label_only.ys
new file mode 100644
index 000000000..60dc0476a
--- /dev/null
+++ b/tests/verilog/gen_block_end_label_only.ys
@@ -0,0 +1,9 @@
+logger -expect error "Begin label missing where end label \(incorrect_name\) was given\." 1
+read_verilog -sv <<EOF
+module top;
+if (1)
+    begin
+        initial $display("HI");
+    end : incorrect_name
+endmodule
+EOF
diff --git a/tests/verilog/gen_block_end_label_wrong.ys b/tests/verilog/gen_block_end_label_wrong.ys
new file mode 100644
index 000000000..43cfc8773
--- /dev/null
+++ b/tests/verilog/gen_block_end_label_wrong.ys
@@ -0,0 +1,9 @@
+logger -expect error "Begin label \(correct_name\) and end label \(incorrect_name\) don't match\." 1
+read_verilog -sv <<EOF
+module top;
+if (1)
+    begin : correct_name
+        initial $display("HI");
+    end : incorrect_name
+endmodule
+EOF
diff --git a/tests/verilog/module_end_label.ys b/tests/verilog/module_end_label.ys
new file mode 100644
index 000000000..c9e5a13a2
--- /dev/null
+++ b/tests/verilog/module_end_label.ys
@@ -0,0 +1,15 @@
+logger -expect-no-warnings
+read_verilog -sv <<EOF
+module correct_name;
+localparam X = 1;
+endmodule : correct_name
+EOF
+
+design -reset
+
+logger -expect error "Module name \(correct_name\) and end label \(incorrect_name\) don't match\." 1
+read_verilog -sv <<EOF
+module correct_name;
+localparam X = 1;
+endmodule : incorrect_name
+EOF
-- 
cgit v1.2.3