Обсуждение: Make copyObject work in C++

Поиск
Список
Период
Сортировка

Make copyObject work in C++

От
Jelte Fennema-Nio
Дата:
Calling copyObject fails in C++ with an error like in most setups:

error: use of undeclared identifier 'typeof'; did you mean 'typeid'

This is due to the C compiler supporting used to compile postgres
supporting typeof, but that function actually not being present in the
C++ compiler. This fixes that by using decltype instead of typeof when
including the header in C++.

Realized because of Thomas' not about how much of our headers should
work in C++, and remembering I hit this specific problem myself.

Another approach would be to force the value of HAVE_TYPEOF to 0 if __cplusplus.

Вложения

Re: Make copyObject work in C++

От
Tom Lane
Дата:
Jelte Fennema-Nio <postgres@jeltef.nl> writes:
> Calling copyObject fails in C++ with an error like in most setups:
> error: use of undeclared identifier 'typeof'; did you mean 'typeid'
> This is due to the C compiler supporting used to compile postgres
> supporting typeof, but that function actually not being present in the
> C++ compiler. This fixes that by using decltype instead of typeof when
> including the header in C++.

Hmm, this only fixes the one use-case.  Admittedly we have only one
use-case, but as soon as we have another we'll have a new problem.
How about instead modifying the macro?  Maybe something like this
in c.h (untested):

#ifdef __cplusplus
#undef typeof
#define typeof decltype
#define HAVE_TYPEOF 1
#endif

> Another approach would be to force the value of HAVE_TYPEOF to 0 if __cplusplus.

That would be sad, because we'd lose the type checking ability
of copyObject() in C++ code.

BTW, grepping finds a number of random references to __typeof__ and
__typeof, which probably ought to be updated to be just typeof.

            regards, tom lane



Re: Make copyObject work in C++

От
Peter Eisentraut
Дата:
On 05.12.25 15:46, Jelte Fennema-Nio wrote:
> Calling copyObject fails in C++ with an error like in most setups:
> 
> error: use of undeclared identifier 'typeof'; did you mean 'typeid'
> 
> This is due to the C compiler supporting used to compile postgres
> supporting typeof, but that function actually not being present in the
> C++ compiler. This fixes that by using decltype instead of typeof when
> including the header in C++.
> 
> Realized because of Thomas' not about how much of our headers should
> work in C++, and remembering I hit this specific problem myself.
> 
> Another approach would be to force the value of HAVE_TYPEOF to 0 if __cplusplus.

In the long run, I would like to change copyObject() to use 
typeof_unqual instead, because that handles qualifiers more correctly. 
(Currently, copyObject() of a const-qualified pointer results in a 
const-qualified pointer, which is nonsensical because the reason you 
made the copy is that you can modify it.)  See attached patch for an 
example.  Does C++ have something that is semantically similar to that?
Вложения

Re: Make copyObject work in C++

От
Peter Eisentraut
Дата:
On 07.12.25 20:45, Tom Lane wrote:
> Hmm, this only fixes the one use-case.  Admittedly we have only one
> use-case, but as soon as we have another we'll have a new problem.
> How about instead modifying the macro?  Maybe something like this
> in c.h (untested):
> 
> #ifdef __cplusplus
> #undef typeof
> #define typeof decltype
> #define HAVE_TYPEOF 1
> #endif

AFAICT, both gcc and clang support typeof in C++ mode as well.  So this 
kind of renaming could be confusing.



Re: Make copyObject work in C++

От
"Jelte Fennema-Nio"
Дата:
On Sun Dec 7, 2025 at 8:45 PM CET, Tom Lane wrote:
> #ifdef __cplusplus
> #undef typeof
> #define typeof decltype
> #define HAVE_TYPEOF 1
> #endif

Went with defining pg_exprtype (pg_typeof already exists). Undefining
typeof seemed a bit heavy-handed. Especially since I think it would be
nice to backport this so C++ extensions can use copyObject directly.

> BTW, grepping finds a number of random references to __typeof__ and
> __typeof, which probably ought to be updated to be just typeof.

Added a follow on patch that starts using pg_exrtype in all those
places.

Вложения

Re: Make copyObject work in C++

