https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120778

--- Comment #3 from GCC Commits <cvs-commit at gcc dot gnu.org> ---
The master branch has been updated by Jakub Jelinek <ja...@gcc.gnu.org>:

https://gcc.gnu.org/g:8f185d3d7a2bcbbfb1a8f70ac602ee6e4ac34080

commit r16-2634-g8f185d3d7a2bcbbfb1a8f70ac602ee6e4ac34080
Author: Jakub Jelinek <ja...@redhat.com>
Date:   Wed Jul 30 13:20:59 2025 +0200

    libcpp: Fix up comma diagnostics in preprocessor for C++ [PR120778]

    The P2843R3 Preprocessing is never undefined paper contains comments
    that various compilers handle comma operators in preprocessor expressions
    incorrectly and I think they are right.

    In both C and C++ the grammar uses constant-expression non-terminal
    for #if/#elif and in both C and C++ that NT is conditional-expression,
    so
      #if 1, 2
    is IMHO clearly wrong in both languages.

    C89 then says for constant-expression
    "Constant expressions shall not contain assignment, increment, decrement,
    function-call, or comma operators, except when they are contained within
the
    operand of a sizeof operator."
    Because all the remaining identifiers in the #if/#elif expression are
    replaced with 0 I think assignments, increment, decrement and function-call
    aren't that big deal because (0 = 1) or ++4 etc. are all invalid, but
    for comma expressions I think it matters.  In r0-56429 PR456 Joseph has
    added !CPP_OPTION (pfile, c99) to handle that correctly.
    Then C99 changed that to:
    "Constant expressions shall not contain assignment, increment, decrement,
function-call,
    or comma operators, except when they are contained within a subexpression
that is not
    evaluated."
    That made for C99+
      #if 1 || (1, 2)
    etc. valid but
      #if (1, 2)
    is still invalid, ditto
      #if 1 ? 1, 2 : 3

    In C++ I can't find anything like that though, and as can be seen on say
    int a[(1, 2)];
    int b[1 ? 1, 2 : 3];
    being accepted by C++ and rejected by C while
    int c[1, 2];
    int d[1 ? 2 : 3, 4];
    being rejected in both C and C++, so I think for C++ it is indeed just the
    grammar that prevents #if 1, 2.  When it is the second operand of ?: or
    inside of () the grammar just uses expression and that allows comma
    operator.

    So, the following patch uses different decisions for C++ when to diagnose
    comma operator in preprocessor expressions, for C++ tracks if it is inside
    of () (obviously () around #embed clauses don't count unless one uses
    limit ((1, 2)) etc.) or inside of the second ?: operand and allows comma
    operator there and disallows elsewhere.

    BTW, I wonder if anything in the standard disallows <=> in the preprocessor
    expressions.  Say
      #if (0 <=> 1) < 0
    etc.
      #include <compare>
      constexpr int a = (0 <=> 1) < 0;
    is valid (but not valid without #include <compare>) and the expressions
    don't use any identifiers.

    2025-07-30  Jakub Jelinek  <ja...@redhat.com>

            PR c++/120778
            * internal.h (struct lexer_state): Add comma_ok member.
            * expr.cc (_cpp_parse_expr): Initialize it to 0, increment on
            CPP_OPEN_PAREN and CPP_QUERY, decrement on CPP_CLOSE_PAREN
            and CPP_COLON.
            (num_binary_op): For C++ pedwarn on comma operator if
            pfile->state.comma_ok is 0 instead of !c99 or skip_eval.

            * g++.dg/cpp/if-comma-1.C: New test.

Reply via email to