[clang] [clang-format] Recognize Verilog export and import (PR #165595)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Oct 29 09:50:17 PDT 2025
https://github.com/sstwcw created https://github.com/llvm/llvm-project/pull/165595
The directives should not change the indentation level. Previously the program erroneously added an indentation level when it saw the `function` keyword.
>From 455a5ab590e058e50dc8b1c3eff126e34706a44c Mon Sep 17 00:00:00 2001
From: sstwcw <su3e8a96kzlver at posteo.net>
Date: Wed, 29 Oct 2025 16:44:15 +0000
Subject: [PATCH] [clang-format] Recognize Verilog export and import
The directives should not change the indentation level. Previously the
program erroneously added an indentation level when it saw the
`function` keyword.
---
clang/lib/Format/FormatToken.h | 182 ++++++++++++++-----
clang/lib/Format/UnwrappedLineParser.cpp | 36 +++-
clang/lib/Format/UnwrappedLineParser.h | 2 +
clang/unittests/Format/FormatTestVerilog.cpp | 10 +
4 files changed, 179 insertions(+), 51 deletions(-)
diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h
index 6f3d24aefc1ca..e7d03cd181fce 100644
--- a/clang/lib/Format/FormatToken.h
+++ b/clang/lib/Format/FormatToken.h
@@ -1164,6 +1164,7 @@ struct AdditionalKeywords {
kw_checker = &IdentTable.get("checker");
kw_clocking = &IdentTable.get("clocking");
kw_constraint = &IdentTable.get("constraint");
+ kw_context = &IdentTable.get("context");
kw_cover = &IdentTable.get("cover");
kw_covergroup = &IdentTable.get("covergroup");
kw_coverpoint = &IdentTable.get("coverpoint");
@@ -1319,50 +1320,138 @@ struct AdditionalKeywords {
// Some keywords are not included here because they don't need special
// treatment like `showcancelled` or they should be treated as identifiers
// like `int` and `logic`.
- VerilogExtraKeywords = std::unordered_set<IdentifierInfo *>(
- {kw_always, kw_always_comb, kw_always_ff,
- kw_always_latch, kw_assert, kw_assign,
- kw_assume, kw_automatic, kw_before,
- kw_begin, kw_bins, kw_binsof,
- kw_casex, kw_casez, kw_celldefine,
- kw_checker, kw_clocking, kw_constraint,
- kw_cover, kw_covergroup, kw_coverpoint,
- kw_disable, kw_dist, kw_edge,
- kw_end, kw_endcase, kw_endchecker,
- kw_endclass, kw_endclocking, kw_endfunction,
- kw_endgenerate, kw_endgroup, kw_endinterface,
- kw_endmodule, kw_endpackage, kw_endprimitive,
- kw_endprogram, kw_endproperty, kw_endsequence,
- kw_endspecify, kw_endtable, kw_endtask,
- kw_extends, kw_final, kw_foreach,
- kw_forever, kw_fork, kw_function,
- kw_generate, kw_highz0, kw_highz1,
- kw_iff, kw_ifnone, kw_ignore_bins,
- kw_illegal_bins, kw_implements, kw_import,
- kw_initial, kw_inout, kw_input,
- kw_inside, kw_interconnect, kw_interface,
- kw_intersect, kw_join, kw_join_any,
- kw_join_none, kw_large, kw_let,
- kw_local, kw_localparam, kw_macromodule,
- kw_matches, kw_medium, kw_negedge,
- kw_output, kw_package, kw_packed,
- kw_parameter, kw_posedge, kw_primitive,
- kw_priority, kw_program, kw_property,
- kw_pull0, kw_pull1, kw_pure,
- kw_rand, kw_randc, kw_randcase,
- kw_randsequence, kw_ref, kw_repeat,
- kw_sample, kw_scalared, kw_sequence,
- kw_small, kw_soft, kw_solve,
- kw_specify, kw_specparam, kw_strong0,
- kw_strong1, kw_supply0, kw_supply1,
- kw_table, kw_tagged, kw_task,
- kw_tri, kw_tri0, kw_tri1,
- kw_triand, kw_trior, kw_trireg,
- kw_unique, kw_unique0, kw_uwire,
- kw_var, kw_vectored, kw_wait,
- kw_wand, kw_weak0, kw_weak1,
- kw_wildcard, kw_wire, kw_with,
- kw_wor, kw_verilogHash, kw_verilogHashHash});
+ VerilogExtraKeywords =
+ std::unordered_set<IdentifierInfo *>({kw_always,
+ kw_always_comb,
+ kw_always_ff,
+ kw_always_latch,
+ kw_assert,
+ kw_assign,
+ kw_assume,
+ kw_automatic,
+ kw_before,
+ kw_begin,
+ kw_bins,
+ kw_binsof,
+ kw_casex,
+ kw_casez,
+ kw_celldefine,
+ kw_checker,
+ kw_clocking,
+ kw_constraint,
+ kw_context,
+ kw_cover,
+ kw_covergroup,
+ kw_coverpoint,
+ kw_disable,
+ kw_dist,
+ kw_edge,
+ kw_end,
+ kw_endcase,
+ kw_endchecker,
+ kw_endclass,
+ kw_endclocking,
+ kw_endfunction,
+ kw_endgenerate,
+ kw_endgroup,
+ kw_endinterface,
+ kw_endmodule,
+ kw_endpackage,
+ kw_endprimitive,
+ kw_endprogram,
+ kw_endproperty,
+ kw_endsequence,
+ kw_endspecify,
+ kw_endtable,
+ kw_endtask,
+ kw_extends,
+ kw_final,
+ kw_foreach,
+ kw_forever,
+ kw_fork,
+ kw_function,
+ kw_generate,
+ kw_highz0,
+ kw_highz1,
+ kw_iff,
+ kw_ifnone,
+ kw_ignore_bins,
+ kw_illegal_bins,
+ kw_implements,
+ kw_import,
+ kw_initial,
+ kw_inout,
+ kw_input,
+ kw_inside,
+ kw_interconnect,
+ kw_interface,
+ kw_intersect,
+ kw_join,
+ kw_join_any,
+ kw_join_none,
+ kw_large,
+ kw_let,
+ kw_local,
+ kw_localparam,
+ kw_macromodule,
+ kw_matches,
+ kw_medium,
+ kw_module,
+ kw_negedge,
+ kw_output,
+ kw_package,
+ kw_packed,
+ kw_parameter,
+ kw_posedge,
+ kw_primitive,
+ kw_priority,
+ kw_program,
+ kw_property,
+ kw_pull0,
+ kw_pull1,
+ kw_pure,
+ kw_rand,
+ kw_randc,
+ kw_randcase,
+ kw_randsequence,
+ kw_ref,
+ kw_repeat,
+ kw_sample,
+ kw_scalared,
+ kw_sequence,
+ kw_small,
+ kw_soft,
+ kw_solve,
+ kw_specify,
+ kw_specparam,
+ kw_strong0,
+ kw_strong1,
+ kw_supply0,
+ kw_supply1,
+ kw_table,
+ kw_tagged,
+ kw_task,
+ kw_tri,
+ kw_tri0,
+ kw_tri1,
+ kw_triand,
+ kw_trior,
+ kw_trireg,
+ kw_unique,
+ kw_unique0,
+ kw_uwire,
+ kw_var,
+ kw_vectored,
+ kw_wait,
+ kw_wand,
+ kw_weak0,
+ kw_weak1,
+ kw_wildcard,
+ kw_wire,
+ kw_with,
+ kw_wor,
+ kw_verilogHash,
+ kw_verilogHashHash});
TableGenExtraKeywords = std::unordered_set<IdentifierInfo *>({
kw_assert,
@@ -1510,6 +1599,7 @@ struct AdditionalKeywords {
IdentifierInfo *kw_checker;
IdentifierInfo *kw_clocking;
IdentifierInfo *kw_constraint;
+ IdentifierInfo *kw_context;
IdentifierInfo *kw_cover;
IdentifierInfo *kw_covergroup;
IdentifierInfo *kw_coverpoint;
@@ -1794,11 +1884,13 @@ struct AdditionalKeywords {
case tok::kw_continue:
case tok::kw_default:
case tok::kw_do:
- case tok::kw_extern:
case tok::kw_else:
case tok::kw_enum:
+ case tok::kw_export:
+ case tok::kw_extern:
case tok::kw_for:
case tok::kw_if:
+ case tok::kw_import:
case tok::kw_restrict:
case tok::kw_signed:
case tok::kw_static:
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp
index 5e2584edac8f4..151ec90dd2f8e 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -1588,15 +1588,15 @@ void UnwrappedLineParser::parseStructuralElement(
parseTryCatch();
return;
case tok::kw_extern:
- nextToken();
if (Style.isVerilog()) {
- // In Verilog and extern module declaration looks like a start of module.
+ // In Verilog an extern module declaration looks like a start of module.
// But there is no body and endmodule. So we handle it separately.
- if (Keywords.isVerilogHierarchy(*FormatTok)) {
- parseVerilogHierarchyHeader();
+ if (tryToParseVerilogExtern())
return;
- }
- } else if (FormatTok->is(tok::string_literal)) {
+ break;
+ }
+ nextToken();
+ if (FormatTok->is(tok::string_literal)) {
nextToken();
if (FormatTok->is(tok::l_brace)) {
if (Style.BraceWrapping.AfterExternBlock)
@@ -1621,6 +1621,8 @@ void UnwrappedLineParser::parseStructuralElement(
parseJavaScriptEs6ImportExport();
return;
}
+ if (Style.isVerilog() && tryToParseVerilogExtern())
+ return;
if (IsCpp) {
nextToken();
if (FormatTok->is(tok::kw_namespace)) {
@@ -1669,6 +1671,8 @@ void UnwrappedLineParser::parseStructuralElement(
addUnwrappedLine();
return;
}
+ if (Style.isVerilog() && tryToParseVerilogExtern())
+ return;
if (IsCpp && parseModuleImport())
return;
}
@@ -4555,6 +4559,26 @@ void UnwrappedLineParser::parseVerilogCaseLabel() {
Line->Level = OrigLevel;
}
+bool UnwrappedLineParser::tryToParseVerilogExtern() {
+ assert(
+ FormatTok->isOneOf(tok::kw_extern, tok::kw_export, Keywords.kw_import));
+ nextToken();
+ // "DPI-C"
+ if (FormatTok->is(tok::string_literal))
+ nextToken();
+ if (FormatTok->isOneOf(Keywords.kw_context, Keywords.kw_pure))
+ nextToken();
+ if (Keywords.isVerilogIdentifier(*FormatTok))
+ nextToken();
+ if (FormatTok->is(tok::equal))
+ nextToken();
+ if (Keywords.isVerilogHierarchy(*FormatTok)) {
+ parseVerilogHierarchyHeader();
+ return true;
+ }
+ return false;
+}
+
bool UnwrappedLineParser::containsExpansion(const UnwrappedLine &Line) const {
for (const auto &N : Line.Tokens) {
if (N.Tok->MacroCtx)
diff --git a/clang/lib/Format/UnwrappedLineParser.h b/clang/lib/Format/UnwrappedLineParser.h
index 8b8ad84896f1a..12abbc0facc30 100644
--- a/clang/lib/Format/UnwrappedLineParser.h
+++ b/clang/lib/Format/UnwrappedLineParser.h
@@ -205,6 +205,8 @@ class UnwrappedLineParser {
unsigned parseVerilogHierarchyHeader();
void parseVerilogTable();
void parseVerilogCaseLabel();
+ // For import, export, and extern.
+ bool tryToParseVerilogExtern();
std::optional<llvm::SmallVector<llvm::SmallVector<FormatToken *, 8>, 1>>
parseMacroCall();
diff --git a/clang/unittests/Format/FormatTestVerilog.cpp b/clang/unittests/Format/FormatTestVerilog.cpp
index 63e2cadfdd7a1..eee2bbdf551e6 100644
--- a/clang/unittests/Format/FormatTestVerilog.cpp
+++ b/clang/unittests/Format/FormatTestVerilog.cpp
@@ -676,6 +676,16 @@ TEST_F(FormatTestVerilog, Hierarchy) {
" endprogram\n"
"endmodule");
// Test that an extern declaration doesn't change the indentation.
+ verifyFormat("import \"DPI-C\" context MyCFunc = function integer MapID\n"
+ " (int portID);\n"
+ "x = x;");
+ verifyFormat("export \"DPI-C\" function exported_sv_func;\n"
+ "x = x;");
+ verifyFormat("import \"DPI-C\" function void f1\n"
+ " (input int i1,\n"
+ " pair i2,\n"
+ " output logic [63 : 0] o3);\n"
+ "x = x;");
verifyFormat("extern module x;\n"
"x = x;");
// Test complex headers
More information about the cfe-commits
mailing list