От
David Geier
Дата:
On 08.12.2025 08:57, Peter Eisentraut wrote:
> On 05.12.25 15:46, Jelte Fennema-Nio wrote:
>> Calling copyObject fails in C++ with an error like in most setups:
>>
>> error: use of undeclared identifier 'typeof'; did you mean 'typeid'
>>
>> This is due to the C compiler supporting used to compile postgres
>> supporting typeof, but that function actually not being present in the
>> C++ compiler. This fixes that by using decltype instead of typeof when
>> including the header in C++.
>>
>> Realized because of Thomas' not about how much of our headers should
>> work in C++, and remembering I hit this specific problem myself.
>>
>> Another approach would be to force the value of HAVE_TYPEOF to 0 if
>> __cplusplus.
> 
> In the long run, I would like to change copyObject() to use
> typeof_unqual instead, because that handles qualifiers more correctly.
> (Currently, copyObject() of a const-qualified pointer results in a
> const-qualified pointer, which is nonsensical because the reason you
> made the copy is that you can modify it.)  See attached patch for an
> example.  Does C++ have something that is semantically similar to that?

Since C++11 there's std::remove_const which can be used as
std::remove_const<decltype(type)>::type.

I'm not aware of anything pre C++11, except for rolling your own variant
of std::remove_const via template specialization.

--
David Geier



Re: Make copyObject work in C++

От
Jelte Fennema-Nio
Дата:
On Mon, 8 Dec 2025 at 09:33, David Geier <geidav.pg@gmail.com> wrote:
> Since C++11 there's std::remove_const which can be used as
> std::remove_const<decltype(type)>::type.
>
> I'm not aware of anything pre C++11, except for rolling your own variant
> of std::remove_const via template specialization.

I think depending on C++11 sounds fine, since we're also depending on
C11 and people tend to use much more recent C++ versions than C
versions (so probably we could even require something higher).



Re: Make copyObject work in C++

От
Tom Lane
Дата:
Peter Eisentraut <peter@eisentraut.org> writes:
> AFAICT, both gcc and clang support typeof in C++ mode as well.  So this 
> kind of renaming could be confusing.

Hm, if that's true then we should not have to do anything ...
so why is Jelte reporting a problem?

            regards, tom lane



Re: Make copyObject work in C++

От
Jelte Fennema-Nio
Дата:
On Mon, 8 Dec 2025 at 15:51, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>
> Peter Eisentraut <peter@eisentraut.org> writes:
> > AFAICT, both gcc and clang support typeof in C++ mode as well.  So this
> > kind of renaming could be confusing.
>
> Hm, if that's true then we should not have to do anything ...
> so why is Jelte reporting a problem?

Seems it's related to -std=c++17 vs -std=gnu++17. I was compiling my
code with the former, which throws the error in question[1]. Compiling
with the latter works fine[2].

So I guess it depends what we want to require from C++ extensions.
Should we require them to compile with gnu extensions? My opinion on
that would be no.

[1]: https://godbolt.org/z/fz567hs1r
[2]: https://godbolt.org/z/cq1se55bn



Re: Make copyObject work in C++

От
Jelte Fennema-Nio
Дата:
On Mon, 8 Dec 2025 at 08:57, Peter Eisentraut <peter@eisentraut.org> wrote:
> In the long run, I would like to change copyObject() to use
> typeof_unqual instead, because that handles qualifiers more correctly.
> (Currently, copyObject() of a const-qualified pointer results in a
> const-qualified pointer, which is nonsensical because the reason you
> made the copy is that you can modify it.)  See attached patch for an
> example.  Does C++ have something that is semantically similar to that?

Yes, there's a std::remove_cv, std::remove_const, and std::remove_volatile[1].

[1]: https://en.cppreference.com/w/cpp/types/remove_cv.html



Re: Make copyObject work in C++

От
"Jelte Fennema-Nio"
Дата:
On Mon Dec 8, 2025 at 9:11 AM CET, Jelte Fennema-Nio wrote:
> Went with defining pg_exprtype (pg_typeof already exists). Undefining
> typeof seemed a bit heavy-handed. Especially since I think it would be
> nice to backport this so C++ extensions can use copyObject directly.

Rebased version of this patchset after conflicts from 315342ffed.

Вложения

Re: Make copyObject work in C++

От
Peter Eisentraut
Дата:
On 05.12.25 15:46, Jelte Fennema-Nio wrote:
> Calling copyObject fails in C++ with an error like in most setups:
> 
> error: use of undeclared identifier 'typeof'; did you mean 'typeid'
> 
> This is due to the C compiler supporting used to compile postgres
> supporting typeof, but that function actually not being present in the
> C++ compiler. This fixes that by using decltype instead of typeof when
> including the header in C++.
> 
> Realized because of Thomas' not about how much of our headers should
> work in C++, and remembering I hit this specific problem myself.

I think it might be good to create a test extension written in C++, like 
under src/test/modules/, and sprinkle it with various constructs like 
copyObject() and static assertions, and whatever else we find that is 
possibly problematic.  Then patches like this one would be much easier 
to analyze and test and keep working in the future.

