preproc: Fix up conditional handling.
authorMarcelina Kościelnicka <mwk@0x04.net>
Mon, 29 Mar 2021 23:15:49 +0000 (01:15 +0200)
committerMarcelina Kościelnicka <mwk@0x04.net>
Tue, 30 Mar 2021 00:29:26 +0000 (02:29 +0200)
Fixes #2710.
Fixes #2711.

frontends/verilog/preproc.cc

index 84966e501905379ff996c6c612a0446dc37a1646..568224da241042027559d26cffa8c3dbe1746752 100644 (file)
@@ -726,8 +726,16 @@ frontend_verilog_preproc(std::istream                 &f,
        defines.merge(global_defines_cache);
 
        std::vector<std::string> filename_stack;
+       // We are inside pass_level levels of satisfied ifdefs, and then within
+       // fail_level levels of unsatisfied ifdefs.  The unsatisfied ones are
+       // always within satisfied ones — even if some condition within is true,
+       // the parent condition failing renders it moot.
        int ifdef_fail_level = 0;
        int ifdef_pass_level = 0;
+       // For the outermost unsatisfied ifdef, true iff that ifdef already
+       // had a satisfied branch, and further elsif/else branches should be
+       // considered unsatisfied even if the condition is true.
+       // Meaningless if ifdef_fail_level == 0.
        bool ifdef_already_satisfied = false;
 
        output_code.clear();
@@ -745,7 +753,7 @@ frontend_verilog_preproc(std::istream                 &f,
                        if (ifdef_fail_level > 0)
                                ifdef_fail_level--;
                        else if (ifdef_pass_level > 0)
-                               ifdef_already_satisfied = --ifdef_pass_level;
+                               ifdef_pass_level--;
                        else
                                log_error("Found %s outside of macro conditional branch!\n", tok.c_str());
                        continue;
@@ -755,8 +763,9 @@ frontend_verilog_preproc(std::istream                 &f,
                        if (ifdef_fail_level == 0) {
                                if (ifdef_pass_level == 0)
                                        log_error("Found %s outside of macro conditional branch!\n", tok.c_str());
-                               log_assert(ifdef_already_satisfied);
+                               ifdef_pass_level--;
                                ifdef_fail_level = 1;
+                               ifdef_already_satisfied = true;
                        } else if (ifdef_fail_level == 1 && !ifdef_already_satisfied) {
                                ifdef_fail_level = 0;
                                ifdef_pass_level++;
@@ -771,8 +780,9 @@ frontend_verilog_preproc(std::istream                 &f,
                        if (ifdef_fail_level == 0) {
                                if (ifdef_pass_level == 0)
                                        log_error("Found %s outside of macro conditional branch!\n", tok.c_str());
-                               log_assert(ifdef_already_satisfied);
+                               ifdef_pass_level--;
                                ifdef_fail_level = 1;
+                               ifdef_already_satisfied = true;
                        } else if (ifdef_fail_level == 1 && !ifdef_already_satisfied && defines.find(name)) {
                                ifdef_fail_level = 0;
                                ifdef_pass_level++;
@@ -931,6 +941,10 @@ frontend_verilog_preproc(std::istream                 &f,
                output_code.push_back(tok);
        }
 
+       if (ifdef_fail_level > 0 || ifdef_pass_level > 0) {
+               log_error("Unterminated preprocessor conditional!\n");
+       }
+
        std::string output;
        for (auto &str : output_code)
                output += str;