diff --git a/Changes b/Changes index b19a62339..7bcadc42f 100644 --- a/Changes +++ b/Changes @@ -11,6 +11,7 @@ Verilator 4.201 devel **Minor:** +* Add EOFNEWLINE warning when missing a newline at EOF. * Verilated signals now use VlWide and VlPacked in place of C arrays. * Fix class unpacked-array compile error (#2774). [Iru Cai] * Fix exceeding command-line ar limit (#2834). [Yinan Xu] diff --git a/bin/verilator b/bin/verilator index d18eafd5c..36176b5ed 100755 --- a/bin/verilator +++ b/bin/verilator @@ -1730,8 +1730,9 @@ received from third parties. Disable all code style related warning messages (note by default they are already disabled). This is equivalent to "-Wno-DECLFILENAME -Wno-DEFPARAM --Wno-IMPORTSTAR -Wno-INCABSPATH -Wno-PINCONNECTEMPTY -Wno-PINNOCONNECT --Wno-SYNCASYNCNET -Wno-UNDRIVEN -Wno-UNUSED -Wno-VARHIDDEN". +-Wno-EOFNEWLINE -Wno-IMPORTSTAR -Wno-INCABSPATH -Wno-PINCONNECTEMPTY +-Wno-PINNOCONNECT -Wno-SYNCASYNCNET -Wno-UNDRIVEN -Wno-UNUSED +-Wno-VARHIDDEN". =item -Wpedantic @@ -1756,9 +1757,9 @@ enabled), but do not affect style messages. This is equivalent to =item -Wwarn-style Enable all code style related warning messages. This is equivalent to -"-Wwarn ASSIGNDLY -Wwarn-DECLFILENAME -Wwarn-DEFPARAM -Wwarn-INCABSPATH --Wwarn-PINNOCONNECT -Wwarn-SYNCASYNCNET -Wwarn-UNDRIVEN -Wwarn-UNUSED --Wwarn-VARHIDDEN". +"-Wwarn ASSIGNDLY -Wwarn-DECLFILENAME -Wwarn-DEFPARAM -Wwarn-EOFNEWLINE +-Wwarn-INCABSPATH -Wwarn-PINNOCONNECT -Wwarn-SYNCASYNCNET -Wwarn-UNDRIVEN +-Wwarn-UNUSED -Wwarn-VARHIDDEN". =item --x-assign 0 @@ -4501,6 +4502,15 @@ the label attached to the block start. Ignoring this warning will only suppress the lint check, it will simulate correctly. +=item EOFNEWLINE + +Warns that a file does not end in a newline. POSIX defines that a line +must end in newline, as otherwise for example 'cat' of the file may produce +undesirable results. + +Disabled by default as this is a code style warning; it will simulate +correctly. + =item GENCLK Deprecated and no longer used as a warning. Used to indicate that the diff --git a/src/V3Error.h b/src/V3Error.h index 1b8ff02ed..307b8a397 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -82,6 +82,7 @@ public: DECLFILENAME, // Declaration doesn't match filename DEPRECATED, // Feature will be deprecated ENDLABEL, // End lable name mismatch + EOFNEWLINE, // End-of-file missing newline GENCLK, // Generated Clock HIERBLOCK, // Ignored hierarchical block setting IFDEPTH, // If statements too deep @@ -160,7 +161,7 @@ public: "CASEINCOMPLETE", "CASEOVERLAP", "CASEWITHX", "CASEX", "CASTCONST", "CDCRSTLOGIC", "CLKDATA", "CMPCONST", "COLONPLUS", "COMBDLY", "CONTASSREG", "DEFPARAM", "DECLFILENAME", "DEPRECATED", - "ENDLABEL", "GENCLK", "HIERBLOCK", + "ENDLABEL", "EOFNEWLINE", "GENCLK", "HIERBLOCK", "IFDEPTH", "IGNOREDRETURN", "IMPERFECTSCH", "IMPLICIT", "IMPORTSTAR", "IMPURE", "INCABSPATH", "INFINITELOOP", "INITIALDLY", "INSECURE", @@ -207,9 +208,10 @@ public: // Warnings that are style only bool styleError() const { return (m_e == ASSIGNDLY // More than style, but for backward compatibility - || m_e == BLKSEQ || m_e == DEFPARAM || m_e == DECLFILENAME || m_e == IMPORTSTAR - || m_e == INCABSPATH || m_e == PINCONNECTEMPTY || m_e == PINNOCONNECT - || m_e == SYNCASYNCNET || m_e == UNDRIVEN || m_e == UNUSED || m_e == VARHIDDEN); + || m_e == BLKSEQ || m_e == DEFPARAM || m_e == DECLFILENAME || m_e == EOFNEWLINE + || m_e == IMPORTSTAR || m_e == INCABSPATH || m_e == PINCONNECTEMPTY + || m_e == PINNOCONNECT || m_e == SYNCASYNCNET || m_e == UNDRIVEN || m_e == UNUSED + || m_e == VARHIDDEN); } }; inline bool operator==(const V3ErrorCode& lhs, const V3ErrorCode& rhs) { diff --git a/src/V3FileLine.h b/src/V3FileLine.h index fa77fdafa..0d8519d83 100644 --- a/src/V3FileLine.h +++ b/src/V3FileLine.h @@ -148,11 +148,19 @@ public: #endif // METHODS void newContent(); + void contentLineno(int num) { + lineno(num); + m_contentLineno = num; + } void lineno(int num) { m_firstLineno = num; m_lastLineno = num; m_firstColumn = m_lastColumn = 1; } + void column(int firstColumn, int lastColumn) { + m_firstColumn = firstColumn; + m_lastColumn = lastColumn; + } void language(V3LangCode lang) { singleton().numberToLang(filenameno(), lang); } void filename(const string& name) { m_filenameno = singleton().nameToNumber(name); } void parent(FileLine* fileline) { m_parent = fileline; } diff --git a/src/V3PreProc.cpp b/src/V3PreProc.cpp index c71070add..2fd43fa54 100644 --- a/src/V3PreProc.cpp +++ b/src/V3PreProc.cpp @@ -810,6 +810,8 @@ void V3PreProcImp::openFile(FileLine*, VInFilter* filterp, const string& filenam // Filter all DOS CR's en-mass. This avoids bugs with lexing CRs in the wrong places. // This will also strip them from strings, but strings aren't supposed // to be multi-line without a "\" + int eof_newline = 0; // Number of characters following last newline + int eof_lineno = 1; for (StrList::iterator it = wholefile.begin(); it != wholefile.end(); ++it) { // We don't end-loop at \0 as we allow and strip mid-string '\0's (for now). bool strip = false; @@ -821,6 +823,12 @@ void V3PreProcImp::openFile(FileLine*, VInFilter* filterp, const string& filenam strip = true; break; } + if (VL_UNLIKELY(*cp == '\n')) { + eof_newline = 0; + ++eof_lineno; + } else { + ++eof_newline; + } } if (strip) { string out; @@ -836,6 +844,15 @@ void V3PreProcImp::openFile(FileLine*, VInFilter* filterp, const string& filenam // Reclaim memory; the push saved the string contents for us *it = ""; } + + // Warning check + if (eof_newline) { + FileLine* fl = new FileLine{flsp}; + fl->contentLineno(eof_lineno); + fl->column(eof_newline + 1, eof_newline + 1); + fl->v3warn(EOFNEWLINE, "Missing newline at end of file (POSIX 3.206)." + << fl->warnMore() << "... Suggest add newline."); + } } void V3PreProcImp::insertUnreadbackAtBol(const string& text) { diff --git a/test_regress/t/t_lint_eofline.out b/test_regress/t/t_lint_eofline.out new file mode 100644 index 000000000..d4f4a5251 --- /dev/null +++ b/test_regress/t/t_lint_eofline.out @@ -0,0 +1,3 @@ +`line 1 "obj_vlt/t_lint_eofline/t_lint_eofline_bad.v" 1 + +`line 2 "obj_vlt/t_lint_eofline/t_lint_eofline_bad.v" 2 diff --git a/test_regress/t/t_lint_eofline.pl b/test_regress/t/t_lint_eofline.pl new file mode 100755 index 000000000..be8639453 --- /dev/null +++ b/test_regress/t/t_lint_eofline.pl @@ -0,0 +1,34 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +use IO::File; +use strict; +use vars qw($Self); + +scenarios(vlt => 1); + +sub gen { + my $filename = shift; + + my $fh = IO::File->new(">$filename"); + # Empty file should not EOFLINE warn +} + +top_filename("$Self->{obj_dir}/t_lint_eofline_bad.v"); + +gen($Self->{top_filename}); + +lint( + verilator_flags2 => ["--lint-only -Wall -Wno-DECLFILENAME -E"], + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_lint_eofline_bad.out b/test_regress/t/t_lint_eofline_bad.out new file mode 100644 index 000000000..ee6a52af0 --- /dev/null +++ b/test_regress/t/t_lint_eofline_bad.out @@ -0,0 +1,5 @@ +%Warning-EOFNEWLINE: obj_vlt/t_lint_eofline_bad/t_lint_eofline_bad.v:4:10: Missing newline at end of file (POSIX 3.206). : ... Suggest add newline. + 4 | endmodule + | ^ + ... Use "/* verilator lint_off EOFNEWLINE */" and lint_on around source to disable this message. +%Error: Exiting due to diff --git a/test_regress/t/t_lint_eofline_bad.pl b/test_regress/t/t_lint_eofline_bad.pl new file mode 100755 index 000000000..1528e4cef --- /dev/null +++ b/test_regress/t/t_lint_eofline_bad.pl @@ -0,0 +1,38 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +use IO::File; +use strict; +use vars qw($Self); + +scenarios(vlt => 1); + +sub gen { + my $filename = shift; + + my $fh = IO::File->new(">$filename"); + $fh->print("// Generated by t_lint_eofline_bad.pl\n"); + $fh->print("module t;\n"); + $fh->print("// No newline below:\n"); + $fh->print("endmodule"); # Intentionally no newline +} + +top_filename("$Self->{obj_dir}/t_lint_eofline_bad.v"); + +gen($Self->{top_filename}); + +lint( + verilator_flags2 => ["--lint-only -Wall -Wno-DECLFILENAME"], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1;