Thread

Commits

  1. Rename pg_builtin_integer_constant_p to pg_integer_constant_p

  2. Teach MSVC that elog/ereport ERROR doesn't return

  1. Fixing MSVC's inability to detect elog(ERROR) does not return

    David Rowley <dgrowleyml@gmail.com> — 2025-07-24T00:14:55Z

    (Moving this discussion to hackers. Previously in [0].)
    
    Background:
    
    The ereport_domain() macro has a pg_unreachable() which is meant to be
    hit when the elevel >= ERROR so that the compiler can determine that
    elog/ereport ERROR never returns. This works fine in gcc and clang but
    MSVC seems to be unable to figure this out.  This causes us to have to
    maintain hundreds of lines like "return NULL; /* keep compiler quiet
    */" to avoid warnings.
    
    What's causing this?:
    
    You might imagine that this happens because pg_unreachable() isn't
    working for MSVC, but you'd be wrong. It's because of the
    double-evaluation mitigation of elevel in the ereport_domain() macro.
    We have:
    
    const int elevel_ = (elevel);
    
    and because later we do:
    
        if (elevel_ >= ERROR) \
            pg_unreachable(); \
    
    the MSVC compiler can't figure out that the pg_unreachable() is always
    hit because it sees elevel_ as variable rather than constant, even
    when the macro's elevel parameter is a compile-time constant.
    
    Fixing it:
    
    Ideally, MSVC would have something like __builtin_const_p(). Looking
    around, I found [1], which hacks together a macro which does the same
    job. The problem is, the macro uses _Generic(), which is C11. Tom
    suggested we adjust the meson build scripts to make MSVC always build
    with C11, which seems doable due to 8fd9bb1d9 making our minimum
    Visual Studio version 2019, and going by [2], vs2019 supports C11.
    
    So, I think that means we can adjust the meson build scripts to pass
    /std:c11 when building in MSVC. The attached patch does this and
    defines a pg_builtin_constant() macro and adjusts ereport_domain() to
    use it.
    
    One thing I've not done yet is adjust all other usages of
    __builtin_const_p() to use pg_builtin_const().
    
    I did a quick check of the postgres.exe size with and without this
    change. It does save about 13KB, but that seems to be entirely from
    the /std:c11 flag. None is due to the compiler emitting less code
    after elog(ERROR) / ereport(ERROR) :-(
    
    postgres.exe size:
    master: 10_143_232 bytes
    patched: 10_129_920 bytes
    
    Does anyone have any objections or comments to any of the above?
    
    David
    
    [0] https://postgr.es/m/CAApHDvrFdXjbrV6KCx_GHKYSufUbNDYSsjppcJQiGOURfJE6qg@mail.gmail.com
    [1] https://stackoverflow.com/questions/49480442/detecting-integer-constant-expressions-in-macros
    [2] https://devblogs.microsoft.com/cppblog/c11-and-c17-standard-support-arriving-in-msvc/
    
  2. Re: Fixing MSVC's inability to detect elog(ERROR) does not return

    Tom Lane <tgl@sss.pgh.pa.us> — 2025-07-24T00:27:31Z

    David Rowley <dgrowleyml@gmail.com> writes:
    > I did a quick check of the postgres.exe size with and without this
    > change. It does save about 13KB, but that seems to be entirely from
    > the /std:c11 flag. None is due to the compiler emitting less code
    > after elog(ERROR) / ereport(ERROR) :-(
    
    Hmmm ... but you did check that in fact we can remove such known-dead
    code and not get a warning now?
    
    			regards, tom lane
    
    
    
    
  3. Re: Fixing MSVC's inability to detect elog(ERROR) does not return

    David Rowley <dgrowleyml@gmail.com> — 2025-07-24T01:47:07Z

    On Thu, 24 Jul 2025 at 12:27, Tom Lane <tgl@sss.pgh.pa.us> wrote:
    > Hmmm ... but you did check that in fact we can remove such known-dead
    > code and not get a warning now?
    
    Yes. The patch has a small temporary adjustment to
    BaseBackupGetTargetHandle() to comment out the return. It compiles for
    me using Visual Studio 2022 without any warnings. If I remove the
    macro change, I get:
    
    [598/2255] Compiling C object
    src/backend/postgres_lib.a.p/backup_basebackup_target.c.obj
    src\backend\backup\basebackup_target.c(150) : warning C4715:
    'BaseBackupGetTargetHandle': not all control paths return a value
    
    David
    
    
    
    
  4. Re: Fixing MSVC's inability to detect elog(ERROR) does not return

    Tom Lane <tgl@sss.pgh.pa.us> — 2025-07-24T03:43:18Z

    David Rowley <dgrowleyml@gmail.com> writes:
    > On Thu, 24 Jul 2025 at 12:27, Tom Lane <tgl@sss.pgh.pa.us> wrote:
    >> Hmmm ... but you did check that in fact we can remove such known-dead
    >> code and not get a warning now?
    
    > Yes. The patch has a small temporary adjustment to
    > BaseBackupGetTargetHandle() to comment out the return. It compiles for
    > me using Visual Studio 2022 without any warnings. If I remove the
    > macro change, I get:
    > [598/2255] Compiling C object
    > src/backend/postgres_lib.a.p/backup_basebackup_target.c.obj
    > src\backend\backup\basebackup_target.c(150) : warning C4715:
    > 'BaseBackupGetTargetHandle': not all control paths return a value
    
    OK.  I'd vote for going ahead and seeing what the buildfarm says.
    
    			regards, tom lane
    
    
    
    
  5. Re: Fixing MSVC's inability to detect elog(ERROR) does not return

    Peter Eisentraut <peter@eisentraut.org> — 2025-07-24T11:02:57Z

    On 24.07.25 03:14, David Rowley wrote:
    > So, I think that means we can adjust the meson build scripts to pass
    > /std:c11 when building in MSVC. The attached patch does this and
    > defines a pg_builtin_constant() macro and adjusts ereport_domain() to
    > use it.
    
    Please review my patch at
    
    https://www.postgresql.org/message-id/ccb273c9-7544-4748-8638-30feba212e6e@eisentraut.org
    https://commitfest.postgresql.org/patch/5934/
    
    for C11 support across all platforms.  Then we avoid the hybrid C99/C11 
    situation that your patch introduces.
    
    
    
    
    
  6. Re: Fixing MSVC's inability to detect elog(ERROR) does not return

    David Rowley <dgrowleyml@gmail.com> — 2025-09-02T02:57:21Z

    On Thu, 24 Jul 2025 at 23:03, Peter Eisentraut <peter@eisentraut.org> wrote:
    > Please review my patch at
    >
    > https://www.postgresql.org/message-id/ccb273c9-7544-4748-8638-30feba212e6e@eisentraut.org
    > https://commitfest.postgresql.org/patch/5934/
    
    Now that we're building with C11, here's a rebased patch with the new
    pg_builtin_constant() macro.
    
    I did some study into the code generation with the patched version. I
    see that errstart_cold() is being used correctly when the elevel is >=
    ERROR. Unfortunately, MSVC does not seem to have anything like
    __attribute__((cold)), so that does nothing different than what
    errstart() does.
    
    I also looked at the size of postgres.exe to see if the code
    generation had improved due to ereport_domain's __assume(0) being
    correctly picked up now. I was surprised to see that the binary had
    increased in size by about 13K:
    
    master: 10147840 bytes.
    patched: 10161152 bytes.
    
    Most of this extra seems to come from the errstart_cold function, as
    if I adjust ereport_domain with:
    
    -                       errstart_cold(elevel, domain) : \
    +                       errstart(elevel, domain) : \
    
    The size is 10149888 bytes, or 2k more than master.
    
    The reason I looked into this is because I wanted to check MSVC was
    correctly eliminating the errstart_code / errstart ternary condition.
    It does. I'm not sure where the extra 2k comes from, however.
    
    I'm unable to detect any performance differences running pgbench -M
    prepared -T 60 -S or with pgbench -M simple -T 60 -S.
    
    David
    
  7. Re: Fixing MSVC's inability to detect elog(ERROR) does not return

    Peter Eisentraut <peter@eisentraut.org> — 2025-09-03T11:31:37Z

    On 02.09.25 04:57, David Rowley wrote:
    > On Thu, 24 Jul 2025 at 23:03, Peter Eisentraut <peter@eisentraut.org> wrote:
    >> Please review my patch at
    >>
    >> https://www.postgresql.org/message-id/ccb273c9-7544-4748-8638-30feba212e6e@eisentraut.org
    >> https://commitfest.postgresql.org/patch/5934/
    > 
    > Now that we're building with C11, here's a rebased patch with the new
    > pg_builtin_constant() macro.
    
    +#if defined(HAVE__BUILTIN_CONSTANT_P)
    +#define pg_builtin_constant(x) __builtin_constant_p(x)
    +#define HAVE_PG_BUILTIN_CONSTANT
    +#elif defined(_MSC_VER) && defined(__STDC_VERSION__) && 
    __STDC_VERSION__ >= 201112L
    +#define pg_builtin_constant(x) \
    +   _Generic((1 ? ((void *) ((x) * (uintptr_t) 0)) : &(int) {1}), int *: 
    1, void *: 0)
    +#define HAVE_PG_BUILTIN_CONSTANT
    +#endif
    
    The variant using _Generic is not a full replacement for 
    __builtin_constant_p(), because it only detects integer constant 
    expressions.  So for example, it wouldn't work in the use in 
    src/include/utils/memutils.h, which checks for constant strings.  So I 
    think we need to be careful here to maintain the difference.
    
    I think what we could do is make a separate macro for detecting integer 
    constant expressions (like ICE_P() in the reddit thread) and define that 
    to __builtin_constant_p if available, else using _Generic.  (We can't 
    use _Generic on all platforms yet, that's a separate undertaking, but I 
    think all platforms support either __builtin_constant_p or _Generic.) 
    And then use that one for ereport.
    
    It would also be nice to provide a comment with some explanation and/or 
    a link and credit for the _Generic expression.
    
    Btw., I think we should stick to the *_p() naming (for "predicate", I 
    think) for compiler-intrinsic-affiliated functions/macros that report 
    boolean results.
    
    The __STDC_VERSION__ comparison can be dropped, since that is the 
    minimum now required.  (But you need to keep defined(__STDC_VERSION__), 
    since this won't work in C++.)
    
    
    
    
    
    
  8. Re: Fixing MSVC's inability to detect elog(ERROR) does not return

    David Rowley <dgrowleyml@gmail.com> — 2025-09-17T03:52:54Z

    On Wed, 3 Sept 2025 at 23:32, Peter Eisentraut <peter@eisentraut.org> wrote:
    > The variant using _Generic is not a full replacement for
    > __builtin_constant_p(), because it only detects integer constant
    > expressions.  So for example, it wouldn't work in the use in
    > src/include/utils/memutils.h, which checks for constant strings.  So I
    > think we need to be careful here to maintain the difference.
    
    Makes sense.
    
    > I think what we could do is make a separate macro for detecting integer
    > constant expressions (like ICE_P() in the reddit thread) and define that
    > to __builtin_constant_p if available, else using _Generic.  (We can't
    > use _Generic on all platforms yet, that's a separate undertaking, but I
    > think all platforms support either __builtin_constant_p or _Generic.)
    > And then use that one for ereport.
    
    Done
    
    > It would also be nice to provide a comment with some explanation and/or
    > a link and credit for the _Generic expression.
    
    I've added a link to the stackoverflow thread in the comment above the
    macro's definition.
    
    > Btw., I think we should stick to the *_p() naming (for "predicate", I
    > think) for compiler-intrinsic-affiliated functions/macros that report
    > boolean results.
    
    I didn't know what the _p suffix was meant to indicate. Do you have a
    link which states that it's for "predicate"?  The other things I had
    in mind were "pointer" and "proprocessor", neither of which makes much
    sense to me. Looking through [1], the only other intrinsic function I
    see ending in _p is __builtin_types_compatible_p(). I don't see what
    these both have in common with each other.
    
    I've modified the patch to include the _p, however, I'd personally
    rather leave this out as if someone asks me what it's for, I've got no
    answer for them, other than Peter said.
    
    > The __STDC_VERSION__ comparison can be dropped, since that is the
    > minimum now required.  (But you need to keep defined(__STDC_VERSION__),
    > since this won't work in C++.)
    
    Done.
    
    Updated patch attached.  Thanks for the review.
    
    David
    
    [1] https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html
    
  9. Re: Fixing MSVC's inability to detect elog(ERROR) does not return

    Tom Lane <tgl@sss.pgh.pa.us> — 2025-09-17T04:02:56Z

    David Rowley <dgrowleyml@gmail.com> writes:
    > On Wed, 3 Sept 2025 at 23:32, Peter Eisentraut <peter@eisentraut.org> wrote:
    >> Btw., I think we should stick to the *_p() naming (for "predicate", I
    >> think) for compiler-intrinsic-affiliated functions/macros that report
    >> boolean results.
    
    > I didn't know what the _p suffix was meant to indicate. Do you have a
    > link which states that it's for "predicate"?
    
    It absolutely stands for "predicate".  That's an ancient Lisp-ism.
    Here's the first link I found with some quick googling:
    
    https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node69.html
    
        A predicate is a function that tests for some condition involving
        its arguments and returns nil if the condition is false, or some
        non-nil value if the condition is true. One may think of a
        predicate as producing a Boolean value, where nil stands for false
        and anything else stands for true. Conditional control structures
        such as cond, if, when, and unless test such Boolean values. We
        say that a predicate is true when it returns a non-nil value, and
        is false when it returns nil; that is, it is true or false
        according to whether the condition being tested is true or false.
    
        By convention, the names of predicates usually end in the letter p
        (which stands for ``predicate''). Common Lisp uses a uniform
        convention in hyphenating names of predicates. If the name of the
        predicate is formed by adding a p to an existing name, such as the
        name of a data type, a hyphen is placed before the final p if and
        only if there is a hyphen in the existing name. For example,
        number begets numberp but standard-char begets standard-char-p. On
        the other hand, if the name of a predicate is formed by adding a
        prefixing qualifier to the front of an existing predicate name,
        the two names are joined with a hyphen and the presence or absence
        of a hyphen before the final p is not changed. For example, the
        predicate string-lessp has no hyphen before the p because it is
        the string version of lessp (a MacLisp function that has been
        renamed < in Common Lisp). The name string-less-p would
        incorrectly imply that it is a predicate that tests for a kind of
        object called a string-less, and the name stringlessp would
        connote a predicate that tests whether something has no strings
        (is ``stringless'')!
    
    Okay, that last part is pretty far down in the weeds.  But a "p"
    suffix meaning "predicate" has decades of history behind it.
    
    			regards, tom lane
    
    
    
    
  10. Re: Fixing MSVC's inability to detect elog(ERROR) does not return

    David Rowley <dgrowleyml@gmail.com> — 2025-09-17T04:25:36Z

    On Wed, 17 Sept 2025 at 16:03, Tom Lane <tgl@sss.pgh.pa.us> wrote:
    >
    > David Rowley <dgrowleyml@gmail.com> writes:
    > > On Wed, 3 Sept 2025 at 23:32, Peter Eisentraut <peter@eisentraut.org> wrote:
    > >> Btw., I think we should stick to the *_p() naming (for "predicate", I
    > >> think) for compiler-intrinsic-affiliated functions/macros that report
    > >> boolean results.
    >
    > > I didn't know what the _p suffix was meant to indicate. Do you have a
    > > link which states that it's for "predicate"?
    >
    > It absolutely stands for "predicate".  That's an ancient Lisp-ism.
    > Here's the first link I found with some quick googling:
    >
    > https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node69.html
    
    Thanks for the confirmation. I'm happy enough to leave the _p in
    there, but at the same time, I don't see the particular reason to
    follow some ancient Lisp rule. Maybe I'm in the minority, having never
    programmed in Lisp.
    
    Anyway, at least the justification for it is in the archives now. Thanks.
    
    David
    
    
    
    
  11. Re: Fixing MSVC's inability to detect elog(ERROR) does not return

    Tom Lane <tgl@sss.pgh.pa.us> — 2025-09-17T04:45:49Z

    David Rowley <dgrowleyml@gmail.com> writes:
    > On Wed, 17 Sept 2025 at 16:03, Tom Lane <tgl@sss.pgh.pa.us> wrote:
    >> It absolutely stands for "predicate".  That's an ancient Lisp-ism.
    
    > Thanks for the confirmation. I'm happy enough to leave the _p in
    > there, but at the same time, I don't see the particular reason to
    > follow some ancient Lisp rule.
    
    I'm just saying that that's surely where the gcc crew got it from.
    I do agree with Peter that we should follow that convention within
    the narrow realm of compiler intrinsics; but I'm not arguing for
    running around and renaming random PG functions to something_p.
    
    As long as we're delving into weeds: we have another project
    convention for "_P", which is terminal symbols in our grammar such
    as NULL_P.  Clearly, that "P" is not for "predicate"; I suppose it
    should be read as "parse" or "parser".  Given that large parts of
    original POSTGRES were written in Lisp, it's a tad hard to believe
    that whoever chose those names had not heard of the "predicate"
    convention.  I guess he/she figured that it didn't matter because
    there'd be very little overlap or scope for confusion, and that
    seems to have been borne out over time.
    
    			regards, tom lane
    
    
    
    
  12. Re: Fixing MSVC's inability to detect elog(ERROR) does not return

    David Rowley <dgrowleyml@gmail.com> — 2025-09-27T10:43:13Z

    On Wed, 17 Sept 2025 at 15:52, David Rowley <dgrowleyml@gmail.com> wrote:
    > Updated patch attached.  Thanks for the review.
    
    Now pushed and awaiting buildfarm feedback.
    
    Thanks for reviewing.
    
    David
    
    
    
    
  13. Re: Fixing MSVC's inability to detect elog(ERROR) does not return

    Peter Eisentraut <peter@eisentraut.org> — 2025-09-30T05:24:49Z

    On 27.09.25 12:43, David Rowley wrote:
    > On Wed, 17 Sept 2025 at 15:52, David Rowley <dgrowleyml@gmail.com> wrote:
    >> Updated patch attached.  Thanks for the review.
    > 
    > Now pushed and awaiting buildfarm feedback.
    
    Cool, seems to work.  I also tried it on CI by removing a few "silence 
    compiler warning" lines.
    
    Quick follow-up: How about we rename pg_builtin_integer_constant_p to 
    pg_integer_constant_p, since it's not actually built-in?  See attached 
    patch.
  14. Re: Fixing MSVC's inability to detect elog(ERROR) does not return

    David Rowley <dgrowleyml@gmail.com> — 2025-09-30T09:03:07Z

    On Tue, 30 Sept 2025 at 18:24, Peter Eisentraut <peter@eisentraut.org> wrote:
    > Quick follow-up: How about we rename pg_builtin_integer_constant_p to
    > pg_integer_constant_p, since it's not actually built-in?  See attached
    > patch.
    
    Seems like a good idea.
    
    The patch looks good. Thanks for fixing the __builtin_const_p typo
    that I managed to introduce too :|
    
    David
    
    
    
    
  15. Re: Fixing MSVC's inability to detect elog(ERROR) does not return

    Peter Eisentraut <peter@eisentraut.org> — 2025-09-30T19:32:09Z

    On 30.09.25 11:03, David Rowley wrote:
    > On Tue, 30 Sept 2025 at 18:24, Peter Eisentraut <peter@eisentraut.org> wrote:
    >> Quick follow-up: How about we rename pg_builtin_integer_constant_p to
    >> pg_integer_constant_p, since it's not actually built-in?  See attached
    >> patch.
    > 
    > Seems like a good idea.
    > 
    > The patch looks good. Thanks for fixing the __builtin_const_p typo
    > that I managed to introduce too :|
    
    pushed
    
    
    
    
    
  16. Re: Fixing MSVC's inability to detect elog(ERROR) does not return

    Tom Lane <tgl@sss.pgh.pa.us> — 2026-07-05T15:18:28Z

    David Rowley <dgrowleyml@gmail.com> writes:
    > Now pushed and awaiting buildfarm feedback.
    
    It came to my attention just now that 59c2f03d1 adjusted ereport()
    to be MSVC-friendly, but did not touch plpy_elog.h's PLy_elog(),
    which has a borrowed copy of the same logic.  Was that intentional?
    It seems like we should keep those looking alike.
    
    			regards, tom lane
    
    
    
    
  17. Re: Fixing MSVC's inability to detect elog(ERROR) does not return

    David Rowley <dgrowleyml@gmail.com> — 2026-07-05T21:54:40Z

    On Mon, 6 Jul 2026 at 03:18, Tom Lane <tgl@sss.pgh.pa.us> wrote:
    > It came to my attention just now that 59c2f03d1 adjusted ereport()
    > to be MSVC-friendly, but did not touch plpy_elog.h's PLy_elog(),
    > which has a borrowed copy of the same logic.  Was that intentional?
    
    That was unintentional and caused by my unawareness of that version of
    the macro.
    
    > It seems like we should keep those looking alike.
    
    Agreed.
    
    David
    
    
    
    
  18. Re: Fixing MSVC's inability to detect elog(ERROR) does not return

    Tom Lane <tgl@sss.pgh.pa.us> — 2026-07-05T22:15:31Z

    David Rowley <dgrowleyml@gmail.com> writes:
    > On Mon, 6 Jul 2026 at 03:18, Tom Lane <tgl@sss.pgh.pa.us> wrote:
    >> It came to my attention just now that 59c2f03d1 adjusted ereport()
    >> to be MSVC-friendly, but did not touch plpy_elog.h's PLy_elog(),
    >> which has a borrowed copy of the same logic.  Was that intentional?
    
    > That was unintentional and caused by my unawareness of that version of
    > the macro.
    
    >> It seems like we should keep those looking alike.
    
    > Agreed.
    
    Cool.  You wanna fix it, or shall I?
    
    			regards, tom lane
    
    
    
    
  19. Re: Fixing MSVC's inability to detect elog(ERROR) does not return

    David Rowley <dgrowleyml@gmail.com> — 2026-07-05T23:39:42Z

    On Mon, 6 Jul 2026 at 10:15, Tom Lane <tgl@sss.pgh.pa.us> wrote:
    > Cool.  You wanna fix it, or shall I?
    
    Happy happy either way. If you're keen to do it, please go ahead,
    otherwise I can take care of it.
    
    David
    
    
    
    
  20. Re: Fixing MSVC's inability to detect elog(ERROR) does not return

    Tom Lane <tgl@sss.pgh.pa.us> — 2026-07-06T17:49:09Z

    David Rowley <dgrowleyml@gmail.com> writes:
    > On Mon, 6 Jul 2026 at 10:15, Tom Lane <tgl@sss.pgh.pa.us> wrote:
    >> Cool.  You wanna fix it, or shall I?
    
    > Happy happy either way. If you're keen to do it, please go ahead,
    > otherwise I can take care of it.
    
    OK, done.
    
    			regards, tom lane