diff --git a/driver/iverilog.man.in b/driver/iverilog.man.in index 47ebf4669..3861690d2 100644 --- a/driver/iverilog.man.in +++ b/driver/iverilog.man.in @@ -316,8 +316,8 @@ after a \fB\-Wall\fP argument to suppress isolated warning types. .TP 8 .B all -This enables the anachronisms, implicit, portbind, select\-range, -timescale, and sensitivity\-entire\-array warning categories. +This enables the anachronisms, implicit, macro-redefinition, portbind, +select\-range, timescale, and sensitivity\-entire\-array warning categories. .TP 8 .B anachronisms @@ -330,6 +330,10 @@ This enables warnings for creation of implicit declarations. For example, if a scalar wire X is used but not declared in the Verilog source, this will print a warning at its first use. +.TP 8 +.B macro-redefinition +This enables preprocessor warnings when a macro is being redefined. + .TP 8 .B portbind This enables warnings for ports of module instantiations that are not diff --git a/driver/main.c b/driver/main.c index fa038bfe6..d12c40fe1 100644 --- a/driver/main.c +++ b/driver/main.c @@ -138,7 +138,7 @@ int gen_std_include = 1; of the include list. */ int gen_relative_include = 0; -char warning_flags[16] = "n"; +char warning_flags[17] = "n"; int separate_compilation_flag = 0; @@ -346,10 +346,14 @@ static int t_version_only(void) static void build_preprocess_command(int e_flag) { - snprintf(tmp, sizeof tmp, "%s%civlpp %s%s -F\"%s\" -f\"%s\" -p\"%s\"%s", - ivlpp_dir, sep, verbose_flag?" -v":"", - e_flag?"":" -L", defines_path, source_path, - compiled_defines_path, e_flag?"":" | "); + snprintf(tmp, sizeof tmp, "%s%civlpp %s%s%s -F\"%s\" -f\"%s\" -p\"%s\"%s", + ivlpp_dir, sep, + verbose_flag ? " -v" : "", + e_flag ? "" : " -L", + strchr(warning_flags, 'r') ? " -Wredef " : "", + defines_path, source_path, + compiled_defines_path, + e_flag ? "" : " | "); } static int t_preprocess_only(void) @@ -520,6 +524,10 @@ static void process_warning_switch(const char*name) process_warning_switch("select-range"); process_warning_switch("timescale"); process_warning_switch("sensitivity-entire-array"); + process_warning_switch("macro-redefinition"); + } else if (strcmp(name,"macro-redefinition") == 0) { + if (! strchr(warning_flags, 'r')) + strcat(warning_flags, "r"); } else if (strcmp(name,"anachronisms") == 0) { if (! strchr(warning_flags, 'n')) strcat(warning_flags, "n"); @@ -558,6 +566,12 @@ static void process_warning_switch(const char*name) cp[0] = cp[1]; cp += 1; } + } else if (strcmp(name,"no-macro-redefinition") == 0) { + char*cp = strchr(warning_flags, 'r'); + if (cp) while (*cp) { + cp[0] = cp[1]; + cp += 1; + } } else if (strcmp(name,"no-floating-nets") == 0) { char*cp = strchr(warning_flags, 'f'); if (cp) while (*cp) { @@ -1306,8 +1320,11 @@ int main(int argc, char **argv) /* Write the preprocessor command needed to preprocess a single file. This may be used to preprocess library files. */ - fprintf(iconfig_file, "ivlpp:%s%civlpp -L -F\"%s\" -P\"%s\"\n", - ivlpp_dir, sep, defines_path, compiled_defines_path); + fprintf(iconfig_file, "ivlpp:%s%civlpp %s -L -F\"%s\" -P\"%s\"\n", + ivlpp_dir, sep, + strchr(warning_flags, 'r') ? "-Wredef" : "", + defines_path, compiled_defines_path + ); /* Done writing to the iconfig file. Close it now. */ fclose(iconfig_file); diff --git a/ivlpp/globals.h b/ivlpp/globals.h index 90b4632b9..1c4cee43d 100644 --- a/ivlpp/globals.h +++ b/ivlpp/globals.h @@ -53,6 +53,8 @@ extern char dep_mode; extern int verbose_flag; +extern int warn_redef; + /* This is the entry to the lexer. */ extern int yylex(void); diff --git a/ivlpp/lexor.lex b/ivlpp/lexor.lex index c81af7397..b8ccb6296 100644 --- a/ivlpp/lexor.lex +++ b/ivlpp/lexor.lex @@ -858,6 +858,19 @@ void define_macro(const char* name, const char* value, int keyword, int argc) { int idx; struct define_t* def; + struct define_t* prev; + + /* Verilog spec has a very nasty system of macros jumping from + * file to file, resulting in a global macro scope. We abosolutely + * MUST track macro redefinitions and warn user about them. + */ + + prev = def_lookup(name); + if (prev && warn_redef) { + emit_pathline(istack); + fprintf(stderr, "warning: redefinition of macro %s from value '%s' to '%s'\n", + name, prev->value, value); + } def = malloc(sizeof(struct define_t)); def->name = strdup(name); diff --git a/ivlpp/main.c b/ivlpp/main.c index 7ec80cb86..b4909b647 100644 --- a/ivlpp/main.c +++ b/ivlpp/main.c @@ -98,6 +98,9 @@ int line_direct_flag = 0; unsigned error_count = 0; FILE *depend_file = NULL; +/* Should we warn about macro redefinitions? */ +int warn_redef = 0; + static int flist_read_flags(const char*path) { char line_buf[2048]; @@ -282,7 +285,7 @@ int main(int argc, char*argv[]) include_dir[0] = 0; /* 0 is reserved for the current files path. */ include_dir[1] = strdup("."); - while ((opt=getopt(argc, argv, "F:f:K:Lo:p:P:vV")) != EOF) switch (opt) { + while ((opt=getopt(argc, argv, "F:f:K:Lo:p:P:vVW:")) != EOF) switch (opt) { case 'F': flist_read_flags(optarg); @@ -336,6 +339,12 @@ int main(int argc, char*argv[]) break; } + case 'W': { + if (strcmp(optarg, "redef")==0) + warn_redef = 1; + break; + } + case 'v': fprintf(stderr, "Icarus Verilog Preprocessor version " VERSION " (" VERSION_TAG ")\n\n"); @@ -366,7 +375,8 @@ int main(int argc, char*argv[]) " -p - Write precompiled defines to \n" " -P - Read precompiled defines from \n" " -v - Verbose\n" - " -V - Print version information and quit\n", + " -V - Print version information and quit\n" + " -W - Enable extra ivlpp warning category (e.g. redef)\n", argv[0]); return flag_errors; }