URI:
       cc1: Fix elif handling - scc - simple c99 compiler
  HTML git clone git://git.simple-cc.org/scc
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
   DIR README
   DIR LICENSE
       ---
   DIR commit b04e1786f2fbbf3976b6d0aba4cc122aefd23bc7
   DIR parent 740fd29faa97cc8a39c7e48c368191bc2df9cc99
  HTML Author: Roberto E. Vargas Caballero <k0ga@shike2.net>
       Date:   Thu, 29 Jan 2026 12:36:50 +0100
       
       cc1: Fix elif handling
       
       The code was assuming that an #else was always inverting the state of the
       preprocessor output, and elif was handled like a #else plus a #if, but
       that was not the actual case. The code tried to manage this situation
       counting the number of nested enabling/disabling of cppoff, but it was
       a non sense because we already had a stack of cpp contexts that could do
       the work much better. Also, we needed a sticky variable (called "done"
       in this commit) to track that one case of the if-else chain was true
       before, because the "enabled" field changes and then we forget the history
       of the chain.
       
       Diffstat:
         M src/cmd/scc-cc/cc1/cpp.c            |      74 ++++++++++++++++++++-----------
         A tests/cc/execute/0233-ifelif.c      |      15 +++++++++++++++
         M tests/cc/execute/scc-tests.lst      |       1 +
       
       3 files changed, 63 insertions(+), 27 deletions(-)
       ---
   DIR diff --git a/src/cmd/scc-cc/cc1/cpp.c b/src/cmd/scc-cc/cc1/cpp.c
       @@ -11,6 +11,7 @@
        #include "cc1.h"
        
        struct ifstate {
       +        unsigned char done;
                unsigned char enabled;
                unsigned char iselse;
        };
       @@ -867,15 +868,16 @@ ifclause(int negate, int isifdef)
        {
                Symbol *sym;
                unsigned n;
       -        int status;
       +        int enabled, done;
                Node *expr;
        
                if (cppctx == NR_COND-1)
                        error("too many nesting levels of conditional inclusion");
                n = cppctx++;
        
       -        if (cppoff) {
       -                status = 0;
       +        if (n > 0 && !ifstate[n-1].enabled) {
       +                done = 1;
       +                enabled = 0;
                        goto disabled;
                }
        
       @@ -890,8 +892,8 @@ ifclause(int negate, int isifdef)
                        }
                        sym = yylval.sym;
                        next();
       -                status = (sym->flags & SDECLARED) != 0;
       -                if (!status)
       +                enabled = (sym->flags & SDECLARED) != 0;
       +                if (!enabled)
                                killsym(sym);
                } else {
                        /* TODO: catch recovery here */
       @@ -900,18 +902,19 @@ ifclause(int negate, int isifdef)
                                return;
                        }
                        DBG("CPP if expr=%d", expr->sym->u.i);
       -                status = expr->sym->u.i != 0;
       +                enabled = expr->sym->u.i != 0;
                        freetree(expr);
                }
        
                if (negate)
       -                status = !status;
       +                enabled = !enabled;
       +        done = enabled;
        
        disabled:
       -        if (status == 0)
       -                ++cppoff;
       -        DBG("CPP if result=%d", status);
       -        ifstate[n].enabled = status;
       +        cppoff = !enabled;
       +        DBG("CPP if result=%d", enabled);
       +        ifstate[n].done = done;
       +        ifstate[n].enabled = enabled;
                ifstate[n].iselse = 0;
        }
        
       @@ -935,16 +938,6 @@ ifndef(void)
        }
        
        static void
       -elseclause(void)
       -{
       -        int status;
       -
       -        status = ifstate[cppctx-1].enabled;
       -        ifstate[cppctx-1].enabled = !status;
       -        cppoff += (status) ? 1 : -1;
       -}
       -
       -static void
        cppelse(void)
        {
                if (cppctx == 0 || ifstate[cppctx-1].iselse) {
       @@ -952,8 +945,21 @@ cppelse(void)
                        return;
                }
        
       -        ifstate[cppctx-1].iselse = 1;
       -        elseclause();
       +        /*
       +         * If we are disabled by a upper ifdef then ifclause() already
       +         * marked us as disabled and done. So if we are done then we
       +         * disable cpp because or ifclause was true, or it was disabled
       +         * by the upper. If we are not done, then it is our turn.
       +         */
       +        if (ifstate[cppctx-1].done) {
       +                ifstate[cppctx-1].enabled = 0;
       +                cppoff = 1;
       +        } else {
       +                ifstate[cppctx-1].done = 1;
       +                ifstate[cppctx-1].enabled = 1;
       +                cppoff = 0;
       +        }
       +
                next();
        }
        
       @@ -965,8 +971,17 @@ elif(void)
                        return;
                }
        
       -        elseclause();
       -        if (ifstate[cppctx-1].enabled) {
       +        /*
       +         * If we are disabled by a upper ifdef then ifclause() already
       +         * marked us as disabled and done. So if we are done then we
       +         * disable cpp because or ifclause was true, or it was disabled
       +         * by the upper. If we are not done, then we have to evaluate
       +         * the if condition.
       +         */
       +        if (ifstate[cppctx-1].done) {
       +                ifstate[cppctx-1].enabled = 0;
       +                cppoff = 1;
       +        } else {
                        --cppctx;
                        cppif();
                }
       @@ -977,8 +992,13 @@ endif(void)
        {
                if (cppctx == 0)
                        error("#endif without #if");
       -        if (!ifstate[--cppctx].enabled)
       -                --cppoff;
       +
       +        if (cppctx > 1)
       +                cppoff = !ifstate[cppctx - 2].enabled;
       +        else
       +                cppoff = 0;
       +
       +        --cppctx;
                next();
        }
        
   DIR diff --git a/tests/cc/execute/0233-ifelif.c b/tests/cc/execute/0233-ifelif.c
       @@ -0,0 +1,15 @@
       +#define FT_UINT_MAX 0xFFFFFFFFUL
       +
       +#if FT_UINT_MAX == 0xFFFFFFFFUL
       +#define FT_SIZEOF_INT  ( 32 / FT_CHAR_BIT )
       +#elif FT_UINT_MAX > 0xFFFFFFFFUL && FT_UINT_MAX == 0xFFFFFFFFFFFFFFFFUL
       +#define FT_SIZEOF_INT  ( 64 / FT_CHAR_BIT )
       +#else
       +#error "Unsupported size of `int' type!"
       +#endif
       +
       +int
       +main(void)
       +{
       +        return 0;
       +}
   DIR diff --git a/tests/cc/execute/scc-tests.lst b/tests/cc/execute/scc-tests.lst
       @@ -223,3 +223,4 @@
        0230-init.c
        0231-init.c
        0232-cppmacro.c
       +0233-ifelif.c