diff --git a/src/V3PreProc.cpp b/src/V3PreProc.cpp index 342797a72..0395a61f6 100644 --- a/src/V3PreProc.cpp +++ b/src/V3PreProc.cpp @@ -1425,7 +1425,8 @@ int V3PreProcImp::getStateToken() { else if (stateIsDefname()) { unputDefrefString("__IF_OFF_IGNORED_DEFINE"); } - m_lexp->m_parenLevel = 0; + // Stringification may still be inside another macro's argument list. + m_lexp->m_parenLevel = m_defRefs.empty() ? 0 : m_defRefs.top().parenLevel(); } else { // Finished a defref inside a upper defref, // and not under stringification or join. // Can't subst now, or diff --git a/test_regress/t/t_preproc_strify_join.out b/test_regress/t/t_preproc_strify_join.out index b80acd35b..99f4c2702 100644 --- a/test_regress/t/t_preproc_strify_join.out +++ b/test_regress/t/t_preproc_strify_join.out @@ -1,3 +1,9 @@ "foo-bar-qux" ""foo-bar-qux"" "" +begin if (!((a_size) <= 2)) ; else begin msg = {"id", " ", $sformatf("Check failed (%s) %s", "!((a_size) <= 2)", "")}; end end +begin if (!((a_size) <= 2)) ; else begin msg = {"id", " ", $sformatf("Check failed (%s) %s", "!((a_size) <= 2)", "")}; end end +begin if (!((a_size) <= 2)) ; else begin msg = {"tag", " ", $sformatf("Check failed (%s) %s", "!((a_size) <= 2)", "message, )")}; end end +begin if (!((a_size) <= 2)) ; else begin msg = {"tag", " ", $sformatf("Check failed (%s) %s", "!((a_size) <= 2)", "nested")}; end end +begin if (!((a_size) <= 2) && !((other_size) <= 2)) ; else begin msg = {"tag", " ", $sformatf("Check failed (%s) %s", "!((a_size) <= 2) && !((other_size) <= 2)", "two macros")}; end end +received(($sformatf("%s", "value")), "tail", 7) diff --git a/test_regress/t/t_preproc_strify_join.v b/test_regress/t/t_preproc_strify_join.v index de49f3d8e..c58582509 100644 --- a/test_regress/t/t_preproc_strify_join.v +++ b/test_regress/t/t_preproc_strify_join.v @@ -17,3 +17,22 @@ `STRIFY `NESTED_STRIFY `EMPTY_STRIFY + +// Preserve the outer argument nesting across parameterized macros in stringification. +// verilog_format: off +`define BELOW_MAX(s_) ((s_) <= 2) +`define IDENTITY(x_) x_ +`define rpt_fatal(MSG_, ID_) msg = {ID_, " ", MSG_}; +`define CHECK(T_, MSG_="", SEV_=error, ID_="id") begin if (T_) ; else begin `rpt_``SEV_($sformatf("Check failed (%s) %s", `"T_`", MSG_), ID_) end end +`define CHECK_FATAL(T_, MSG_="", ID_="id") `CHECK(T_, MSG_, fatal, ID_) + +`CHECK_FATAL(!((a_size) <= 2)) +`CHECK_FATAL(!`BELOW_MAX(a_size)) +`CHECK_FATAL(!`BELOW_MAX(a_size), "message, )", "tag") +`CHECK_FATAL(!`BELOW_MAX(`IDENTITY(a_size)), "nested", "tag") +`CHECK_FATAL(!`BELOW_MAX(a_size) && !`BELOW_MAX(other_size), "two macros", "tag") + +`define STRING_ARG(x_) `"`IDENTITY(x_)`" +`define TAKE_ARGS(a_, b_, c_) received(a_, b_, c_) +`TAKE_ARGS(($sformatf("%s", `STRING_ARG(value))), "tail", 7) +// verilog_format: on