This would probably require resolving 
<https://commitfest.postgresql.org/patch/5885/> first.




Re: Make copyObject work in C++

От
"Jelte Fennema-Nio"
Дата:
On Tue Dec 16, 2025 at 1:28 PM CET, Peter Eisentraut wrote:
> I think it might be good to create a test extension written in C++, like
> under src/test/modules/, and sprinkle it with various constructs like
> copyObject() and static assertions, and whatever else we find that is
> possibly problematic.

Attached is a patchset that does that. It required a few more fixes to
make the extension compile on MSVC too.

Вложения

Re: Make copyObject work in C++

От
"Jelte Fennema-Nio"
Дата:
On Sat Jan 3, 2026 at 10:32 AM CET, Jelte Fennema-Nio wrote:
> Attached is a patchset that does that. It required a few more fixes to
> make the extension compile on MSVC too.

Rebased after Peter merged the C++ improvements from the other thread.

Вложения

Re: Make copyObject work in C++

От
Peter Eisentraut
Дата:
On 10.01.26 12:09, Jelte Fennema-Nio wrote:
> On Sat Jan 3, 2026 at 10:32 AM CET, Jelte Fennema-Nio wrote:
>> Attached is a patchset that does that. It required a few more fixes to
>> make the extension compile on MSVC too.
> 
> Rebased after Peter merged the C++ improvements from the other thread.

I have a couple of comments on the sample extension module.

I think this module should have a runtime test, too.  Otherwise you 
don't know that you got the linkage correct, or whether this works at 
all.  It doesn't have to do much, like it could literally be a + b, and 
it could evolve in the future to test hooks, _PG_init, etc.

Let's put a README file in the module's directory instead of putting the 
explanation into the Makefile/meson.build.

I wonder if the module's build integration would work correctly in the 
autoconf/makefile case if no C++ is available.  AFAICT, it would fail to 
build with g++ not found or similar.

AFAICT, the minimum changes to get a minimum test module to work are

- fix for "restrict", recently committed
- disable warning about zero-length arrays, seems trivial
- named designated initializers

I learned that named designated initializers in C++ are not allowed to 
be specified out of order, so they are not a full equivalent to the C 
syntax.  This could be a problem for example if someone wanted in the 
future to have something like

     PG_MODULE_MAGIC_EXT(.threads_supported = true)

(while not specifying the leading .name and .version fields).

I think for now the easiest fix would be to just not use the named 
initializers in the definition of PG_MODULE_MAGIC_DATA.  Then we don't 
need to require C++20 and have that additional code.  In the future, we 
might need a different solution more suitable for C++.

The use of -std=c++11 for CI is a valid idea; I have often wanted that 
for C as well.  But conversely we also want to allow testing optional 
extension and future C standard features.  So we need a comprehensive 
solution there that covers both ends and both languages.  Let's leave 
that out for now and think about it separately.




Re: Make copyObject work in C++

От
"Jelte Fennema-Nio"
Дата:
On Wed, 14 Jan 2026 at 16:59, Peter Eisentraut <peter@eisentraut.org> wrote:
> I think this module should have a runtime test, too.  Otherwise you
> don't know that you got the linkage correct, or whether this works at
> all.  It doesn't have to do much, like it could literally be a + b, and
> it could evolve in the future to test hooks, _PG_init, etc.

Done

> Let's put a README file in the module's directory instead of putting the
> explanation into the Makefile/meson.build.

Done

> I wonder if the module's build integration would work correctly in the
> autoconf/makefile case if no C++ is available.  AFAICT, it would fail to
> build with g++ not found or similar.

Changed this to check that if CXX is g++, the command is also actually
available before including the module for the build.

> AFAICT, the minimum changes to get a minimum test module to work are
>
> - fix for "restrict", recently committed
> - disable warning about zero-length arrays, seems trivial
> - named designated initializers

Correct, I've now restructured the commits to have the module
introduction as the first one. Then all the other commits, both fix a
macro to work in C++ and add some usage of those macros as coverage to
the previously added module.

> I learned that named designated initializers in C++ are not allowed to
> be specified out of order, so they are not a full equivalent to the C
> syntax.  This could be a problem for example if someone wanted in the
> future to have something like
>
>      PG_MODULE_MAGIC_EXT(.threads_supported = true)
>
> (while not specifying the leading .name and .version fields).

This would still work fine, because fields are left out. The problem
occurs when defining values for fields, but in a different order than
the fields are specified in the struct (so e.g. by putting .version
before .name). The reason for that is related to destructor ordering.

> I think for now the easiest fix would be to just not use the named
> initializers in the definition of PG_MODULE_MAGIC_DATA.  Then we don't
> need to require C++20 and have that additional code.  In the future, we
> might need a different solution more suitable for C++.

There is a small problem with this though. Using both designated an
non-designated initializers, is not valid standard C++. I even get a
warning (but no error) about that with clang:

../src/test/modules/test_cplusplusext/test_cplusplusext.cpp:24:2: warning: mixture of designated and non-designated
initializersin the same initializer list is a C99 extension [-Wc99-designator] 

In C mixing them is allowed just fine.

Sadly that means that C++ extensions (even when compiled for C++20)
shouldn't use PG_MODULE_MAGIC_EXT with designated initializers at all.
I've updated the documentation to reflect that. I agree that it's better
to avoid requiring C++20 on MSVC (at least for now).

> The use of -std=c++11 for CI is a valid idea; I have often wanted that
> for C as well.  But conversely we also want to allow testing optional
> extension and future C standard features.  So we need a comprehensive
> solution there that covers both ends and both languages.  Let's leave
> that out for now and think about it separately.

Removed

Вложения

Re: Make copyObject work in C++

От
Peter Eisentraut
Дата:
On 17.01.26 16:25, Jelte Fennema-Nio wrote:
>> AFAICT, the minimum changes to get a minimum test module to work are
>>
>> - fix for "restrict", recently committed
>> - disable warning about zero-length arrays, seems trivial
>> - named designated initializers
> 
> Correct, I've now restructured the commits to have the module
> introduction as the first one. Then all the other commits, both fix a
> macro to work in C++ and add some usage of those macros as coverage to
> the previously added module.

I have split your first patch further.  For a start, I left out the 
PG_MODULE_MAGIC*-related changes and disabled the module under MSVC. 
This has been committed.  I plan to let the buildfarm run with it for a 
day or two and then add in the basic MSVC support.

I implemented a different solution for checking whether C++ is available 
under configure.  The runtime check from the makefile looked a bit 
fragile.  This way, we now have a "have_cxx" variable available in both 
meson and makefiles.




Re: Make copyObject work in C++

От
Andres Freund
Дата:
On 2026-01-20 17:28:00 +0100, Peter Eisentraut wrote:
> On 17.01.26 16:25, Jelte Fennema-Nio wrote:
> > > AFAICT, the minimum changes to get a minimum test module to work are
> > >
> > > - fix for "restrict", recently committed
> > > - disable warning about zero-length arrays, seems trivial
> > > - named designated initializers
> >
> > Correct, I've now restructured the commits to have the module
> > introduction as the first one. Then all the other commits, both fix a
> > macro to work in C++ and add some usage of those macros as coverage to
> > the previously added module.
>
> I have split your first patch further.  For a start, I left out the
> PG_MODULE_MAGIC*-related changes and disabled the module under MSVC. This
> has been committed.  I plan to let the buildfarm run with it for a day or
> two and then add in the basic MSVC support.

Seems like billbug doesn't like this:

https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=billbug&dt=2026-01-20%2016%3A00%3A02

gmake[1]: Entering directory
'/home/marcel/build-farm-20/buildroot/HEAD/pgsql.build/src/test/modules/test_cplusplusext'
g++ -Wall -Wpointer-arith -Wendif-labels -Wmissing-format-attribute -Wimplicit-fallthrough=3 -Wcast-function-type
-Wshadow=compatible-local-Wformat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard -g -O2 -fPIC
-fvisibility=hidden-fvisibility-inlines-hidden -I. -I. -I../../../../src/include -D_POSIX_C_SOURCE=200112L
-D__EXTENSIONS__-D_POSIX_PTHREAD_SEMANTICS  -I/usr/openssl/3/include -I/usr/include/libxml2     -c -o
test_cplusplusext.otest_cplusplusext.cpp
 
In file included from ../../../../src/include/postgres.h:48,
                 from test_cplusplusext.cpp:18:
../../../../src/include/c.h:158:21: error: '_Noreturn' does not name a type; did you mean 'pg_noreturn'?
  158 | #define pg_noreturn _Noreturn
      |                     ^~~~~~~~~
../../../../src/include/c.h:918:1: note: in expansion of macro 'pg_noreturn'
  918 | pg_noreturn extern void ExceptionalCondition(const char *conditionName,
      | ^~~~~~~~~~~
../../../../src/include/lib/stringinfo.h: In function 'void initStringInfoFromString(StringInfo, char*, int)':
../../../../src/include/c.h:890:25: error: 'ExceptionalCondition' was not declared in this scope
  890 |                         ExceptionalCondition(#condition, __FILE__, __LINE__); \\
      |                         ^~~~~~~~~~~~~~~~~~~~
../../../../src/include/lib/stringinfo.h:177:9: note: in expansion of macro 'Assert'
  177 |         Assert(data[len] == '\\0');
      |         ^~~~~~
../../../../src/include/utils/elog.h: At global scope:
../../../../src/include/c.h:158:21: error: '_Noreturn' does not name a type; did you mean 'pg_noreturn'?
  158 | #define pg_noreturn _Noreturn
      |                     ^~~~~~~~~
../../../../src/include/utils/elog.h:471:1: note: in expansion of macro 'pg_noreturn'
  471 | pg_noreturn extern void ReThrowError(ErrorData *edata);
      | ^~~~~~~~~~~
../../../../src/include/c.h:158:21: error: '_Noreturn' does not name a type; did you mean 'pg_noreturn'?
  158 | #define pg_noreturn _Noreturn
      |                     ^~~~~~~~~
../../../../src/include/utils/elog.h:473:1: note: in expansion of macro 'pg_noreturn'
  473 | pg_noreturn extern void pg_re_throw(void);
      | ^~~~~~~~~~~

Greetings,

Andres Freund



Re: Make copyObject work in C++

От
Peter Eisentraut
Дата:
On 20.01.26 17:38, Andres Freund wrote:
>> I have split your first patch further.  For a start, I left out the
>> PG_MODULE_MAGIC*-related changes and disabled the module under MSVC. This
>> has been committed.  I plan to let the buildfarm run with it for a day or
>> two and then add in the basic MSVC support.
> Seems like billbug doesn't like this:
> 
> https://buildfarm.postgresql.org/cgi-bin/show_log.pl? 
> nm=billbug&dt=2026-01-20%2016%3A00%3A02
> 
> gmake[1]: Entering directory
'/home/marcel/build-farm-20/buildroot/HEAD/pgsql.build/src/test/modules/test_cplusplusext'
> g++ -Wall -Wpointer-arith -Wendif-labels -Wmissing-format-attribute -Wimplicit-fallthrough=3 -Wcast-function-type
-Wshadow=compatible-local-Wformat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard -g -O2 -fPIC
-fvisibility=hidden-fvisibility-inlines-hidden -I. -I. -I../../../../src/include -D_POSIX_C_SOURCE=200112L
-D__EXTENSIONS__-D_POSIX_PTHREAD_SEMANTICS  -I/usr/openssl/3/include -I/usr/include/libxml2     -c -o
test_cplusplusext.otest_cplusplusext.cpp
 
> In file included from ../../../../src/include/postgres.h:48,
>                   from test_cplusplusext.cpp:18:
> ../../../../src/include/c.h:158:21: error: '_Noreturn' does not name a type; did you mean 'pg_noreturn'?
>    158 | #define pg_noreturn _Noreturn
>        |                     ^~~~~~~~~
> ../../../../src/include/c.h:918:1: note: in expansion of macro 'pg_noreturn'
>    918 | pg_noreturn extern void ExceptionalCondition(const char *conditionName,
>        | ^~~~~~~~~~~

It's getting confused by _Noreturn, which is defined thus:

#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
#define pg_noreturn _Noreturn

But apparently on these Solaris-related platforms, g++ defines 
__STDC_VERSION__ even in C++ mode.  (Confirmed in local testing.) 
Apparently, this is even allowed by the C++ standard.

So the smallest fix is probably to gate this more like this:

#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) && 
!defined(__cplusplus)
#define pg_noreturn _Noreturn

(Eventually, we could add support for C++ attributes, but one step at a 
time.)




Re: Make copyObject work in C++

От
Andres Freund
Дата:
Hi,

On 2026-01-20 20:07:15 +0100, Peter Eisentraut wrote:
> On 20.01.26 17:38, Andres Freund wrote:
> > > I have split your first patch further.  For a start, I left out the
> > > PG_MODULE_MAGIC*-related changes and disabled the module under MSVC. This
> > > has been committed.  I plan to let the buildfarm run with it for a day or
> > > two and then add in the basic MSVC support.
> > Seems like billbug doesn't like this:
> > 
> > https://buildfarm.postgresql.org/cgi-bin/show_log.pl?
> > nm=billbug&dt=2026-01-20%2016%3A00%3A02
> > 
> > gmake[1]: Entering directory
'/home/marcel/build-farm-20/buildroot/HEAD/pgsql.build/src/test/modules/test_cplusplusext'
> > g++ -Wall -Wpointer-arith -Wendif-labels -Wmissing-format-attribute -Wimplicit-fallthrough=3 -Wcast-function-type
-Wshadow=compatible-local-Wformat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard -g -O2 -fPIC
-fvisibility=hidden-fvisibility-inlines-hidden -I. -I. -I../../../../src/include -D_POSIX_C_SOURCE=200112L
-D__EXTENSIONS__-D_POSIX_PTHREAD_SEMANTICS  -I/usr/openssl/3/include -I/usr/include/libxml2     -c -o
test_cplusplusext.otest_cplusplusext.cpp
 
> > In file included from ../../../../src/include/postgres.h:48,
> >                   from test_cplusplusext.cpp:18:
> > ../../../../src/include/c.h:158:21: error: '_Noreturn' does not name a type; did you mean 'pg_noreturn'?
> >    158 | #define pg_noreturn _Noreturn
> >        |                     ^~~~~~~~~
> > ../../../../src/include/c.h:918:1: note: in expansion of macro 'pg_noreturn'
> >    918 | pg_noreturn extern void ExceptionalCondition(const char *conditionName,
> >        | ^~~~~~~~~~~
> 
> It's getting confused by _Noreturn, which is defined thus:
> 
> #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
> #define pg_noreturn _Noreturn
> 
> But apparently on these Solaris-related platforms, g++ defines
> __STDC_VERSION__ even in C++ mode.  (Confirmed in local testing.)
> Apparently, this is even allowed by the C++ standard.

Heh. Pretty odd to do that only on some platforms...


> So the smallest fix is probably to gate this more like this:
> 
> #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) &&
> !defined(__cplusplus)
> #define pg_noreturn _Noreturn
> 
> (Eventually, we could add support for C++ attributes, but one step at a
> time.)

Makes sense to me.

Greetings,

Andres Freund



Re: Make copyObject work in C++

От
"Jelte Fennema-Nio"
Дата:
On Tue Jan 20, 2026 at 5:28 PM CET, Peter Eisentraut wrote:
> I have split your first patch further.  For a start, I left out the
> PG_MODULE_MAGIC*-related changes and disabled the module under MSVC.
> This has been committed.  I plan to let the buildfarm run with it for a
> day or two and then add in the basic MSVC support.

To hopefully make your life a bit easier. Here's a rebased version that
enables the MSVC support again, with an updated commit message.

Вложения

Re: Make copyObject work in C++

От
Andres Freund
Дата:
Hi,

On 2026-01-25 13:42:51 +0100, Jelte Fennema-Nio wrote:
> This reverts to using positional initializers in PG_MODULE_MAGIC_DATA so
> that its possible to write C++ extensions in standard C++11. Sadly that
> means that using designated initializers in C++20 is still not allowed
> in PG_MODULE_MAGIC_EXT because mixing designated an positional
> initializers is a C only feature. This restriction for C++ extensions is
> now documented and tested.

I'm pretty sceptical this is the right direction. We were going for designated
initializers for a reason, namely that we expect more arguments to be added
over time and perhaps eventually also to remove some. And this will just lead
to that being harder because we have to worry about C++ extensions.


But I'm also confused as to why it's needed - there's nomixing of designated
and non-designated initializers that I can see? If you use
PG_MODULE_MAGIC_EXT(.name = "whatnot"), it evaluates down to

extern __attribute__((visibility("default"))) const Pg_magic_struct *Pg_magic_func(void); const Pg_magic_struct *
Pg_magic_func(void){ static const Pg_magic_struct Pg_magic_data = { .len = sizeof(Pg_magic_struct), .abi_fields = {
190000/ 100, 100, 32, 64, true, "PostgreSQL", }, .name="whatnot"}; return &Pg_magic_data; } extern int
no_such_variable;

And indeed, contra to what you reported upthread, I can't get clang to report
a warning about that.  I do obviously see warnings about the wrong order if I
pass the arguments in the wrong order, but that's a lot less problematic. And
omitted args don't trigger warnings, as you noted.


Greetings,

Andres Freund



Re: Make copyObject work in C++

От
"Jelte Fennema-Nio"
Дата:
On Sun Jan 25, 2026 at 5:50 PM CET, Andres Freund wrote:
> I'm pretty sceptical this is the right direction.

The only other option I can think of is not supporting C++ extension on
MSVC unless they are compiled with C++20 (or later). I don't
particularly care about Windows C++ extensions myself, so I personally
would be fine with that choice. It seems a bit harsh, though.

> We were going for designated
> initializers for a reason, namely that we expect more arguments to be added
> over time and perhaps eventually also to remove some. And this will just lead
> to that being harder because we have to worry about C++ extensions.

Adding new arguments (aka fields) should cause no problems. Assuming
we'd add them at the end of the Pg_magic_struct definition. Removing
ones seems like even for C you'd need different PG_MODULE_MAGIC_EXT
invocations depending on PG_VERSION_NUM. I don't see how using
positional args would make that harder.

> But I'm also confused as to why it's needed - there's nomixing of designated
> and non-designated initializers that I can see? If you use
> PG_MODULE_MAGIC_EXT(.name = "whatnot"), it evaluates down to
>
> extern __attribute__((visibility("default"))) const Pg_magic_struct *Pg_magic_func(void); const Pg_magic_struct *
Pg_magic_func(void){ static const Pg_magic_struct Pg_magic_data = { .len = sizeof(Pg_magic_struct), .abi_fields = {
190000/ 100, 100, 32, 64, true, "PostgreSQL", }, .name="whatnot"}; return &Pg_magic_data; } extern int
no_such_variable;
>
> And indeed, contra to what you reported upthread, I can't get clang to report
> a warning about that.  I do obviously see warnings about the wrong order if I
> pass the arguments in the wrong order, but that's a lot less problematic. And
> omitted args don't trigger warnings, as you noted.

It sounds like I wasn't clear enough what the problem was. The main
problem currently is that MSVC C++ fails to compile a cpp file
containing PG_MODULE_MAGIC (or PG_MODULE_MAGIC_EXT) unless you use /std:c++20.

Afaict it would have been possible to do so before 9324c8c580 (aka
anything before PG18), but since that commit you need /std:c++20. The
fact that we haven't heard anyone complain so far, might be an indication
that not many people (or maybe anyone) is using C++ extensions on Windows.

The only way to make PG_MODULE_MAGIC work on MSVC pre-C++20 is to
partially revert 9324c8c580, and use positional arguments in the
definition of PG_MODULE_MAGIC_DATA again. Like I've done in v7-0001.

For C extensions v7-0001 has no downsides. However, after applying
v7-0001, C++ extensions that use PG_MODULE_MAGIC_EXT with designated
parameters will get the following warning on at least clang 18 on my
machine:

meson setup --prefix ~/.pgenv/pgsql-master --debug build --reconfigure -Dc_args='-fno-omit-frame-pointer'
-Dcassert=true
meson test -C build --suite setup --suite test_cplusplusext

[2202/2268] Compiling C++ object src/test/modules/test_cplusplusext/test_cplusplusext.so.p/test_cplusplusext.cpp.o
../src/test/modules/test_cplusplusext/test_cplusplusext.cpp:23:21: warning: mixture of designated and non-designated
initializersin the same initializer list is a C99 extension [-Wc99-designator] 
   23 | PG_MODULE_MAGIC_EXT(.name="test_cplusplusext",.version= "1.2");
      |                     ^~~~~~~~~~~~~~~~~~~~~~~~~
../src/include/fmgr.h:548:24: note: expanded from macro 'PG_MODULE_MAGIC_EXT'
  548 |                 PG_MODULE_MAGIC_DATA(__VA_ARGS__); \
      |                                      ^~~~~~~~~~~
../src/include/fmgr.h:509:2: note: expanded from macro 'PG_MODULE_MAGIC_DATA'
  509 |         __VA_ARGS__ \
      |         ^~~~~~~~~~~
../src/test/modules/test_cplusplusext/test_cplusplusext.cpp:23:1: note: first non-designated initializer is here
   23 | PG_MODULE_MAGIC_EXT(.name="test_cplusplusext",.version= "1.2");
      | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../src/include/fmgr.h:548:3: note: expanded from macro 'PG_MODULE_MAGIC_EXT'
  548 |                 PG_MODULE_MAGIC_DATA(__VA_ARGS__); \
      |                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../src/include/fmgr.h:507:2: note: expanded from macro 'PG_MODULE_MAGIC_DATA'
  507 |         sizeof(Pg_magic_struct), \
      |         ^~~~~~~~~~~~~~~~~~~~~~~

Note that you need to use meson test, not meson install, otherwise
test_cplusplusext.cpp won't get compiled.

So to be clear, yes right now there's no mixing of designated and
non-designated initializers. But after applying v7-0001 there would be
when you use something like this:
PG_MODULE_MAGIC_EXT(.name="test_cplusplusext",.version= "1.2");


And while the C standard allows mixing designated and non-designated
initializerss, the C++ standard (even C++20) does not.



Re: Make copyObject work in C++

От
Andres Freund
Дата:
Hi,

On 2026-01-25 18:52:37 +0100, Jelte Fennema-Nio wrote:
> On Sun Jan 25, 2026 at 5:50 PM CET, Andres Freund wrote:
> > We were going for designated
> > initializers for a reason, namely that we expect more arguments to be added
> > over time and perhaps eventually also to remove some. And this will just lead
> > to that being harder because we have to worry about C++ extensions.
> 
> Adding new arguments (aka fields) should cause no problems. Assuming
> we'd add them at the end of the Pg_magic_struct definition. Removing
> ones seems like even for C you'd need different PG_MODULE_MAGIC_EXT
> invocations depending on PG_VERSION_NUM. I don't see how using
> positional args would make that harder.

Named args make that easier in two ways: First, only extensions using the
to-be-removed option will fail. Second, removal of options reliably generates
errors, rather than bogusly use one field for another, just because the types
are compatible.

Greetings,

Andres Freund



Re: Make copyObject work in C++

От
Peter Eisentraut
Дата:
On 25.01.26 18:52, Jelte Fennema-Nio wrote:
> On Sun Jan 25, 2026 at 5:50 PM CET, Andres Freund wrote:
>> I'm pretty sceptical this is the right direction. 
> 
> The only other option I can think of is not supporting C++ extension on
> MSVC unless they are compiled with C++20 (or later). I don't
> particularly care about Windows C++ extensions myself, so I personally
> would be fine with that choice. It seems a bit harsh, though.

Maybe it would be enough to only support PG_MODULE_MAGIC (without 
arguments) in C++ for now.

That would still require removing the named initializers inside 
PG_MODULE_MAGIC_DATA(), but that's only an internal change, and it would 
not affect C-language users of PG_MODULE_MAGIC_EXT, and we wouldn't lock 
ourselves into a particular style in C++.

Then, maybe in a couple of years, when C++20 is more widely available, 
we could enable PG_MODULE_MAGIC_EXT for C++, or design an alternative 
construct for C++.




Re: Make copyObject work in C++

От
Jelte Fennema-Nio
Дата:
On Mon, 26 Jan 2026 at 11:29, Peter Eisentraut <peter@eisentraut.org> wrote:
> Maybe it would be enough to only support PG_MODULE_MAGIC (without
> arguments) in C++ for now.

You mean by explicitly ifdefing out PG_MODULE_MAGIC_EXT to make it
unusable in C++? Or just not adding the additional documentation that
I added in my patch?
I'm currently using PG_MODULE_MAGIC_EXT in the C++ extension that I
maintain, and I'd prefer to continue doing so. Especially because it
(currently) doesn't have to work on MSVC for my purposes.



Re: Make copyObject work in C++

От
Jelte Fennema-Nio
Дата:
On Sun, 25 Jan 2026 at 21:06, Andres Freund <andres@anarazel.de> wrote:
> Named args make that easier in two ways: First, only extensions using the
> to-be-removed option will fail. Second, removal of options reliably generates
> errors, rather than bogusly use one field for another, just because the types
> are compatible.

Fair enough, for removals it has some benefits. Still seems like a
relatively small win for something I don't expect us to be doing
anytime soon (name and version I expect to stay around forever).



Re: Make copyObject work in C++

От
Bryan Green
Дата:
On 1/25/2026 6:42 AM, Jelte Fennema-Nio wrote:
> On Tue Jan 20, 2026 at 5:28 PM CET, Peter Eisentraut wrote:
>> I have split your first patch further.  For a start, I left out the
>> PG_MODULE_MAGIC*-related changes and disabled the module under MSVC.
>> This has been committed.  I plan to let the buildfarm run with it for
>> a day or two and then add in the basic MSVC support.
> 
> To hopefully make your life a bit easier. Here's a rebased version that
> enables the MSVC support again, with an updated commit message.
> 
This causes the build to break on VS 2022.  Versions prior do not have
support for __typeof_unqual__.  This would have led to
HAVE_TYPEOF_UNQUAL being not defined on the buildfarm causing the
fallback to copyObjectImpl() for VS 2019.

When you build on VS 2022 you will get an error:
../src/backend/commands/event_trigger.c(1901): error C2100: you cannot
dereference an operand of type 'void'

VS 2022 (MSVC) does not handle the void * dereference the way gcc/clang
does (thanks to GNU extensions, I believe).  It exposes
__typeof_unqual__ even it C11, but enforces strict C semantics on the
void * dereference.  To work on this platform the call
copyObject(lfirst(cell)) would need to have a cast to the correct
concrete type: copyObject((Node *)lfirst(cell)).

I was about to update to VS 2026, but now I think I should have an
instance of VS from 2019, 2022, and 2026.

-- 
Bryan Green
EDB: https://www.enterprisedb.com