pg_attribute_noreturn(), MSVC, C11

Started by Andres Freundabout 1 year ago17 messages
#1Andres Freund
andres@anarazel.de

Hi,

I just encountered another
warning C4715: 'XYZ: not all control paths return a value

with msvc in CI in a case where it should be trivial for the compiler to
recognize that the function return isn't reachable.

Which made me check if these days msvc has something like gcc's
__attribute__((noreturn)).

And it turns out that yes! The _Noreturn attribute has been added to C11 and
msvc supports C11:
https://learn.microsoft.com/en-us/cpp/c-language/noreturn?view=msvc-170

Besides the _Noreturn keyword the standard also added a stdnoreturn.h which
provides the 'noreturn' macro.

I first thought we could just implement pg_attribute_noreturn() using
_Noreturn if available. However, our current pg_attribute_noreturn() is in the
wrong place for that to work :(. _Noreturn is to be placed with the return
type, whereas function attributes with the __attribute__(()) syntax are after
the parameter list.

So we probably can't transparently switch between these.

C11 has been out a while, so I'm somewhat inclined to adopt _Noreturn/noreturn
in a conditional way. Older compilers would still work, just not understand
noreturn.

One wrinkle: _Noreturn/noreturn have been deprecated in C23, because that
adopted C++11's attribute syntax (i.e. [[noreturn]]). But that's at least in
the same place as _Noreturn/return.

We can't remove [[noreturn]] with preprocessor magic, so it's not really
viable to use that for, uhm, quite a while.

If we were to use _Noreturn, I think it could just be something like:

I think it should suffice to do something like

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

(or alternatively include stdreturn if __STDC_VERSION__ indicates support and
define a bare 'noreturn' if not)

For msvc that mean we'd need to add /std:c11 (or /std:c17) to the compiler
flags, as it otherwise it results in a weird mix of c89 an c99). But that
might be a good idea anyway. With one minor change [1]The msvc implementation of VA_ARGS_NARGS only works with the traditional preprocessor, but C11 support enables the new one. But we can detect that with something like (!defined(_MSVC_TRADITIONAL) || _MSVC_TRADITIONAL) the tests pass with
msvc when using /std:c17.

Before realizing that we'd have to change our existing annotations and that
there's no way to use both old and new syntax, depending on compiler support,
I was thinking this would be an obvious thing to do. I'm still leaning on it
being worth it, but not as clearly as before.

For an example of _Noreturn being used: https://godbolt.org/z/j15d35dao

Greetings,

Andres Freund

[1]: The msvc implementation of VA_ARGS_NARGS only works with the traditional preprocessor, but C11 support enables the new one. But we can detect that with something like (!defined(_MSVC_TRADITIONAL) || _MSVC_TRADITIONAL)
preprocessor, but C11 support enables the new one. But we can detect that
with something like
(!defined(_MSVC_TRADITIONAL) || _MSVC_TRADITIONAL)

See https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=msvc-170
and https://learn.microsoft.com/en-us/cpp/build/reference/std-specify-language-standard-version?view=msvc-170

Without adapting the definition of VA_ARGS_NARGS compilation fails as it
results in the macro resulting in VA_ARGS_NARGS_(prefix, 63, 62, ...) in
the using code...

#2Andres Freund
andres@anarazel.de
In reply to: Andres Freund (#1)
Re: pg_attribute_noreturn(), MSVC, C11

Hi,

On 2024-12-13 14:10:13 -0500, Andres Freund wrote:

I just encountered another
warning C4715: 'XYZ: not all control paths return a value

with msvc in CI in a case where it should be trivial for the compiler to
recognize that the function return isn't reachable.

Which made me check if these days msvc has something like gcc's
__attribute__((noreturn)).

And it turns out that yes! The _Noreturn attribute has been added to C11 and
msvc supports C11:
https://learn.microsoft.com/en-us/cpp/c-language/noreturn?view=msvc-170

Besides the _Noreturn keyword the standard also added a stdnoreturn.h which
provides the 'noreturn' macro.

I first thought we could just implement pg_attribute_noreturn() using
_Noreturn if available. However, our current pg_attribute_noreturn() is in the
wrong place for that to work :(. _Noreturn is to be placed with the return
type, whereas function attributes with the __attribute__(()) syntax are after
the parameter list.

The point about __attribute__(()) being after the parameter list is wrong, I
confused myself there. But that doesn't change that much, the common current
placement doesn't work for _Noreturn.

C11 has been out a while, so I'm somewhat inclined to adopt _Noreturn/noreturn
in a conditional way. Older compilers would still work, just not understand
noreturn.

One wrinkle: _Noreturn/noreturn have been deprecated in C23, because that
adopted C++11's attribute syntax (i.e. [[noreturn]]). But that's at least in
the same place as _Noreturn/return.

We can't remove [[noreturn]] with preprocessor magic, so it's not really
viable to use that for, uhm, quite a while.

If we were to use _Noreturn, I think it could just be something like:

I think it should suffice to do something like

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

(or alternatively include stdreturn if __STDC_VERSION__ indicates support and
define a bare 'noreturn' if not)

Another wrinkle: While __attribute__((noreturn)) works for function pointers
(or function pointer typedefs) _Noreturn doesn't. Gah. We only use it that
way in two places, but still :(

Greetings,

Andres Freund

#3Peter Eisentraut
peter@eisentraut.org
In reply to: Andres Freund (#1)
Re: pg_attribute_noreturn(), MSVC, C11

On 13.12.24 20:10, Andres Freund wrote:

C11 has been out a while, so I'm somewhat inclined to adopt _Noreturn/noreturn
in a conditional way. Older compilers would still work, just not understand
noreturn.

One wrinkle: _Noreturn/noreturn have been deprecated in C23, because that
adopted C++11's attribute syntax (i.e. [[noreturn]]). But that's at least in
the same place as _Noreturn/return.

We can't remove [[noreturn]] with preprocessor magic, so it's not really
viable to use that for, uhm, quite a while.

If we were to use _Noreturn, I think it could just be something like:

I think it should suffice to do something like

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

This looks reasonable to me. We also have pg_nodiscard. (That's got a
slightly different history in the C standard, but I mean it's also
"pg_someattribute".)

(or alternatively include stdreturn if __STDC_VERSION__ indicates support and
define a bare 'noreturn' if not)

For msvc that mean we'd need to add /std:c11 (or /std:c17) to the compiler
flags, as it otherwise it results in a weird mix of c89 an c99). But that
might be a good idea anyway. With one minor change [1] the tests pass with
msvc when using /std:c17.

According to my notes, C11 requires MSVC 2019, and we currently require
2015, so this will require a bit of logic.

#4Peter Eisentraut
peter@eisentraut.org
In reply to: Andres Freund (#2)
Re: pg_attribute_noreturn(), MSVC, C11

On 13.12.24 20:54, Andres Freund wrote:

Another wrinkle: While __attribute__((noreturn)) works for function pointers
(or function pointer typedefs) _Noreturn doesn't. Gah. We only use it that
way in two places, but still :(

Yeah, I wrote an experimental patch for noreturn support some years ago,
and that was also my result back then. (I assume you have a current
patch, otherwise I can dig out that one.) I had also written down that
there were some problems with Perl and Tcl headers, FWIW. Did you have
any problems with those?

I think we can take a small loss here and move with the standard.
Unless you can think of a way to define
pg_noreturn_but_for_function_pointers in a systematic way.

#5Andres Freund
andres@anarazel.de
In reply to: Peter Eisentraut (#3)
Re: pg_attribute_noreturn(), MSVC, C11

Hi,

On 2024-12-14 18:15:13 +0100, Peter Eisentraut wrote:

On 13.12.24 20:10, Andres Freund wrote:

(or alternatively include stdreturn if __STDC_VERSION__ indicates support and
define a bare 'noreturn' if not)

For msvc that mean we'd need to add /std:c11 (or /std:c17) to the compiler
flags, as it otherwise it results in a weird mix of c89 an c99). But that
might be a good idea anyway. With one minor change [1] the tests pass with
msvc when using /std:c17.

According to my notes, C11 requires MSVC 2019, and we currently require
2015, so this will require a bit of logic.

Yea. Not hard though:

@@ -298,6 +298,7 @@ elif host_system == 'windows'
   if cc.get_id() == 'msvc'
     ldflags += '/INCREMENTAL:NO'
     ldflags += '/STACK:@0@'.format(cdata.get('WIN32_STACK_RLIMIT'))
+    cflags += cc.first_supported_argument('/std:c17', '/std:c11')
     # ldflags += '/nxcompat' # generated by msbuild, should have it for ninja?
   else
     ldflags += '-Wl,--stack,@0@'.format(cdata.get('WIN32_STACK_RLIMIT'))

It's not quite the way meson wants you to do it (declare it in
default_options), but with our minimum meson version that's just a single
option, not a list...

Greetings,

Andres Freund

#6Andres Freund
andres@anarazel.de
In reply to: Peter Eisentraut (#4)
Re: pg_attribute_noreturn(), MSVC, C11

Hi,

On 2024-12-14 18:18:35 +0100, Peter Eisentraut wrote:

On 13.12.24 20:54, Andres Freund wrote:

Another wrinkle: While __attribute__((noreturn)) works for function pointers
(or function pointer typedefs) _Noreturn doesn't. Gah. We only use it that
way in two places, but still :(

Yeah, I wrote an experimental patch for noreturn support some years ago, and
that was also my result back then.

It's quite annoying...

(I assume you have a current patch, otherwise I can dig out that one.)

Yea, I do. Not pretty, but ...

I guess I'll try to pretty it up a bit and post it then.

I had also written down that there were some problems with Perl and Tcl
headers, FWIW. Did you have any problems with those?

Not so far.

I think we can take a small loss here and move with the standard. Unless you
can think of a way to define pg_noreturn_but_for_function_pointers in a
systematic way.

The small loss unfortunately isn't that small, because clang treats
__attribute__((noreturn)) to be part of the function signature, but not
_Noreturn. Which means you can't just put __attribute__((noreturn)) to the
function pointer's signature, because it'll complain about incompatible
function pointers:

../../../../../home/andres/src/postgresql/src/backend/backup/basebackup_incremental.c:179:20: error: incompatible function pointer types assigning to 'json_manifest_error_callback' (aka 'void (*)(struct JsonManifestParseContext *, const char *, ...) __attribute__((noreturn))') from 'void (JsonManifestParseContext *, const char *, ...)' (aka 'void (struct JsonManifestParseContext *, const char *, ...)') [-Wincompatible-function-pointer-types]
179 | context->error_cb = manifest_report_error;

A workaround would be to have pg_nodiscard to just specify both
__attribute__((noreturn)) and _Nodiscard, and
pg_noreturn_but_for_function_pointers just specify __attribute__((noreturn)).
But at that point it's not obvious why we'd use _Nodiscard at all.

I wonder if we should switch to pg_nodiscard in the position that _Nodiscard
would be used and implement it as __attribute__((noreturn)) on gnu like
compilers and __declspec(noreturn) on msvc.

Kinda curious that we have pg_nodiscard, but didn't use __declspec(nodiscard).

Greetings,

Andres Freund

#7Peter Eisentraut
peter@eisentraut.org
In reply to: Peter Eisentraut (#4)
4 attachment(s)
Re: pg_attribute_noreturn(), MSVC, C11

On 14.12.24 18:18, Peter Eisentraut wrote:

On 13.12.24 20:54, Andres Freund wrote:

Another wrinkle: While __attribute__((noreturn)) works for function
pointers
(or function pointer typedefs) _Noreturn doesn't. Gah.  We only use it
that
way in two places, but still :(

Yeah, I wrote an experimental patch for noreturn support some years ago,
and that was also my result back then.  (I assume you have a current
patch, otherwise I can dig out that one.)  I had also written down that
there were some problems with Perl and Tcl headers, FWIW.  Did you have
any problems with those?

I think we can take a small loss here and move with the standard. Unless
you can think of a way to define pg_noreturn_but_for_function_pointers
in a systematic way.

I have a patch proposal here. I discovered a few more complications
that need to be paid attention to.

First, we can't use bare "noreturn". There are third-party header files
(such as Tcl) that use __attribute__((noreturn)), and that will get
confused. That's the same reason we don't use bare restrict but
pg_restrict.

I suggest we define pg_noreturn as

1. If C11 is supported, then _Noreturn, else
2. If GCC-compatible, then __attribute__((noreturn)), else
3. If MSVC, then __declspec((noreturn))

When PostgreSQL starts requiring C11, then the latter two options can be
dropped.

Note that this also fixes a possible conflict where some third-party
code includes <stdnoreturn.h> and then includes our c.h. I don't think
this has been reported, but it's surely bound to happen.

For the function pointers, I don't think there is a good solution. The
current behavior is evidently inconsistent and incompatible and not well
documented, and I don't see how it's going to get better in these
aspects any time soon. I think the way forward in the mid-term is to
avoid designing more interfaces like that and provide wrapper functions
like json_manifest_parse_failure() where you can enforce the return
behavior in the normal way.

Finally, while I was looking at this, I figured we could also add
pg_nodiscard support to non-GCC compilers that support C23 (probably
none right now, but eventually), by defining pg_nodiscard as
[[nodiscard]]. But that revealed that clang requires these attributes
to appear before the extern/static keywords, which is not how it's
currently written. So I changed that, too, and also wrote the
pg_noreturn patch in the same style. And then I also added a definition
of pg_noreturn as [[noreturn]] (actually, [[__noreturn__]], for the
reasons given earlier), for consistency, and also as a hedge in case
some compiler drops C11 support in a few decades. (I tried to
language-lawyer my way through this, and I don't know that clang is
correct here, but this issue is widely reported out there and everyone
agrees that the fix is to just swap the things around. At least we can
enforce some stylistic consistency that way.)

Attachments:

0001-pg_noreturn-to-replace-pg_attribute_noreturn.patchtext/plain; charset=UTF-8; name=0001-pg_noreturn-to-replace-pg_attribute_noreturn.patchDownload
From 1c85012cbb00cb9dc7216d98a6ffd056b2f3c3c7 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Sat, 28 Dec 2024 11:00:24 +0100
Subject: [PATCH 1/4] pg_noreturn to replace pg_attribute_noreturn()

We want to support a "noreturn" decoration on more compilers besides
just GCC-compatible ones, but for that we need to move the decoration
in front of the function declaration instead of either behind it or
wherever, which is the current style afforded by GCC-style attributes.
Also rename the macro to "pg_noreturn" to be similar to the C11
standard "noreturn", and also because it's not necessarily an
attribute anymore.

pg_noreturn is now supported on all compilers that support C11 (using
_Noreturn), as well as GCC-compatible ones (using __attribute__, as
before), as well as MSVC (using __declspec).  (When PostgreSQL
requires C11, the latter two variants can be dropped.)

Now, all supported compilers effectively support pg_noreturn, so the
extra code for !HAVE_PG_ATTRIBUTE_NORETURN can be dropped.

This also fixes a possible problem if third-party code includes
stdnoreturn.h, because then the current definition of

    #define pg_attribute_noreturn() __attribute__((noreturn))

would cause an error.

Note that the C standard does not support a noreturn attribute on
function pointer types.  So we have to drop these here.  There are
only two instances at this time, so it's not a big loss.
---
 contrib/dblink/dblink.c                       |  6 ++--
 contrib/pgcrypto/px.h                         |  2 +-
 src/backend/access/transam/xlogrecovery.c     |  3 +-
 src/backend/backup/basebackup_incremental.c   |  6 ++--
 src/backend/postmaster/autovacuum.c           |  2 +-
 src/backend/postmaster/launch_backend.c       |  2 +-
 src/backend/postmaster/postmaster.c           |  2 +-
 src/backend/replication/logical/tablesync.c   |  3 +-
 src/backend/replication/walsender.c           |  2 +-
 src/backend/utils/adt/ri_triggers.c           |  8 ++---
 src/backend/utils/fmgr/dfmgr.c                |  4 +--
 src/backend/utils/hash/dynahash.c             |  2 +-
 src/backend/utils/mmgr/slab.c                 |  2 +-
 src/bin/pg_combinebackup/load_manifest.c      |  6 ++--
 src/bin/pg_dump/pg_backup_utils.h             |  2 +-
 src/bin/pg_upgrade/pg_upgrade.h               |  2 +-
 src/bin/pg_verifybackup/pg_verifybackup.c     |  6 ++--
 src/bin/pg_verifybackup/pg_verifybackup.h     |  4 +--
 src/bin/pgbench/pgbench.h                     | 12 ++++----
 src/include/bootstrap/bootstrap.h             |  4 +--
 src/include/c.h                               | 30 ++++++++++++-------
 src/include/commands/defrem.h                 |  2 +-
 src/include/common/parse_manifest.h           |  3 +-
 src/include/mb/pg_wchar.h                     |  6 ++--
 src/include/parser/parse_relation.h           |  6 ++--
 src/include/parser/scanner.h                  |  2 +-
 src/include/postmaster/autovacuum.h           |  4 +--
 src/include/postmaster/bgworker_internals.h   |  2 +-
 src/include/postmaster/bgwriter.h             |  4 +--
 src/include/postmaster/pgarch.h               |  2 +-
 src/include/postmaster/postmaster.h           |  4 +--
 src/include/postmaster/startup.h              |  2 +-
 src/include/postmaster/syslogger.h            |  2 +-
 src/include/postmaster/walsummarizer.h        |  2 +-
 src/include/postmaster/walwriter.h            |  2 +-
 src/include/replication/slotsync.h            |  2 +-
 src/include/replication/walreceiver.h         |  2 +-
 src/include/replication/walsender_private.h   |  2 +-
 src/include/storage/ipc.h                     |  2 +-
 src/include/storage/lock.h                    |  2 +-
 src/include/tcop/backend_startup.h            |  2 +-
 src/include/tcop/tcopprot.h                   | 12 ++++----
 src/include/utils/elog.h                      | 13 ++------
 src/include/utils/float.h                     |  6 ++--
 src/include/utils/help_config.h               |  2 +-
 src/include/utils/memutils_internal.h         |  4 +--
 src/interfaces/ecpg/preproc/preproc_extern.h  |  2 +-
 src/pl/plpgsql/src/plpgsql.h                  |  2 +-
 .../modules/libpq_pipeline/libpq_pipeline.c   |  5 ++--
 src/test/modules/test_shm_mq/test_shm_mq.h    |  2 +-
 src/test/modules/worker_spi/worker_spi.c      |  2 +-
 src/timezone/zic.c                            |  4 +--
 src/tools/pg_bsd_indent/err.h                 |  8 ++---
 53 files changed, 111 insertions(+), 116 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index c1c82eb4dd8..c4d5bc79986 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -160,8 +160,7 @@ xpstrdup(const char *in)
 	return pstrdup(in);
 }
 
-static void
-pg_attribute_noreturn()
+pg_noreturn static void
 dblink_res_internalerror(PGconn *conn, PGresult *res, const char *p2)
 {
 	char	   *msg = pchomp(PQerrorMessage(conn));
@@ -170,8 +169,7 @@ dblink_res_internalerror(PGconn *conn, PGresult *res, const char *p2)
 	elog(ERROR, "%s: %s", p2, msg);
 }
 
-static void
-pg_attribute_noreturn()
+pg_noreturn static void
 dblink_conn_not_avail(const char *conname)
 {
 	if (conname)
diff --git a/contrib/pgcrypto/px.h b/contrib/pgcrypto/px.h
index 471bb4ec727..45332fcddb6 100644
--- a/contrib/pgcrypto/px.h
+++ b/contrib/pgcrypto/px.h
@@ -173,7 +173,7 @@ int			px_find_hmac(const char *name, PX_HMAC **res);
 int			px_find_cipher(const char *name, PX_Cipher **res);
 int			px_find_combo(const char *name, PX_Combo **res);
 
-void		px_THROW_ERROR(int err) pg_attribute_noreturn();
+pg_noreturn void px_THROW_ERROR(int err);
 const char *px_strerror(int err);
 
 const char *px_resolve_alias(const PX_Alias *list, const char *name);
diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index c6994b78282..d94b73b6a25 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -4763,8 +4763,7 @@ check_primary_slot_name(char **newval, void **extra, GucSource source)
  * that we have odd behaviors such as unexpected GUC ordering dependencies.
  */
 
-static void
-pg_attribute_noreturn()
+pg_noreturn static void
 error_multiple_recovery_targets(void)
 {
 	ereport(ERROR,
diff --git a/src/backend/backup/basebackup_incremental.c b/src/backend/backup/basebackup_incremental.c
index 87cc1b96cbc..18c21dbea2a 100644
--- a/src/backend/backup/basebackup_incremental.c
+++ b/src/backend/backup/basebackup_incremental.c
@@ -139,9 +139,9 @@ static void manifest_process_wal_range(JsonManifestParseContext *context,
 									   TimeLineID tli,
 									   XLogRecPtr start_lsn,
 									   XLogRecPtr end_lsn);
-static void manifest_report_error(JsonManifestParseContext *context,
-								  const char *fmt,...)
-			pg_attribute_printf(2, 3) pg_attribute_noreturn();
+pg_noreturn static void manifest_report_error(JsonManifestParseContext *context,
+											  const char *fmt,...)
+			pg_attribute_printf(2, 3);
 static int	compare_block_numbers(const void *a, const void *b);
 
 /*
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 8078eeef62e..54b662ffd13 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -315,7 +315,7 @@ int			AutovacuumLauncherPid = 0;
 
 static Oid	do_start_worker(void);
 static void HandleAutoVacLauncherInterrupts(void);
-static void AutoVacLauncherShutdown(void) pg_attribute_noreturn();
+pg_noreturn static void AutoVacLauncherShutdown(void);
 static void launcher_determine_sleep(bool canlaunch, bool recursing,
 									 struct timeval *nap);
 static void launch_worker(TimestampTz now);
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 1f2d829ec5a..6059f56f2a2 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -171,7 +171,7 @@ static pid_t internal_forkexec(const char *child_kind, int child_slot,
 typedef struct
 {
 	const char *name;
-	void		(*main_fn) (char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+	void		(*main_fn) (char *startup_data, size_t startup_data_len);
 	bool		shmem_attach;
 } child_process_kind;
 
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 6f849ffbcb5..ae233d76649 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -412,7 +412,7 @@ static void LogChildExit(int lev, const char *procname,
 						 int pid, int exitstatus);
 static void PostmasterStateMachine(void);
 
-static void ExitPostmaster(int status) pg_attribute_noreturn();
+pg_noreturn static void ExitPostmaster(int status);
 static int	ServerLoop(void);
 static int	BackendStartup(ClientSocket *client_sock);
 static void report_fork_failure_to_client(ClientSocket *client_sock, int errnum);
diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c
index 7c8a0e9cfeb..40393f8d364 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -139,8 +139,7 @@ static StringInfo copybuf = NULL;
 /*
  * Exit routine for synchronization worker.
  */
-static void
-pg_attribute_noreturn()
+pg_noreturn static void
 finish_sync_worker(void)
 {
 	/*
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index dc25dd6af91..aca4473af69 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -237,7 +237,7 @@ typedef void (*WalSndSendDataCallback) (void);
 static void WalSndLoop(WalSndSendDataCallback send_data);
 static void InitWalSenderSlot(void);
 static void WalSndKill(int code, Datum arg);
-static void WalSndShutdown(void) pg_attribute_noreturn();
+pg_noreturn static void WalSndShutdown(void);
 static void XLogSendPhysical(void);
 static void XLogSendLogical(void);
 static void WalSndDone(WalSndSendDataCallback send_data);
diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c
index 093a3f1b66b..d29ed047d28 100644
--- a/src/backend/utils/adt/ri_triggers.c
+++ b/src/backend/utils/adt/ri_triggers.c
@@ -233,10 +233,10 @@ static bool ri_PerformCheck(const RI_ConstraintInfo *riinfo,
 static void ri_ExtractValues(Relation rel, TupleTableSlot *slot,
 							 const RI_ConstraintInfo *riinfo, bool rel_is_pk,
 							 Datum *vals, char *nulls);
-static void ri_ReportViolation(const RI_ConstraintInfo *riinfo,
-							   Relation pk_rel, Relation fk_rel,
-							   TupleTableSlot *violatorslot, TupleDesc tupdesc,
-							   int queryno, bool is_restrict, bool partgone) pg_attribute_noreturn();
+pg_noreturn static void ri_ReportViolation(const RI_ConstraintInfo *riinfo,
+										   Relation pk_rel, Relation fk_rel,
+										   TupleTableSlot *violatorslot, TupleDesc tupdesc,
+										   int queryno, bool is_restrict, bool partgone);
 
 
 /*
diff --git a/src/backend/utils/fmgr/dfmgr.c b/src/backend/utils/fmgr/dfmgr.c
index 8b7807472fd..0592ed637ee 100644
--- a/src/backend/utils/fmgr/dfmgr.c
+++ b/src/backend/utils/fmgr/dfmgr.c
@@ -67,8 +67,8 @@ static DynamicFileList *file_tail = NULL;
 char	   *Dynamic_library_path;
 
 static void *internal_load_library(const char *libname);
-static void incompatible_module_error(const char *libname,
-									  const Pg_magic_struct *module_magic_data) pg_attribute_noreturn();
+pg_noreturn static void incompatible_module_error(const char *libname,
+												  const Pg_magic_struct *module_magic_data);
 static char *expand_dynamic_library_name(const char *name);
 static void check_restricted_library_name(const char *name);
 static char *substitute_libpath_macro(const char *name);
diff --git a/src/backend/utils/hash/dynahash.c b/src/backend/utils/hash/dynahash.c
index 493eae4f4b0..8aa0c50b07c 100644
--- a/src/backend/utils/hash/dynahash.c
+++ b/src/backend/utils/hash/dynahash.c
@@ -272,7 +272,7 @@ static HASHBUCKET get_hash_entry(HTAB *hashp, int freelist_idx);
 static void hdefault(HTAB *hashp);
 static int	choose_nelem_alloc(Size entrysize);
 static bool init_htab(HTAB *hashp, long nelem);
-static void hash_corrupted(HTAB *hashp) pg_attribute_noreturn();
+pg_noreturn static void hash_corrupted(HTAB *hashp);
 static uint32 hash_initial_lookup(HTAB *hashp, uint32 hashvalue,
 								  HASHBUCKET **bucketptr);
 static long next_pow2_long(long num);
diff --git a/src/backend/utils/mmgr/slab.c b/src/backend/utils/mmgr/slab.c
index 3e15d59683f..bf8b841caa4 100644
--- a/src/backend/utils/mmgr/slab.c
+++ b/src/backend/utils/mmgr/slab.c
@@ -601,8 +601,8 @@ SlabAllocFromNewBlock(MemoryContext context, Size size, int flags)
  *		want to avoid that.
  */
 pg_noinline
+pg_noreturn
 static void
-pg_attribute_noreturn()
 SlabAllocInvalidSize(MemoryContext context, Size size)
 {
 	SlabContext *slab = (SlabContext *) context;
diff --git a/src/bin/pg_combinebackup/load_manifest.c b/src/bin/pg_combinebackup/load_manifest.c
index 54adb5a41d2..9c60bee17bf 100644
--- a/src/bin/pg_combinebackup/load_manifest.c
+++ b/src/bin/pg_combinebackup/load_manifest.c
@@ -68,9 +68,9 @@ static void combinebackup_per_wal_range_cb(JsonManifestParseContext *context,
 										   TimeLineID tli,
 										   XLogRecPtr start_lsn,
 										   XLogRecPtr end_lsn);
-static void report_manifest_error(JsonManifestParseContext *context,
-								  const char *fmt,...)
-			pg_attribute_printf(2, 3) pg_attribute_noreturn();
+pg_noreturn static void report_manifest_error(JsonManifestParseContext *context,
+											  const char *fmt,...)
+			pg_attribute_printf(2, 3);
 
 /*
  * Load backup_manifest files from an array of backups and produces an array
diff --git a/src/bin/pg_dump/pg_backup_utils.h b/src/bin/pg_dump/pg_backup_utils.h
index f2677839e30..470e9a0c9af 100644
--- a/src/bin/pg_dump/pg_backup_utils.h
+++ b/src/bin/pg_dump/pg_backup_utils.h
@@ -29,7 +29,7 @@ extern const char *progname;
 
 extern void set_dump_section(const char *arg, int *dumpSections);
 extern void on_exit_nicely(on_exit_nicely_callback function, void *arg);
-extern void exit_nicely(int code) pg_attribute_noreturn();
+pg_noreturn extern void exit_nicely(int code);
 
 /* In pg_dump, we modify pg_fatal to call exit_nicely instead of exit */
 #undef pg_fatal
diff --git a/src/bin/pg_upgrade/pg_upgrade.h b/src/bin/pg_upgrade/pg_upgrade.h
index 53f693c2d4b..26451578981 100644
--- a/src/bin/pg_upgrade/pg_upgrade.h
+++ b/src/bin/pg_upgrade/pg_upgrade.h
@@ -471,7 +471,7 @@ int			get_user_info(char **user_name_p);
 void		check_ok(void);
 void		report_status(eLogType type, const char *fmt,...) pg_attribute_printf(2, 3);
 void		pg_log(eLogType type, const char *fmt,...) pg_attribute_printf(2, 3);
-void		pg_fatal(const char *fmt,...) pg_attribute_printf(1, 2) pg_attribute_noreturn();
+pg_noreturn void pg_fatal(const char *fmt,...) pg_attribute_printf(1, 2);
 void		end_progress_output(void);
 void		cleanup_output_dirs(void);
 void		prep_status(const char *fmt,...) pg_attribute_printf(1, 2);
diff --git a/src/bin/pg_verifybackup/pg_verifybackup.c b/src/bin/pg_verifybackup/pg_verifybackup.c
index 0719cb89783..e4f4f8e6d39 100644
--- a/src/bin/pg_verifybackup/pg_verifybackup.c
+++ b/src/bin/pg_verifybackup/pg_verifybackup.c
@@ -69,9 +69,9 @@ static void verifybackup_per_wal_range_cb(JsonManifestParseContext *context,
 										  TimeLineID tli,
 										  XLogRecPtr start_lsn,
 										  XLogRecPtr end_lsn);
-static void report_manifest_error(JsonManifestParseContext *context,
-								  const char *fmt,...)
-			pg_attribute_printf(2, 3) pg_attribute_noreturn();
+pg_noreturn static void report_manifest_error(JsonManifestParseContext *context,
+											  const char *fmt,...)
+			pg_attribute_printf(2, 3);
 
 static void verify_tar_backup(verifier_context *context, DIR *dir);
 static void verify_plain_backup_directory(verifier_context *context,
diff --git a/src/bin/pg_verifybackup/pg_verifybackup.h b/src/bin/pg_verifybackup/pg_verifybackup.h
index 2f864fb0f3f..7da31d90fea 100644
--- a/src/bin/pg_verifybackup/pg_verifybackup.h
+++ b/src/bin/pg_verifybackup/pg_verifybackup.h
@@ -98,8 +98,8 @@ typedef struct verifier_context
 extern void report_backup_error(verifier_context *context,
 								const char *pg_restrict fmt,...)
 			pg_attribute_printf(2, 3);
-extern void report_fatal_error(const char *pg_restrict fmt,...)
-			pg_attribute_printf(1, 2) pg_attribute_noreturn();
+pg_noreturn extern void report_fatal_error(const char *pg_restrict fmt,...)
+			pg_attribute_printf(1, 2);
 extern bool should_ignore_relpath(verifier_context *context,
 								  const char *relpath);
 
diff --git a/src/bin/pgbench/pgbench.h b/src/bin/pgbench/pgbench.h
index 177f218c223..83565a9f1b0 100644
--- a/src/bin/pgbench/pgbench.h
+++ b/src/bin/pgbench/pgbench.h
@@ -142,9 +142,9 @@ extern PgBenchExpr *expr_parse_result;
 
 extern int	expr_yyparse(yyscan_t yyscanner);
 extern int	expr_yylex(union YYSTYPE *yylval_param, yyscan_t yyscanner);
-extern void expr_yyerror(yyscan_t yyscanner, const char *message) pg_attribute_noreturn();
-extern void expr_yyerror_more(yyscan_t yyscanner, const char *message,
-							  const char *more) pg_attribute_noreturn();
+pg_noreturn extern void expr_yyerror(yyscan_t yyscanner, const char *message);
+pg_noreturn extern void expr_yyerror_more(yyscan_t yyscanner, const char *message,
+										  const char *more);
 extern bool expr_lex_one_word(PsqlScanState state, PQExpBuffer word_buf,
 							  int *offset);
 extern yyscan_t expr_scanner_init(PsqlScanState state,
@@ -157,9 +157,9 @@ extern char *expr_scanner_get_substring(PsqlScanState state,
 										bool chomp);
 extern int	expr_scanner_get_lineno(PsqlScanState state, int offset);
 
-extern void syntax_error(const char *source, int lineno, const char *line,
-						 const char *command, const char *msg,
-						 const char *more, int column) pg_attribute_noreturn();
+pg_noreturn extern void syntax_error(const char *source, int lineno, const char *line,
+									 const char *command, const char *msg,
+									 const char *more, int column);
 
 extern bool strtoint64(const char *str, bool errorOK, int64 *result);
 extern bool strtodouble(const char *str, bool errorOK, double *dv);
diff --git a/src/include/bootstrap/bootstrap.h b/src/include/bootstrap/bootstrap.h
index 33035d4ed82..39e50ec79da 100644
--- a/src/include/bootstrap/bootstrap.h
+++ b/src/include/bootstrap/bootstrap.h
@@ -33,7 +33,7 @@ extern PGDLLIMPORT Form_pg_attribute attrtypes[MAXATTR];
 extern PGDLLIMPORT int numattr;
 
 
-extern void BootstrapModeMain(int argc, char *argv[], bool check_only) pg_attribute_noreturn();
+pg_noreturn extern void BootstrapModeMain(int argc, char *argv[], bool check_only);
 
 extern void closerel(char *relname);
 extern void boot_openrel(char *relname);
@@ -64,6 +64,6 @@ typedef void *yyscan_t;
 extern int	boot_yyparse(yyscan_t yyscanner);
 extern int	boot_yylex_init(yyscan_t *yyscannerp);
 extern int	boot_yylex(union YYSTYPE *yylval_param, yyscan_t yyscanner);
-extern void boot_yyerror(yyscan_t yyscanner, const char *message) pg_attribute_noreturn();
+pg_noreturn extern void boot_yyerror(yyscan_t yyscanner, const char *message);
 
 #endif							/* BOOTSTRAP_H */
diff --git a/src/include/c.h b/src/include/c.h
index 13bb39fdef3..eee2f476cb7 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -142,6 +142,22 @@
 #define pg_nodiscard
 #endif
 
+/*
+ * pg_noreturn corresponds to the C11 noreturn/_Noreturn function specifier.
+ * We can't use the standard name "noreturn" because some third-party code
+ * uses __attribute__((noreturn)) in headers, which would get confused if
+ * "noreturn" is defined to "_Noreturn", as is done by <stdnoreturn.h>.
+ */
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
+#define pg_noreturn _Noreturn
+#elif defined(__GNUC__)
+#define pg_noreturn __attribute__((noreturn))
+#elif defined(_MSC_VER)
+#define pg_noreturn __declspec(noreturn)
+#else
+#define pg_noreturn
+#endif
+
 /*
  * This macro will disable address safety instrumentation for a function
  * when running with "-fsanitize=address". Think twice before using this!
@@ -210,30 +226,24 @@
 #define pg_attribute_printf(f,a)
 #endif
 
-/* GCC and Sunpro support aligned, packed and noreturn */
+/* GCC and Sunpro support aligned and packed */
 #if defined(__GNUC__) || defined(__SUNPRO_C)
 #define pg_attribute_aligned(a) __attribute__((aligned(a)))
-#define pg_attribute_noreturn() __attribute__((noreturn))
 #define pg_attribute_packed() __attribute__((packed))
-#define HAVE_PG_ATTRIBUTE_NORETURN 1
 #elif defined(_MSC_VER)
 /*
- * MSVC supports aligned.  noreturn is also possible but in MSVC it is
- * declared before the definition while pg_attribute_noreturn() macro
- * is currently used after the definition.
+ * MSVC supports aligned.
  *
  * Packing is also possible but only by wrapping the entire struct definition
  * which doesn't fit into our current macro declarations.
  */
 #define pg_attribute_aligned(a) __declspec(align(a))
-#define pg_attribute_noreturn()
 #else
 /*
  * NB: aligned and packed are not given default definitions because they
  * affect code functionality; they *must* be implemented by the compiler
  * if they are to be used.
  */
-#define pg_attribute_noreturn()
 #endif
 
 /*
@@ -855,8 +865,8 @@ typedef NameData *Name;
  * we should declare it as long as !FRONTEND.
  */
 #ifndef FRONTEND
-extern void ExceptionalCondition(const char *conditionName,
-								 const char *fileName, int lineNumber) pg_attribute_noreturn();
+pg_noreturn extern void ExceptionalCondition(const char *conditionName,
+											 const char *fileName, int lineNumber);
 #endif
 
 /*
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index 5fd095ea177..2e3fdda72fa 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -160,6 +160,6 @@ extern List *defGetQualifiedName(DefElem *def);
 extern TypeName *defGetTypeName(DefElem *def);
 extern int	defGetTypeLength(DefElem *def);
 extern List *defGetStringList(DefElem *def);
-extern void errorConflictingDefElem(DefElem *defel, ParseState *pstate) pg_attribute_noreturn();
+pg_noreturn extern void errorConflictingDefElem(DefElem *defel, ParseState *pstate);
 
 #endif							/* DEFREM_H */
diff --git a/src/include/common/parse_manifest.h b/src/include/common/parse_manifest.h
index 607db25a3a6..e7a3ce750e9 100644
--- a/src/include/common/parse_manifest.h
+++ b/src/include/common/parse_manifest.h
@@ -34,8 +34,7 @@ typedef void (*json_manifest_per_wal_range_callback) (JsonManifestParseContext *
 													  TimeLineID tli,
 													  XLogRecPtr start_lsn, XLogRecPtr end_lsn);
 typedef void (*json_manifest_error_callback) (JsonManifestParseContext *,
-											  const char *fmt,...) pg_attribute_printf(2, 3)
-			pg_attribute_noreturn();
+											  const char *fmt,...) pg_attribute_printf(2, 3);
 
 struct JsonManifestParseContext
 {
diff --git a/src/include/mb/pg_wchar.h b/src/include/mb/pg_wchar.h
index 249cd18a357..dc23b903b07 100644
--- a/src/include/mb/pg_wchar.h
+++ b/src/include/mb/pg_wchar.h
@@ -767,9 +767,9 @@ extern void check_encoding_conversion_args(int src_encoding,
 										   int expected_src_encoding,
 										   int expected_dest_encoding);
 
-extern void report_invalid_encoding(int encoding, const char *mbstr, int len) pg_attribute_noreturn();
-extern void report_untranslatable_char(int src_encoding, int dest_encoding,
-									   const char *mbstr, int len) pg_attribute_noreturn();
+pg_noreturn extern void report_invalid_encoding(int encoding, const char *mbstr, int len);
+pg_noreturn extern void report_untranslatable_char(int src_encoding, int dest_encoding,
+												   const char *mbstr, int len);
 
 extern int	local2local(const unsigned char *l, unsigned char *p, int len,
 						int src_encoding, int dest_encoding,
diff --git a/src/include/parser/parse_relation.h b/src/include/parser/parse_relation.h
index 91fd8e243b5..5b3461a65fe 100644
--- a/src/include/parser/parse_relation.h
+++ b/src/include/parser/parse_relation.h
@@ -110,9 +110,9 @@ extern bool isLockedRefname(ParseState *pstate, const char *refname);
 extern void addNSItemToQuery(ParseState *pstate, ParseNamespaceItem *nsitem,
 							 bool addToJoinList,
 							 bool addToRelNameSpace, bool addToVarNameSpace);
-extern void errorMissingRTE(ParseState *pstate, RangeVar *relation) pg_attribute_noreturn();
-extern void errorMissingColumn(ParseState *pstate,
-							   const char *relname, const char *colname, int location) pg_attribute_noreturn();
+pg_noreturn extern void errorMissingRTE(ParseState *pstate, RangeVar *relation);
+pg_noreturn extern void errorMissingColumn(ParseState *pstate,
+										   const char *relname, const char *colname, int location);
 extern void expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
 					  int location, bool include_dropped,
 					  List **colnames, List **colvars);
diff --git a/src/include/parser/scanner.h b/src/include/parser/scanner.h
index d6293b1e878..ee42650fa08 100644
--- a/src/include/parser/scanner.h
+++ b/src/include/parser/scanner.h
@@ -145,6 +145,6 @@ extern void setup_scanner_errposition_callback(ScannerCallbackState *scbstate,
 											   core_yyscan_t yyscanner,
 											   int location);
 extern void cancel_scanner_errposition_callback(ScannerCallbackState *scbstate);
-extern void scanner_yyerror(const char *message, core_yyscan_t yyscanner) pg_attribute_noreturn();
+pg_noreturn extern void scanner_yyerror(const char *message, core_yyscan_t yyscanner);
 
 #endif							/* SCANNER_H */
diff --git a/src/include/postmaster/autovacuum.h b/src/include/postmaster/autovacuum.h
index cae1e8b3294..1ff38db9e1f 100644
--- a/src/include/postmaster/autovacuum.h
+++ b/src/include/postmaster/autovacuum.h
@@ -56,8 +56,8 @@ extern void autovac_init(void);
 /* called from postmaster when a worker could not be forked */
 extern void AutoVacWorkerFailed(void);
 
-extern void AutoVacLauncherMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
-extern void AutoVacWorkerMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+pg_noreturn extern void AutoVacLauncherMain(char *startup_data, size_t startup_data_len);
+pg_noreturn extern void AutoVacWorkerMain(char *startup_data, size_t startup_data_len);
 
 extern bool AutoVacuumRequestWork(AutoVacuumWorkItemType type,
 								  Oid relationId, BlockNumber blkno);
diff --git a/src/include/postmaster/bgworker_internals.h b/src/include/postmaster/bgworker_internals.h
index f55adc85efc..1ba46b00b7e 100644
--- a/src/include/postmaster/bgworker_internals.h
+++ b/src/include/postmaster/bgworker_internals.h
@@ -52,6 +52,6 @@ extern void ForgetUnstartedBackgroundWorkers(void);
 extern void ResetBackgroundWorkerCrashTimes(void);
 
 /* Entry point for background worker processes */
-extern void BackgroundWorkerMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+pg_noreturn extern void BackgroundWorkerMain(char *startup_data, size_t startup_data_len);
 
 #endif							/* BGWORKER_INTERNALS_H */
diff --git a/src/include/postmaster/bgwriter.h b/src/include/postmaster/bgwriter.h
index 407f26e5302..d524964b8b0 100644
--- a/src/include/postmaster/bgwriter.h
+++ b/src/include/postmaster/bgwriter.h
@@ -27,8 +27,8 @@ extern PGDLLIMPORT int CheckPointTimeout;
 extern PGDLLIMPORT int CheckPointWarning;
 extern PGDLLIMPORT double CheckPointCompletionTarget;
 
-extern void BackgroundWriterMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
-extern void CheckpointerMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+pg_noreturn extern void BackgroundWriterMain(char *startup_data, size_t startup_data_len);
+pg_noreturn extern void CheckpointerMain(char *startup_data, size_t startup_data_len);
 
 extern void RequestCheckpoint(int flags);
 extern void CheckpointWriteDelay(int flags, double progress);
diff --git a/src/include/postmaster/pgarch.h b/src/include/postmaster/pgarch.h
index a7a417226b0..c59e5d93c67 100644
--- a/src/include/postmaster/pgarch.h
+++ b/src/include/postmaster/pgarch.h
@@ -29,7 +29,7 @@
 extern Size PgArchShmemSize(void);
 extern void PgArchShmemInit(void);
 extern bool PgArchCanRestart(void);
-extern void PgArchiverMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+pg_noreturn extern void PgArchiverMain(char *startup_data, size_t startup_data_len);
 extern void PgArchWakeup(void);
 extern void PgArchForceDirScan(void);
 
diff --git a/src/include/postmaster/postmaster.h b/src/include/postmaster/postmaster.h
index 24d49a5439e..089c024e2f7 100644
--- a/src/include/postmaster/postmaster.h
+++ b/src/include/postmaster/postmaster.h
@@ -91,7 +91,7 @@ extern PGDLLIMPORT const char *progname;
 extern PGDLLIMPORT bool redirection_done;
 extern PGDLLIMPORT bool LoadedSSL;
 
-extern void PostmasterMain(int argc, char *argv[]) pg_attribute_noreturn();
+pg_noreturn extern void PostmasterMain(int argc, char *argv[]);
 extern void ClosePostmasterPorts(bool am_syslogger);
 extern void InitProcessGlobals(void);
 
@@ -114,7 +114,7 @@ extern pid_t postmaster_child_launch(BackendType child_type,
 									 struct ClientSocket *client_sock);
 const char *PostmasterChildName(BackendType child_type);
 #ifdef EXEC_BACKEND
-extern void SubPostmasterMain(int argc, char *argv[]) pg_attribute_noreturn();
+pg_noreturn extern void SubPostmasterMain(int argc, char *argv[]);
 #endif
 
 /* defined in pmchild.c */
diff --git a/src/include/postmaster/startup.h b/src/include/postmaster/startup.h
index dde7ebde881..057b208548e 100644
--- a/src/include/postmaster/startup.h
+++ b/src/include/postmaster/startup.h
@@ -26,7 +26,7 @@
 extern PGDLLIMPORT int log_startup_progress_interval;
 
 extern void HandleStartupProcInterrupts(void);
-extern void StartupProcessMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+pg_noreturn extern void StartupProcessMain(char *startup_data, size_t startup_data_len);
 extern void PreRestoreCommand(void);
 extern void PostRestoreCommand(void);
 extern bool IsPromoteSignaled(void);
diff --git a/src/include/postmaster/syslogger.h b/src/include/postmaster/syslogger.h
index 27bd16ae1da..a12488b3022 100644
--- a/src/include/postmaster/syslogger.h
+++ b/src/include/postmaster/syslogger.h
@@ -90,7 +90,7 @@ extern int	SysLogger_Start(int child_slot);
 
 extern void write_syslogger_file(const char *buffer, int count, int destination);
 
-extern void SysLoggerMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+pg_noreturn extern void SysLoggerMain(char *startup_data, size_t startup_data_len);
 
 extern bool CheckLogrotateSignal(void);
 extern void RemoveLogrotateSignalFiles(void);
diff --git a/src/include/postmaster/walsummarizer.h b/src/include/postmaster/walsummarizer.h
index 2642aa701d7..18d85b7eb9a 100644
--- a/src/include/postmaster/walsummarizer.h
+++ b/src/include/postmaster/walsummarizer.h
@@ -21,7 +21,7 @@ extern PGDLLIMPORT int wal_summary_keep_time;
 
 extern Size WalSummarizerShmemSize(void);
 extern void WalSummarizerShmemInit(void);
-extern void WalSummarizerMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+pg_noreturn extern void WalSummarizerMain(char *startup_data, size_t startup_data_len);
 
 extern void GetWalSummarizerState(TimeLineID *summarized_tli,
 								  XLogRecPtr *summarized_lsn,
diff --git a/src/include/postmaster/walwriter.h b/src/include/postmaster/walwriter.h
index 5884d69fed1..4d880afd821 100644
--- a/src/include/postmaster/walwriter.h
+++ b/src/include/postmaster/walwriter.h
@@ -18,6 +18,6 @@
 extern PGDLLIMPORT int WalWriterDelay;
 extern PGDLLIMPORT int WalWriterFlushAfter;
 
-extern void WalWriterMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+pg_noreturn extern void WalWriterMain(char *startup_data, size_t startup_data_len);
 
 #endif							/* _WALWRITER_H */
diff --git a/src/include/replication/slotsync.h b/src/include/replication/slotsync.h
index e03c2a005a4..19670d5cea9 100644
--- a/src/include/replication/slotsync.h
+++ b/src/include/replication/slotsync.h
@@ -26,7 +26,7 @@ extern PGDLLIMPORT char *PrimarySlotName;
 extern char *CheckAndGetDbnameFromConninfo(void);
 extern bool ValidateSlotSyncParams(int elevel);
 
-extern void ReplSlotSyncWorkerMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+pg_noreturn extern void ReplSlotSyncWorkerMain(char *startup_data, size_t startup_data_len);
 
 extern void ShutDownSlotSync(void);
 extern bool SlotSyncWorkerCanRestart(void);
diff --git a/src/include/replication/walreceiver.h b/src/include/replication/walreceiver.h
index 3342286d2a3..18cf8fc93ab 100644
--- a/src/include/replication/walreceiver.h
+++ b/src/include/replication/walreceiver.h
@@ -486,7 +486,7 @@ walrcv_clear_result(WalRcvExecResult *walres)
 }
 
 /* prototypes for functions in walreceiver.c */
-extern void WalReceiverMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+pg_noreturn extern void WalReceiverMain(char *startup_data, size_t startup_data_len);
 extern void ProcessWalRcvInterrupts(void);
 extern void WalRcvForceReply(void);
 
diff --git a/src/include/replication/walsender_private.h b/src/include/replication/walsender_private.h
index 9a9c40d6f34..335303b7360 100644
--- a/src/include/replication/walsender_private.h
+++ b/src/include/replication/walsender_private.h
@@ -132,7 +132,7 @@ typedef void *yyscan_t;
 #endif
 extern int	replication_yyparse(yyscan_t yyscanner);
 extern int	replication_yylex(union YYSTYPE *yylval_param, yyscan_t yyscanner);
-extern void replication_yyerror(yyscan_t yyscanner, const char *message) pg_attribute_noreturn();
+pg_noreturn extern void replication_yyerror(yyscan_t yyscanner, const char *message);
 extern void replication_scanner_init(const char *str, yyscan_t *yyscannerp);
 extern void replication_scanner_finish(yyscan_t yyscanner);
 extern bool replication_scanner_is_replication_command(yyscan_t yyscanner);
diff --git a/src/include/storage/ipc.h b/src/include/storage/ipc.h
index b2d062781ec..5c5b692445c 100644
--- a/src/include/storage/ipc.h
+++ b/src/include/storage/ipc.h
@@ -65,7 +65,7 @@ typedef void (*shmem_startup_hook_type) (void);
 extern PGDLLIMPORT bool proc_exit_inprogress;
 extern PGDLLIMPORT bool shmem_exit_inprogress;
 
-extern void proc_exit(int code) pg_attribute_noreturn();
+pg_noreturn extern void proc_exit(int code);
 extern void shmem_exit(int code);
 extern void on_proc_exit(pg_on_exit_callback function, Datum arg);
 extern void on_shmem_exit(pg_on_exit_callback function, Datum arg);
diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h
index 787f3db06a9..4e29881ca3e 100644
--- a/src/include/storage/lock.h
+++ b/src/include/storage/lock.h
@@ -605,7 +605,7 @@ extern void lock_twophase_standby_recover(TransactionId xid, uint16 info,
 
 extern DeadLockState DeadLockCheck(PGPROC *proc);
 extern PGPROC *GetBlockingAutoVacuumPgproc(void);
-extern void DeadLockReport(void) pg_attribute_noreturn();
+pg_noreturn extern void DeadLockReport(void);
 extern void RememberSimpleDeadLock(PGPROC *proc1,
 								   LOCKMODE lockmode,
 								   LOCK *lock,
diff --git a/src/include/tcop/backend_startup.h b/src/include/tcop/backend_startup.h
index 993b013afdd..8cc6cd2bf67 100644
--- a/src/include/tcop/backend_startup.h
+++ b/src/include/tcop/backend_startup.h
@@ -39,6 +39,6 @@ typedef struct BackendStartupData
 	CAC_state	canAcceptConnections;
 } BackendStartupData;
 
-extern void BackendMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+pg_noreturn extern void BackendMain(char *startup_data, size_t startup_data_len);
 
 #endif							/* BACKEND_STARTUP_H */
diff --git a/src/include/tcop/tcopprot.h b/src/include/tcop/tcopprot.h
index 3c6ed917e17..b3060e0a430 100644
--- a/src/include/tcop/tcopprot.h
+++ b/src/include/tcop/tcopprot.h
@@ -69,19 +69,19 @@ extern List *pg_plan_queries(List *querytrees, const char *query_string,
 							 ParamListInfo boundParams);
 
 extern void die(SIGNAL_ARGS);
-extern void quickdie(SIGNAL_ARGS) pg_attribute_noreturn();
+pg_noreturn extern void quickdie(SIGNAL_ARGS);
 extern void StatementCancelHandler(SIGNAL_ARGS);
-extern void FloatExceptionHandler(SIGNAL_ARGS) pg_attribute_noreturn();
+pg_noreturn extern void FloatExceptionHandler(SIGNAL_ARGS);
 extern void HandleRecoveryConflictInterrupt(ProcSignalReason reason);
 extern void ProcessClientReadInterrupt(bool blocked);
 extern void ProcessClientWriteInterrupt(bool blocked);
 
 extern void process_postgres_switches(int argc, char *argv[],
 									  GucContext ctx, const char **dbname);
-extern void PostgresSingleUserMain(int argc, char *argv[],
-								   const char *username) pg_attribute_noreturn();
-extern void PostgresMain(const char *dbname,
-						 const char *username) pg_attribute_noreturn();
+pg_noreturn extern void PostgresSingleUserMain(int argc, char *argv[],
+											   const char *username);
+pg_noreturn extern void PostgresMain(const char *dbname,
+									 const char *username);
 extern void ResetUsage(void);
 extern void ShowUsage(const char *title);
 extern int	check_log_duration(char *msec_str, bool was_logged);
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
index e54eca5b489..73e3716bae1 100644
--- a/src/include/utils/elog.h
+++ b/src/include/utils/elog.h
@@ -415,17 +415,8 @@ extern PGDLLIMPORT ErrorContextCallback *error_context_stack;
 		error_context_stack = _save_context_stack##__VA_ARGS__; \
 	} while (0)
 
-/*
- * Some compilers understand pg_attribute_noreturn(); for other compilers,
- * insert pg_unreachable() so that the compiler gets the point.
- */
-#ifdef HAVE_PG_ATTRIBUTE_NORETURN
 #define PG_RE_THROW()  \
 	pg_re_throw()
-#else
-#define PG_RE_THROW()  \
-	(pg_re_throw(), pg_unreachable())
-#endif
 
 extern PGDLLIMPORT sigjmp_buf *PG_exception_stack;
 
@@ -476,9 +467,9 @@ extern void EmitErrorReport(void);
 extern ErrorData *CopyErrorData(void);
 extern void FreeErrorData(ErrorData *edata);
 extern void FlushErrorState(void);
-extern void ReThrowError(ErrorData *edata) pg_attribute_noreturn();
+pg_noreturn extern void ReThrowError(ErrorData *edata);
 extern void ThrowErrorData(ErrorData *edata);
-extern void pg_re_throw(void) pg_attribute_noreturn();
+pg_noreturn extern void pg_re_throw(void);
 
 extern char *GetErrorContextStack(void);
 
diff --git a/src/include/utils/float.h b/src/include/utils/float.h
index 7d1badd292a..96d4f7effbc 100644
--- a/src/include/utils/float.h
+++ b/src/include/utils/float.h
@@ -37,9 +37,9 @@ extern PGDLLIMPORT int extra_float_digits;
 /*
  * Utility functions in float.c
  */
-extern void float_overflow_error(void) pg_attribute_noreturn();
-extern void float_underflow_error(void) pg_attribute_noreturn();
-extern void float_zero_divide_error(void) pg_attribute_noreturn();
+pg_noreturn extern void float_overflow_error(void);
+pg_noreturn extern void float_underflow_error(void);
+pg_noreturn extern void float_zero_divide_error(void);
 extern int	is_infinite(float8 val);
 extern float8 float8in_internal(char *num, char **endptr_p,
 								const char *type_name, const char *orig_string,
diff --git a/src/include/utils/help_config.h b/src/include/utils/help_config.h
index c27a54f1b91..38d92eac803 100644
--- a/src/include/utils/help_config.h
+++ b/src/include/utils/help_config.h
@@ -12,6 +12,6 @@
 #ifndef HELP_CONFIG_H
 #define HELP_CONFIG_H 1
 
-extern void GucInfoMain(void) pg_attribute_noreturn();
+pg_noreturn extern void GucInfoMain(void);
 
 #endif
diff --git a/src/include/utils/memutils_internal.h b/src/include/utils/memutils_internal.h
index 5ce2d9b5877..eecb0aabd75 100644
--- a/src/include/utils/memutils_internal.h
+++ b/src/include/utils/memutils_internal.h
@@ -160,8 +160,8 @@ extern void MemoryContextCreate(MemoryContext node,
 extern void *MemoryContextAllocationFailure(MemoryContext context, Size size,
 											int flags);
 
-extern void MemoryContextSizeFailure(MemoryContext context, Size size,
-									 int flags) pg_attribute_noreturn();
+pg_noreturn extern void MemoryContextSizeFailure(MemoryContext context, Size size,
+												 int flags);
 
 static inline void
 MemoryContextCheckSize(MemoryContext context, Size size, int flags)
diff --git a/src/interfaces/ecpg/preproc/preproc_extern.h b/src/interfaces/ecpg/preproc/preproc_extern.h
index a60b0381fbb..2c89e30621e 100644
--- a/src/interfaces/ecpg/preproc/preproc_extern.h
+++ b/src/interfaces/ecpg/preproc/preproc_extern.h
@@ -89,7 +89,7 @@ extern char *cat_str(int count,...);
 extern char *make2_str(const char *str1, const char *str2);
 extern char *make3_str(const char *str1, const char *str2, const char *str3);
 extern void mmerror(int error_code, enum errortype type, const char *error,...) pg_attribute_printf(3, 4);
-extern void mmfatal(int error_code, const char *error,...) pg_attribute_printf(2, 3) pg_attribute_noreturn();
+pg_noreturn extern void mmfatal(int error_code, const char *error,...) pg_attribute_printf(2, 3);
 extern void output_get_descr_header(const char *desc_name);
 extern void output_get_descr(const char *desc_name, const char *index);
 extern void output_set_descr_header(const char *desc_name);
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index 50c3b28472b..15904c08a4b 100644
--- a/src/pl/plpgsql/src/plpgsql.h
+++ b/src/pl/plpgsql/src/plpgsql.h
@@ -1326,7 +1326,7 @@ extern int	plpgsql_peek(void);
 extern void plpgsql_peek2(int *tok1_p, int *tok2_p, int *tok1_loc,
 						  int *tok2_loc);
 extern int	plpgsql_scanner_errposition(int location);
-extern void plpgsql_yyerror(const char *message) pg_attribute_noreturn();
+pg_noreturn extern void plpgsql_yyerror(const char *message);
 extern int	plpgsql_location_to_lineno(int location);
 extern int	plpgsql_latest_lineno(void);
 extern void plpgsql_scanner_init(const char *str);
diff --git a/src/test/modules/libpq_pipeline/libpq_pipeline.c b/src/test/modules/libpq_pipeline/libpq_pipeline.c
index 1323e4c598d..8afbcbbe084 100644
--- a/src/test/modules/libpq_pipeline/libpq_pipeline.c
+++ b/src/test/modules/libpq_pipeline/libpq_pipeline.c
@@ -24,7 +24,7 @@
 
 
 static void exit_nicely(PGconn *conn);
-static void pg_attribute_noreturn() pg_fatal_impl(int line, const char *fmt,...)
+pg_noreturn static void pg_fatal_impl(int line, const char *fmt,...)
 			pg_attribute_printf(2, 3);
 static bool process_result(PGconn *conn, PGresult *res, int results,
 						   int numsent);
@@ -71,8 +71,7 @@ exit_nicely(PGconn *conn)
  * Print an error to stderr and terminate the program.
  */
 #define pg_fatal(...) pg_fatal_impl(__LINE__, __VA_ARGS__)
-static void
-pg_attribute_noreturn()
+pg_noreturn static void
 pg_fatal_impl(int line, const char *fmt,...)
 {
 	va_list		args;
diff --git a/src/test/modules/test_shm_mq/test_shm_mq.h b/src/test/modules/test_shm_mq/test_shm_mq.h
index 0ae7bd64cd0..854bdd46bc2 100644
--- a/src/test/modules/test_shm_mq/test_shm_mq.h
+++ b/src/test/modules/test_shm_mq/test_shm_mq.h
@@ -40,6 +40,6 @@ extern void test_shm_mq_setup(int64 queue_size, int32 nworkers,
 							  shm_mq_handle **input);
 
 /* Main entrypoint for a worker. */
-extern PGDLLEXPORT void test_shm_mq_main(Datum) pg_attribute_noreturn();
+pg_noreturn extern PGDLLEXPORT void test_shm_mq_main(Datum);
 
 #endif
diff --git a/src/test/modules/worker_spi/worker_spi.c b/src/test/modules/worker_spi/worker_spi.c
index d4403b24d98..04c2955e3fc 100644
--- a/src/test/modules/worker_spi/worker_spi.c
+++ b/src/test/modules/worker_spi/worker_spi.c
@@ -44,7 +44,7 @@ PG_MODULE_MAGIC;
 
 PG_FUNCTION_INFO_V1(worker_spi_launch);
 
-PGDLLEXPORT void worker_spi_main(Datum main_arg) pg_attribute_noreturn();
+PGDLLEXPORT pg_noreturn void worker_spi_main(Datum main_arg);
 
 /* GUC variables */
 static int	worker_spi_naptime = 10;
diff --git a/src/timezone/zic.c b/src/timezone/zic.c
index d605c721ecf..3b70b888180 100644
--- a/src/timezone/zic.c
+++ b/src/timezone/zic.c
@@ -117,11 +117,11 @@ extern int	link(const char *target, const char *linkname);
 	(itssymlink(target) ? (errno = ENOTSUP, -1) : link(target, linkname))
 #endif
 
-static void memory_exhausted(const char *msg) pg_attribute_noreturn();
+pg_noreturn static void memory_exhausted(const char *msg);
 static void verror(const char *string, va_list args) pg_attribute_printf(1, 0);
 static void error(const char *string,...) pg_attribute_printf(1, 2);
 static void warning(const char *string,...) pg_attribute_printf(1, 2);
-static void usage(FILE *stream, int status) pg_attribute_noreturn();
+pg_noreturn static void usage(FILE *stream, int status);
 static void addtt(zic_t starttime, int type);
 static int	addtype(zic_t utoff, char const *abbr,
 					bool isdst, bool ttisstd, bool ttisut);
diff --git a/src/tools/pg_bsd_indent/err.h b/src/tools/pg_bsd_indent/err.h
index a3e8f978255..1083462088e 100644
--- a/src/tools/pg_bsd_indent/err.h
+++ b/src/tools/pg_bsd_indent/err.h
@@ -37,9 +37,9 @@
  * This is cut down to just the minimum that we need to build indent.
  */
 
-void	err(int, const char *, ...)
-  pg_attribute_noreturn() pg_attribute_printf(2, 3);
-void	errx(int, const char *, ...)
-  pg_attribute_noreturn() pg_attribute_printf(2, 3);
+pg_noreturn void err(int, const char *, ...)
+  pg_attribute_printf(2, 3);
+pg_noreturn void errx(int, const char *, ...)
+  pg_attribute_printf(2, 3);
 
 #endif /* !_ERR_H_ */

base-commit: d85ce012f99f63249bb45a78fcecb7a2383920b1
-- 
2.47.1

0002-Add-another-pg_noreturn.patchtext/plain; charset=UTF-8; name=0002-Add-another-pg_noreturn.patchDownload
From 0f59b0a7fee4f69d9632c732ba4dc4bb220fd401 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Sat, 28 Dec 2024 11:00:24 +0100
Subject: [PATCH 2/4] Add another pg_noreturn

The previous change revealed a compiler warning about possibly
uninitialized variables, which this fixes.
---
 src/common/parse_manifest.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/common/parse_manifest.c b/src/common/parse_manifest.c
index a3896eaebe2..b3406b40d48 100644
--- a/src/common/parse_manifest.c
+++ b/src/common/parse_manifest.c
@@ -114,8 +114,8 @@ static void json_manifest_finalize_wal_range(JsonManifestParseState *parse);
 static void verify_manifest_checksum(JsonManifestParseState *parse,
 									 const char *buffer, size_t size,
 									 pg_cryptohash_ctx *incr_ctx);
-static void json_manifest_parse_failure(JsonManifestParseContext *context,
-										char *msg);
+pg_noreturn static void json_manifest_parse_failure(JsonManifestParseContext *context,
+													char *msg);
 
 static int	hexdecode_char(char c);
 static bool hexdecode_string(uint8 *result, char *input, int nbytes);
@@ -889,6 +889,7 @@ static void
 json_manifest_parse_failure(JsonManifestParseContext *context, char *msg)
 {
 	context->error_cb(context, "could not parse backup manifest: %s", msg);
+	pg_unreachable();
 }
 
 /*
-- 
2.47.1

0003-Swap-order-of-extern-static-and-pg_nodiscard.patchtext/plain; charset=UTF-8; name=0003-Swap-order-of-extern-static-and-pg_nodiscard.patchDownload
From c72d50b0374246da3927a02a2d91938cb442b157 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Sat, 28 Dec 2024 11:00:24 +0100
Subject: [PATCH 3/4] Swap order of extern/static and pg_nodiscard

Clang in C23 mode requires all attributes to be before extern or
static.  So just swap these.  This also keeps the order consistent
with the previously introduced pg_noreturn.
---
 src/include/nodes/pg_list.h   | 68 +++++++++++++++++------------------
 src/include/storage/buffile.h |  2 +-
 src/include/utils/guc.h       |  2 +-
 src/include/utils/palloc.h    |  8 ++---
 4 files changed, 40 insertions(+), 40 deletions(-)

diff --git a/src/include/nodes/pg_list.h b/src/include/nodes/pg_list.h
index d131350e107..293981b2742 100644
--- a/src/include/nodes/pg_list.h
+++ b/src/include/nodes/pg_list.h
@@ -608,23 +608,23 @@ extern List *list_make5_impl(NodeTag t, ListCell datum1, ListCell datum2,
 							 ListCell datum3, ListCell datum4,
 							 ListCell datum5);
 
-extern pg_nodiscard List *lappend(List *list, void *datum);
-extern pg_nodiscard List *lappend_int(List *list, int datum);
-extern pg_nodiscard List *lappend_oid(List *list, Oid datum);
-extern pg_nodiscard List *lappend_xid(List *list, TransactionId datum);
+pg_nodiscard extern List *lappend(List *list, void *datum);
+pg_nodiscard extern List *lappend_int(List *list, int datum);
+pg_nodiscard extern List *lappend_oid(List *list, Oid datum);
+pg_nodiscard extern List *lappend_xid(List *list, TransactionId datum);
 
-extern pg_nodiscard List *list_insert_nth(List *list, int pos, void *datum);
-extern pg_nodiscard List *list_insert_nth_int(List *list, int pos, int datum);
-extern pg_nodiscard List *list_insert_nth_oid(List *list, int pos, Oid datum);
+pg_nodiscard extern List *list_insert_nth(List *list, int pos, void *datum);
+pg_nodiscard extern List *list_insert_nth_int(List *list, int pos, int datum);
+pg_nodiscard extern List *list_insert_nth_oid(List *list, int pos, Oid datum);
 
-extern pg_nodiscard List *lcons(void *datum, List *list);
-extern pg_nodiscard List *lcons_int(int datum, List *list);
-extern pg_nodiscard List *lcons_oid(Oid datum, List *list);
+pg_nodiscard extern List *lcons(void *datum, List *list);
+pg_nodiscard extern List *lcons_int(int datum, List *list);
+pg_nodiscard extern List *lcons_oid(Oid datum, List *list);
 
-extern pg_nodiscard List *list_concat(List *list1, const List *list2);
-extern pg_nodiscard List *list_concat_copy(const List *list1, const List *list2);
+pg_nodiscard extern List *list_concat(List *list1, const List *list2);
+pg_nodiscard extern List *list_concat_copy(const List *list1, const List *list2);
 
-extern pg_nodiscard List *list_truncate(List *list, int new_size);
+pg_nodiscard extern List *list_truncate(List *list, int new_size);
 
 extern bool list_member(const List *list, const void *datum);
 extern bool list_member_ptr(const List *list, const void *datum);
@@ -632,15 +632,15 @@ extern bool list_member_int(const List *list, int datum);
 extern bool list_member_oid(const List *list, Oid datum);
 extern bool list_member_xid(const List *list, TransactionId datum);
 
-extern pg_nodiscard List *list_delete(List *list, void *datum);
-extern pg_nodiscard List *list_delete_ptr(List *list, void *datum);
-extern pg_nodiscard List *list_delete_int(List *list, int datum);
-extern pg_nodiscard List *list_delete_oid(List *list, Oid datum);
-extern pg_nodiscard List *list_delete_first(List *list);
-extern pg_nodiscard List *list_delete_last(List *list);
-extern pg_nodiscard List *list_delete_first_n(List *list, int n);
-extern pg_nodiscard List *list_delete_nth_cell(List *list, int n);
-extern pg_nodiscard List *list_delete_cell(List *list, ListCell *cell);
+pg_nodiscard extern List *list_delete(List *list, void *datum);
+pg_nodiscard extern List *list_delete_ptr(List *list, void *datum);
+pg_nodiscard extern List *list_delete_int(List *list, int datum);
+pg_nodiscard extern List *list_delete_oid(List *list, Oid datum);
+pg_nodiscard extern List *list_delete_first(List *list);
+pg_nodiscard extern List *list_delete_last(List *list);
+pg_nodiscard extern List *list_delete_first_n(List *list, int n);
+pg_nodiscard extern List *list_delete_nth_cell(List *list, int n);
+pg_nodiscard extern List *list_delete_cell(List *list, ListCell *cell);
 
 extern List *list_union(const List *list1, const List *list2);
 extern List *list_union_ptr(const List *list1, const List *list2);
@@ -657,25 +657,25 @@ extern List *list_difference_ptr(const List *list1, const List *list2);
 extern List *list_difference_int(const List *list1, const List *list2);
 extern List *list_difference_oid(const List *list1, const List *list2);
 
-extern pg_nodiscard List *list_append_unique(List *list, void *datum);
-extern pg_nodiscard List *list_append_unique_ptr(List *list, void *datum);
-extern pg_nodiscard List *list_append_unique_int(List *list, int datum);
-extern pg_nodiscard List *list_append_unique_oid(List *list, Oid datum);
+pg_nodiscard extern List *list_append_unique(List *list, void *datum);
+pg_nodiscard extern List *list_append_unique_ptr(List *list, void *datum);
+pg_nodiscard extern List *list_append_unique_int(List *list, int datum);
+pg_nodiscard extern List *list_append_unique_oid(List *list, Oid datum);
 
-extern pg_nodiscard List *list_concat_unique(List *list1, const List *list2);
-extern pg_nodiscard List *list_concat_unique_ptr(List *list1, const List *list2);
-extern pg_nodiscard List *list_concat_unique_int(List *list1, const List *list2);
-extern pg_nodiscard List *list_concat_unique_oid(List *list1, const List *list2);
+pg_nodiscard extern List *list_concat_unique(List *list1, const List *list2);
+pg_nodiscard extern List *list_concat_unique_ptr(List *list1, const List *list2);
+pg_nodiscard extern List *list_concat_unique_int(List *list1, const List *list2);
+pg_nodiscard extern List *list_concat_unique_oid(List *list1, const List *list2);
 
 extern void list_deduplicate_oid(List *list);
 
 extern void list_free(List *list);
 extern void list_free_deep(List *list);
 
-extern pg_nodiscard List *list_copy(const List *oldlist);
-extern pg_nodiscard List *list_copy_head(const List *oldlist, int len);
-extern pg_nodiscard List *list_copy_tail(const List *oldlist, int nskip);
-extern pg_nodiscard List *list_copy_deep(const List *oldlist);
+pg_nodiscard extern List *list_copy(const List *oldlist);
+pg_nodiscard extern List *list_copy_head(const List *oldlist, int len);
+pg_nodiscard extern List *list_copy_tail(const List *oldlist, int nskip);
+pg_nodiscard extern List *list_copy_deep(const List *oldlist);
 
 typedef int (*list_sort_comparator) (const ListCell *a, const ListCell *b);
 extern void list_sort(List *list, list_sort_comparator cmp);
diff --git a/src/include/storage/buffile.h b/src/include/storage/buffile.h
index 5f6d7c8e3ff..19356dc779b 100644
--- a/src/include/storage/buffile.h
+++ b/src/include/storage/buffile.h
@@ -38,7 +38,7 @@ typedef struct BufFile BufFile;
 
 extern BufFile *BufFileCreateTemp(bool interXact);
 extern void BufFileClose(BufFile *file);
-extern pg_nodiscard size_t BufFileRead(BufFile *file, void *ptr, size_t size);
+pg_nodiscard extern size_t BufFileRead(BufFile *file, void *ptr, size_t size);
 extern void BufFileReadExact(BufFile *file, void *ptr, size_t size);
 extern size_t BufFileReadMaybeEOF(BufFile *file, void *ptr, size_t size, bool eofOK);
 extern void BufFileWrite(BufFile *file, const void *ptr, size_t size);
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 840b0fe57ff..4c56f487806 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -440,7 +440,7 @@ extern ArrayType *GUCArrayDelete(ArrayType *array, const char *name);
 extern ArrayType *GUCArrayReset(ArrayType *array);
 
 extern void *guc_malloc(int elevel, size_t size);
-extern pg_nodiscard void *guc_realloc(int elevel, void *old, size_t size);
+pg_nodiscard extern void *guc_realloc(int elevel, void *old, size_t size);
 extern char *guc_strdup(int elevel, const char *src);
 extern void guc_free(void *ptr);
 
diff --git a/src/include/utils/palloc.h b/src/include/utils/palloc.h
index 773a5d2c347..94024b48065 100644
--- a/src/include/utils/palloc.h
+++ b/src/include/utils/palloc.h
@@ -79,10 +79,10 @@ extern void *palloc(Size size);
 extern void *palloc0(Size size);
 extern void *palloc_extended(Size size, int flags);
 extern void *palloc_aligned(Size size, Size alignto, int flags);
-extern pg_nodiscard void *repalloc(void *pointer, Size size);
-extern pg_nodiscard void *repalloc_extended(void *pointer,
+pg_nodiscard extern void *repalloc(void *pointer, Size size);
+pg_nodiscard extern void *repalloc_extended(void *pointer,
 											Size size, int flags);
-extern pg_nodiscard void *repalloc0(void *pointer, Size oldsize, Size size);
+pg_nodiscard extern void *repalloc0(void *pointer, Size oldsize, Size size);
 extern void pfree(void *pointer);
 
 /*
@@ -110,7 +110,7 @@ extern void pfree(void *pointer);
 
 /* Higher-limit allocators. */
 extern void *MemoryContextAllocHuge(MemoryContext context, Size size);
-extern pg_nodiscard void *repalloc_huge(void *pointer, Size size);
+pg_nodiscard extern void *repalloc_huge(void *pointer, Size size);
 
 /*
  * Although this header file is nominally backend-only, certain frontend
-- 
2.47.1

0004-Support-pg_nodiscard-on-non-GNU-compilers-that-suppo.patchtext/plain; charset=UTF-8; name=0004-Support-pg_nodiscard-on-non-GNU-compilers-that-suppo.patchDownload
From 181ba6f67169d3fe80026b37adceea1f484218ee Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Sat, 28 Dec 2024 11:00:24 +0100
Subject: [PATCH 4/4] Support pg_nodiscard on non-GNU compilers that support
 C23

Support pg_nodiscard on compilers that support C23 attribute syntax.
Previously, only GCC-compatible compilers were supported.

Also, define pg_noreturn similarly using C23 attribute syntax if the
compiler supports C23.  This doesn't have much of an effect right now,
since all compilers that support C23 surely also support the existing
C11-compatible code.  But it keeps pg_nodiscard and pg_noreturn
consistent.
---
 src/include/c.h | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/src/include/c.h b/src/include/c.h
index eee2f476cb7..0c802f4ea82 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -132,11 +132,11 @@
 
 /*
  * pg_nodiscard means the compiler should warn if the result of a function
- * call is ignored.  The name "nodiscard" is chosen in alignment with
- * (possibly future) C and C++ standards.  For maximum compatibility, use it
- * as a function declaration specifier, so it goes before the return type.
+ * call is ignored.
  */
-#ifdef __GNUC__
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
+#define pg_nodiscard [[__nodiscard__]]
+#elif defined(__GNUC__)
 #define pg_nodiscard __attribute__((warn_unused_result))
 #else
 #define pg_nodiscard
@@ -148,7 +148,9 @@
  * uses __attribute__((noreturn)) in headers, which would get confused if
  * "noreturn" is defined to "_Noreturn", as is done by <stdnoreturn.h>.
  */
-#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
+#define pg_noreturn [[__noreturn__]]
+#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
 #define pg_noreturn _Noreturn
 #elif defined(__GNUC__)
 #define pg_noreturn __attribute__((noreturn))
-- 
2.47.1

In reply to: Peter Eisentraut (#7)
Re: pg_attribute_noreturn(), MSVC, C11

Peter Eisentraut <peter@eisentraut.org> writes:

I suggest we define pg_noreturn as

1. If C11 is supported, then _Noreturn, else
2. If GCC-compatible, then __attribute__((noreturn)), else

Would it be worth also checking __has_attribute(noreturn)? Or do all
compilers that have __attribute__((noreturn)) claim to be GCC?

3. If MSVC, then __declspec((noreturn))

- ilmari

#9Peter Eisentraut
peter@eisentraut.org
In reply to: Dagfinn Ilmari Mannsåker (#8)
Re: pg_attribute_noreturn(), MSVC, C11

On 03.01.25 21:51, Dagfinn Ilmari Mannsåker wrote:

Peter Eisentraut <peter@eisentraut.org> writes:

I suggest we define pg_noreturn as

1. If C11 is supported, then _Noreturn, else
2. If GCC-compatible, then __attribute__((noreturn)), else

Would it be worth also checking __has_attribute(noreturn)? Or do all
compilers that have __attribute__((noreturn)) claim to be GCC?

I don't think that would expand the set of supported compilers in a
significant way. We can always add it if we find one, of course.

Show quoted text

3. If MSVC, then __declspec((noreturn))

#10Peter Eisentraut
peter@eisentraut.org
In reply to: Peter Eisentraut (#9)
Re: pg_attribute_noreturn(), MSVC, C11

On 06.01.25 15:52, Peter Eisentraut wrote:

On 03.01.25 21:51, Dagfinn Ilmari Mannsåker wrote:

Peter Eisentraut <peter@eisentraut.org> writes:

I suggest we define pg_noreturn as

1. If C11 is supported, then _Noreturn, else
2. If GCC-compatible, then __attribute__((noreturn)), else

Would it be worth also checking __has_attribute(noreturn)?  Or do all
compilers that have __attribute__((noreturn)) claim to be GCC?

I don't think that would expand the set of supported compilers in a
significant way.  We can always add it if we find one, of course.

In fact, as another thought, we could even drop #2. Among the
GCC-compatible compilers, both GCC and Clang have supported #1 for ages,
and the only other candidate I could find on the build farm is the
Solaris compiler, which also supports C11 by default, per its documentation.

Show quoted text

3. If MSVC, then __declspec((noreturn))

#11Peter Eisentraut
peter@eisentraut.org
In reply to: Peter Eisentraut (#10)
4 attachment(s)
Re: pg_attribute_noreturn(), MSVC, C11

On 22.01.25 19:16, Peter Eisentraut wrote:

On 06.01.25 15:52, Peter Eisentraut wrote:

On 03.01.25 21:51, Dagfinn Ilmari Mannsåker wrote:

Peter Eisentraut <peter@eisentraut.org> writes:

I suggest we define pg_noreturn as

1. If C11 is supported, then _Noreturn, else
2. If GCC-compatible, then __attribute__((noreturn)), else

Would it be worth also checking __has_attribute(noreturn)?  Or do all
compilers that have __attribute__((noreturn)) claim to be GCC?

I don't think that would expand the set of supported compilers in a
significant way.  We can always add it if we find one, of course.

In fact, as another thought, we could even drop #2.  Among the GCC-
compatible compilers, both GCC and Clang have supported #1 for ages, and
the only other candidate I could find on the build farm is the Solaris
compiler, which also supports C11 by default, per its documentation.

3. If MSVC, then __declspec((noreturn))

Here is an updated patch set that contains the above small change and
fixes some conflicts that have arisen in the meantime.

Attachments:

v2-0001-pg_noreturn-to-replace-pg_attribute_noreturn.patchtext/plain; charset=UTF-8; name=v2-0001-pg_noreturn-to-replace-pg_attribute_noreturn.patchDownload
From 8464526cede39d032f52239c5dcdfdbada189691 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Thu, 13 Feb 2025 16:01:06 +0100
Subject: [PATCH v2 1/4] pg_noreturn to replace pg_attribute_noreturn()

We want to support a "noreturn" decoration on more compilers besides
just GCC-compatible ones, but for that we need to move the decoration
in front of the function declaration instead of either behind it or
wherever, which is the current style afforded by GCC-style attributes.
Also rename the macro to "pg_noreturn" to be similar to the C11
standard "noreturn".

pg_noreturn is now supported on all compilers that support C11 (using
_Noreturn), as well as MSVC (using __declspec).  (When PostgreSQL
requires C11, the latter variant can be dropped.)  (We don't need the
previously used variant for GCC-compatible compilers using
__attribute__, because all reasonable candidates already support C11,
so that variant would be dead code in practice.)

Now, all supported compilers effectively support pg_noreturn, so the
extra code for !HAVE_PG_ATTRIBUTE_NORETURN can be dropped.

This also fixes a possible problem if third-party code includes
stdnoreturn.h, because then the current definition of

    #define pg_attribute_noreturn() __attribute__((noreturn))

would cause an error.

Note that the C standard does not support a noreturn attribute on
function pointer types.  So we have to drop these here.  There are
only two instances at this time, so it's not a big loss.

Discussion: https://www.postgresql.org/message-id/flat/pxr5b3z7jmkpenssra5zroxi7qzzp6eswuggokw64axmdixpnk@zbwxuq7gbbcw
---
 contrib/dblink/dblink.c                       |  6 ++--
 contrib/pgcrypto/px.h                         |  2 +-
 src/backend/access/transam/xlogrecovery.c     |  3 +-
 src/backend/backup/basebackup_incremental.c   |  6 ++--
 src/backend/postmaster/autovacuum.c           |  2 +-
 src/backend/postmaster/launch_backend.c       |  2 +-
 src/backend/postmaster/postmaster.c           |  2 +-
 src/backend/replication/logical/tablesync.c   |  3 +-
 src/backend/replication/walsender.c           |  2 +-
 src/backend/utils/adt/ri_triggers.c           |  8 +++---
 src/backend/utils/fmgr/dfmgr.c                |  4 +--
 src/backend/utils/hash/dynahash.c             |  2 +-
 src/backend/utils/mmgr/slab.c                 |  2 +-
 src/bin/pg_combinebackup/load_manifest.c      |  6 ++--
 src/bin/pg_dump/pg_backup_utils.h             |  2 +-
 src/bin/pg_upgrade/pg_upgrade.h               |  2 +-
 src/bin/pg_verifybackup/pg_verifybackup.c     |  6 ++--
 src/bin/pg_verifybackup/pg_verifybackup.h     |  4 +--
 src/bin/pgbench/pgbench.h                     | 12 ++++----
 src/include/bootstrap/bootstrap.h             |  4 +--
 src/include/c.h                               | 28 ++++++++++++-------
 src/include/commands/defrem.h                 |  2 +-
 src/include/common/parse_manifest.h           |  3 +-
 src/include/mb/pg_wchar.h                     |  6 ++--
 src/include/parser/parse_relation.h           |  6 ++--
 src/include/parser/scanner.h                  |  2 +-
 src/include/postmaster/autovacuum.h           |  4 +--
 src/include/postmaster/bgworker_internals.h   |  2 +-
 src/include/postmaster/bgwriter.h             |  4 +--
 src/include/postmaster/pgarch.h               |  2 +-
 src/include/postmaster/postmaster.h           |  4 +--
 src/include/postmaster/startup.h              |  2 +-
 src/include/postmaster/syslogger.h            |  2 +-
 src/include/postmaster/walsummarizer.h        |  2 +-
 src/include/postmaster/walwriter.h            |  2 +-
 src/include/replication/slotsync.h            |  2 +-
 src/include/replication/walreceiver.h         |  2 +-
 src/include/replication/walsender_private.h   |  2 +-
 src/include/storage/ipc.h                     |  2 +-
 src/include/storage/lock.h                    |  2 +-
 src/include/tcop/backend_startup.h            |  2 +-
 src/include/tcop/tcopprot.h                   | 12 ++++----
 src/include/utils/elog.h                      | 13 ++-------
 src/include/utils/float.h                     |  6 ++--
 src/include/utils/help_config.h               |  2 +-
 src/include/utils/memutils_internal.h         |  4 +--
 src/interfaces/ecpg/preproc/preproc_extern.h  |  2 +-
 src/pl/plpgsql/src/plpgsql.h                  |  2 +-
 .../modules/libpq_pipeline/libpq_pipeline.c   |  5 ++--
 src/test/modules/test_shm_mq/test_shm_mq.h    |  2 +-
 src/test/modules/worker_spi/worker_spi.c      |  2 +-
 src/timezone/zic.c                            |  4 +--
 src/tools/pg_bsd_indent/err.h                 |  8 +++---
 53 files changed, 109 insertions(+), 116 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index bed2dee3d72..58c1a6221c8 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -160,8 +160,7 @@ xpstrdup(const char *in)
 	return pstrdup(in);
 }
 
-static void
-pg_attribute_noreturn()
+pg_noreturn static void
 dblink_res_internalerror(PGconn *conn, PGresult *res, const char *p2)
 {
 	char	   *msg = pchomp(PQerrorMessage(conn));
@@ -170,8 +169,7 @@ dblink_res_internalerror(PGconn *conn, PGresult *res, const char *p2)
 	elog(ERROR, "%s: %s", p2, msg);
 }
 
-static void
-pg_attribute_noreturn()
+pg_noreturn static void
 dblink_conn_not_avail(const char *conname)
 {
 	if (conname)
diff --git a/contrib/pgcrypto/px.h b/contrib/pgcrypto/px.h
index 37013cd9f82..4b81fceab8e 100644
--- a/contrib/pgcrypto/px.h
+++ b/contrib/pgcrypto/px.h
@@ -181,7 +181,7 @@ int			px_find_hmac(const char *name, PX_HMAC **res);
 int			px_find_cipher(const char *name, PX_Cipher **res);
 int			px_find_combo(const char *name, PX_Combo **res);
 
-void		px_THROW_ERROR(int err) pg_attribute_noreturn();
+pg_noreturn void px_THROW_ERROR(int err);
 const char *px_strerror(int err);
 
 const char *px_resolve_alias(const PX_Alias *list, const char *name);
diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index 473de6710d7..efc628fb43c 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -4776,8 +4776,7 @@ check_primary_slot_name(char **newval, void **extra, GucSource source)
  * that we have odd behaviors such as unexpected GUC ordering dependencies.
  */
 
-static void
-pg_attribute_noreturn()
+pg_noreturn static void
 error_multiple_recovery_targets(void)
 {
 	ereport(ERROR,
diff --git a/src/backend/backup/basebackup_incremental.c b/src/backend/backup/basebackup_incremental.c
index 360711fadb8..1172c1ea528 100644
--- a/src/backend/backup/basebackup_incremental.c
+++ b/src/backend/backup/basebackup_incremental.c
@@ -139,9 +139,9 @@ static void manifest_process_wal_range(JsonManifestParseContext *context,
 									   TimeLineID tli,
 									   XLogRecPtr start_lsn,
 									   XLogRecPtr end_lsn);
-static void manifest_report_error(JsonManifestParseContext *context,
-								  const char *fmt,...)
-			pg_attribute_printf(2, 3) pg_attribute_noreturn();
+pg_noreturn static void manifest_report_error(JsonManifestParseContext *context,
+											  const char *fmt,...)
+			pg_attribute_printf(2, 3);
 static int	compare_block_numbers(const void *a, const void *b);
 
 /*
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index ade2708b59e..fcc6756b2b8 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -317,7 +317,7 @@ int			AutovacuumLauncherPid = 0;
 
 static Oid	do_start_worker(void);
 static void HandleAutoVacLauncherInterrupts(void);
-static void AutoVacLauncherShutdown(void) pg_attribute_noreturn();
+pg_noreturn static void AutoVacLauncherShutdown(void);
 static void launcher_determine_sleep(bool canlaunch, bool recursing,
 									 struct timeval *nap);
 static void launch_worker(TimestampTz now);
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index a97a1eda6da..3d583211c8a 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -171,7 +171,7 @@ static pid_t internal_forkexec(const char *child_kind, int child_slot,
 typedef struct
 {
 	const char *name;
-	void		(*main_fn) (char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+	void		(*main_fn) (char *startup_data, size_t startup_data_len);
 	bool		shmem_attach;
 } child_process_kind;
 
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index bb22b13adef..9429da0b77b 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -426,7 +426,7 @@ static void LogChildExit(int lev, const char *procname,
 static void PostmasterStateMachine(void);
 static void UpdatePMState(PMState newState);
 
-static void ExitPostmaster(int status) pg_attribute_noreturn();
+pg_noreturn static void ExitPostmaster(int status);
 static int	ServerLoop(void);
 static int	BackendStartup(ClientSocket *client_sock);
 static void report_fork_failure_to_client(ClientSocket *client_sock, int errnum);
diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c
index 6af5c9fe16c..65b98aa905f 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -139,8 +139,7 @@ static StringInfo copybuf = NULL;
 /*
  * Exit routine for synchronization worker.
  */
-static void
-pg_attribute_noreturn()
+pg_noreturn static void
 finish_sync_worker(void)
 {
 	/*
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 446d10c1a7d..d96121b3aad 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -237,7 +237,7 @@ typedef void (*WalSndSendDataCallback) (void);
 static void WalSndLoop(WalSndSendDataCallback send_data);
 static void InitWalSenderSlot(void);
 static void WalSndKill(int code, Datum arg);
-static void WalSndShutdown(void) pg_attribute_noreturn();
+pg_noreturn static void WalSndShutdown(void);
 static void XLogSendPhysical(void);
 static void XLogSendLogical(void);
 static void WalSndDone(WalSndSendDataCallback send_data);
diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c
index 8473448849c..c4ff18ce65e 100644
--- a/src/backend/utils/adt/ri_triggers.c
+++ b/src/backend/utils/adt/ri_triggers.c
@@ -235,10 +235,10 @@ static bool ri_PerformCheck(const RI_ConstraintInfo *riinfo,
 static void ri_ExtractValues(Relation rel, TupleTableSlot *slot,
 							 const RI_ConstraintInfo *riinfo, bool rel_is_pk,
 							 Datum *vals, char *nulls);
-static void ri_ReportViolation(const RI_ConstraintInfo *riinfo,
-							   Relation pk_rel, Relation fk_rel,
-							   TupleTableSlot *violatorslot, TupleDesc tupdesc,
-							   int queryno, bool is_restrict, bool partgone) pg_attribute_noreturn();
+pg_noreturn static void ri_ReportViolation(const RI_ConstraintInfo *riinfo,
+										   Relation pk_rel, Relation fk_rel,
+										   TupleTableSlot *violatorslot, TupleDesc tupdesc,
+										   int queryno, bool is_restrict, bool partgone);
 
 
 /*
diff --git a/src/backend/utils/fmgr/dfmgr.c b/src/backend/utils/fmgr/dfmgr.c
index 87b233cb887..4409e3e6fa8 100644
--- a/src/backend/utils/fmgr/dfmgr.c
+++ b/src/backend/utils/fmgr/dfmgr.c
@@ -67,8 +67,8 @@ static DynamicFileList *file_tail = NULL;
 char	   *Dynamic_library_path;
 
 static void *internal_load_library(const char *libname);
-static void incompatible_module_error(const char *libname,
-									  const Pg_magic_struct *module_magic_data) pg_attribute_noreturn();
+pg_noreturn static void incompatible_module_error(const char *libname,
+												  const Pg_magic_struct *module_magic_data);
 static char *expand_dynamic_library_name(const char *name);
 static void check_restricted_library_name(const char *name);
 static char *substitute_libpath_macro(const char *name);
diff --git a/src/backend/utils/hash/dynahash.c b/src/backend/utils/hash/dynahash.c
index cd5a00132fc..3f25929f2d8 100644
--- a/src/backend/utils/hash/dynahash.c
+++ b/src/backend/utils/hash/dynahash.c
@@ -272,7 +272,7 @@ static HASHBUCKET get_hash_entry(HTAB *hashp, int freelist_idx);
 static void hdefault(HTAB *hashp);
 static int	choose_nelem_alloc(Size entrysize);
 static bool init_htab(HTAB *hashp, long nelem);
-static void hash_corrupted(HTAB *hashp) pg_attribute_noreturn();
+pg_noreturn static void hash_corrupted(HTAB *hashp);
 static uint32 hash_initial_lookup(HTAB *hashp, uint32 hashvalue,
 								  HASHBUCKET **bucketptr);
 static long next_pow2_long(long num);
diff --git a/src/backend/utils/mmgr/slab.c b/src/backend/utils/mmgr/slab.c
index ec8eddad863..d32c0d318fb 100644
--- a/src/backend/utils/mmgr/slab.c
+++ b/src/backend/utils/mmgr/slab.c
@@ -601,8 +601,8 @@ SlabAllocFromNewBlock(MemoryContext context, Size size, int flags)
  *		want to avoid that.
  */
 pg_noinline
+pg_noreturn
 static void
-pg_attribute_noreturn()
 SlabAllocInvalidSize(MemoryContext context, Size size)
 {
 	SlabContext *slab = (SlabContext *) context;
diff --git a/src/bin/pg_combinebackup/load_manifest.c b/src/bin/pg_combinebackup/load_manifest.c
index 485fe518e41..8e0d04a26a6 100644
--- a/src/bin/pg_combinebackup/load_manifest.c
+++ b/src/bin/pg_combinebackup/load_manifest.c
@@ -68,9 +68,9 @@ static void combinebackup_per_wal_range_cb(JsonManifestParseContext *context,
 										   TimeLineID tli,
 										   XLogRecPtr start_lsn,
 										   XLogRecPtr end_lsn);
-static void report_manifest_error(JsonManifestParseContext *context,
-								  const char *fmt,...)
-			pg_attribute_printf(2, 3) pg_attribute_noreturn();
+pg_noreturn static void report_manifest_error(JsonManifestParseContext *context,
+											  const char *fmt,...)
+			pg_attribute_printf(2, 3);
 
 /*
  * Load backup_manifest files from an array of backups and produces an array
diff --git a/src/bin/pg_dump/pg_backup_utils.h b/src/bin/pg_dump/pg_backup_utils.h
index 38551944513..ba042016879 100644
--- a/src/bin/pg_dump/pg_backup_utils.h
+++ b/src/bin/pg_dump/pg_backup_utils.h
@@ -29,7 +29,7 @@ extern const char *progname;
 
 extern void set_dump_section(const char *arg, int *dumpSections);
 extern void on_exit_nicely(on_exit_nicely_callback function, void *arg);
-extern void exit_nicely(int code) pg_attribute_noreturn();
+pg_noreturn extern void exit_nicely(int code);
 
 /* In pg_dump, we modify pg_fatal to call exit_nicely instead of exit */
 #undef pg_fatal
diff --git a/src/bin/pg_upgrade/pg_upgrade.h b/src/bin/pg_upgrade/pg_upgrade.h
index 0cdd675e4f1..0f5dbe57097 100644
--- a/src/bin/pg_upgrade/pg_upgrade.h
+++ b/src/bin/pg_upgrade/pg_upgrade.h
@@ -471,7 +471,7 @@ int			get_user_info(char **user_name_p);
 void		check_ok(void);
 void		report_status(eLogType type, const char *fmt,...) pg_attribute_printf(2, 3);
 void		pg_log(eLogType type, const char *fmt,...) pg_attribute_printf(2, 3);
-void		pg_fatal(const char *fmt,...) pg_attribute_printf(1, 2) pg_attribute_noreturn();
+pg_noreturn void pg_fatal(const char *fmt,...) pg_attribute_printf(1, 2);
 void		end_progress_output(void);
 void		cleanup_output_dirs(void);
 void		prep_status(const char *fmt,...) pg_attribute_printf(1, 2);
diff --git a/src/bin/pg_verifybackup/pg_verifybackup.c b/src/bin/pg_verifybackup/pg_verifybackup.c
index 7c720ab98bd..84edd2cdca5 100644
--- a/src/bin/pg_verifybackup/pg_verifybackup.c
+++ b/src/bin/pg_verifybackup/pg_verifybackup.c
@@ -69,9 +69,9 @@ static void verifybackup_per_wal_range_cb(JsonManifestParseContext *context,
 										  TimeLineID tli,
 										  XLogRecPtr start_lsn,
 										  XLogRecPtr end_lsn);
-static void report_manifest_error(JsonManifestParseContext *context,
-								  const char *fmt,...)
-			pg_attribute_printf(2, 3) pg_attribute_noreturn();
+pg_noreturn static void report_manifest_error(JsonManifestParseContext *context,
+											  const char *fmt,...)
+			pg_attribute_printf(2, 3);
 
 static void verify_tar_backup(verifier_context *context, DIR *dir);
 static void verify_plain_backup_directory(verifier_context *context,
diff --git a/src/bin/pg_verifybackup/pg_verifybackup.h b/src/bin/pg_verifybackup/pg_verifybackup.h
index 622c9d82a81..8cb6f9c53ad 100644
--- a/src/bin/pg_verifybackup/pg_verifybackup.h
+++ b/src/bin/pg_verifybackup/pg_verifybackup.h
@@ -98,8 +98,8 @@ typedef struct verifier_context
 extern void report_backup_error(verifier_context *context,
 								const char *pg_restrict fmt,...)
 			pg_attribute_printf(2, 3);
-extern void report_fatal_error(const char *pg_restrict fmt,...)
-			pg_attribute_printf(1, 2) pg_attribute_noreturn();
+pg_noreturn extern void report_fatal_error(const char *pg_restrict fmt,...)
+			pg_attribute_printf(1, 2);
 extern bool should_ignore_relpath(verifier_context *context,
 								  const char *relpath);
 
diff --git a/src/bin/pgbench/pgbench.h b/src/bin/pgbench/pgbench.h
index f6a883611c5..566db4c7bf9 100644
--- a/src/bin/pgbench/pgbench.h
+++ b/src/bin/pgbench/pgbench.h
@@ -140,9 +140,9 @@ struct PgBenchExprList
 
 extern int	expr_yyparse(PgBenchExpr **expr_parse_result_p, yyscan_t yyscanner);
 extern int	expr_yylex(union YYSTYPE *yylval_param, yyscan_t yyscanner);
-extern void expr_yyerror(PgBenchExpr **expr_parse_result_p, yyscan_t yyscanner, const char *message) pg_attribute_noreturn();
-extern void expr_yyerror_more(yyscan_t yyscanner, const char *message,
-							  const char *more) pg_attribute_noreturn();
+pg_noreturn extern void expr_yyerror(PgBenchExpr **expr_parse_result_p, yyscan_t yyscanner, const char *message);
+pg_noreturn extern void expr_yyerror_more(yyscan_t yyscanner, const char *message,
+										  const char *more);
 extern bool expr_lex_one_word(PsqlScanState state, PQExpBuffer word_buf,
 							  int *offset);
 extern yyscan_t expr_scanner_init(PsqlScanState state,
@@ -155,9 +155,9 @@ extern char *expr_scanner_get_substring(PsqlScanState state,
 										bool chomp);
 extern int	expr_scanner_get_lineno(PsqlScanState state, int offset);
 
-extern void syntax_error(const char *source, int lineno, const char *line,
-						 const char *command, const char *msg,
-						 const char *more, int column) pg_attribute_noreturn();
+pg_noreturn extern void syntax_error(const char *source, int lineno, const char *line,
+									 const char *command, const char *msg,
+									 const char *more, int column);
 
 extern bool strtoint64(const char *str, bool errorOK, int64 *result);
 extern bool strtodouble(const char *str, bool errorOK, double *dv);
diff --git a/src/include/bootstrap/bootstrap.h b/src/include/bootstrap/bootstrap.h
index 69f3d31a4ef..befc4fa1b3d 100644
--- a/src/include/bootstrap/bootstrap.h
+++ b/src/include/bootstrap/bootstrap.h
@@ -33,7 +33,7 @@ extern PGDLLIMPORT Form_pg_attribute attrtypes[MAXATTR];
 extern PGDLLIMPORT int numattr;
 
 
-extern void BootstrapModeMain(int argc, char *argv[], bool check_only) pg_attribute_noreturn();
+pg_noreturn extern void BootstrapModeMain(int argc, char *argv[], bool check_only);
 
 extern void closerel(char *relname);
 extern void boot_openrel(char *relname);
@@ -64,6 +64,6 @@ typedef void *yyscan_t;
 extern int	boot_yyparse(yyscan_t yyscanner);
 extern int	boot_yylex_init(yyscan_t *yyscannerp);
 extern int	boot_yylex(union YYSTYPE *yylval_param, yyscan_t yyscanner);
-extern void boot_yyerror(yyscan_t yyscanner, const char *message) pg_attribute_noreturn();
+pg_noreturn extern void boot_yyerror(yyscan_t yyscanner, const char *message);
 
 #endif							/* BOOTSTRAP_H */
diff --git a/src/include/c.h b/src/include/c.h
index a14c6315162..d42548cb1c1 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -145,6 +145,20 @@
 #define pg_nodiscard
 #endif
 
+/*
+ * pg_noreturn corresponds to the C11 noreturn/_Noreturn function specifier.
+ * We can't use the standard name "noreturn" because some third-party code
+ * uses __attribute__((noreturn)) in headers, which would get confused if
+ * "noreturn" is defined to "_Noreturn", as is done by <stdnoreturn.h>.
+ */
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
+#define pg_noreturn _Noreturn
+#elif defined(_MSC_VER)
+#define pg_noreturn __declspec(noreturn)
+#else
+#define pg_noreturn
+#endif
+
 /*
  * This macro will disable address safety instrumentation for a function
  * when running with "-fsanitize=address". Think twice before using this!
@@ -213,30 +227,24 @@
 #define pg_attribute_printf(f,a)
 #endif
 
-/* GCC and Sunpro support aligned, packed and noreturn */
+/* GCC and Sunpro support aligned and packed */
 #if defined(__GNUC__) || defined(__SUNPRO_C)
 #define pg_attribute_aligned(a) __attribute__((aligned(a)))
-#define pg_attribute_noreturn() __attribute__((noreturn))
 #define pg_attribute_packed() __attribute__((packed))
-#define HAVE_PG_ATTRIBUTE_NORETURN 1
 #elif defined(_MSC_VER)
 /*
- * MSVC supports aligned.  noreturn is also possible but in MSVC it is
- * declared before the definition while pg_attribute_noreturn() macro
- * is currently used after the definition.
+ * MSVC supports aligned.
  *
  * Packing is also possible but only by wrapping the entire struct definition
  * which doesn't fit into our current macro declarations.
  */
 #define pg_attribute_aligned(a) __declspec(align(a))
-#define pg_attribute_noreturn()
 #else
 /*
  * NB: aligned and packed are not given default definitions because they
  * affect code functionality; they *must* be implemented by the compiler
  * if they are to be used.
  */
-#define pg_attribute_noreturn()
 #endif
 
 /*
@@ -858,8 +866,8 @@ typedef NameData *Name;
  * we should declare it as long as !FRONTEND.
  */
 #ifndef FRONTEND
-extern void ExceptionalCondition(const char *conditionName,
-								 const char *fileName, int lineNumber) pg_attribute_noreturn();
+pg_noreturn extern void ExceptionalCondition(const char *conditionName,
+											 const char *fileName, int lineNumber);
 #endif
 
 /*
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index 6d9348bac80..dd22b5efdfd 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -160,6 +160,6 @@ extern List *defGetQualifiedName(DefElem *def);
 extern TypeName *defGetTypeName(DefElem *def);
 extern int	defGetTypeLength(DefElem *def);
 extern List *defGetStringList(DefElem *def);
-extern void errorConflictingDefElem(DefElem *defel, ParseState *pstate) pg_attribute_noreturn();
+pg_noreturn extern void errorConflictingDefElem(DefElem *defel, ParseState *pstate);
 
 #endif							/* DEFREM_H */
diff --git a/src/include/common/parse_manifest.h b/src/include/common/parse_manifest.h
index 255cab5c2a9..6172d1d5224 100644
--- a/src/include/common/parse_manifest.h
+++ b/src/include/common/parse_manifest.h
@@ -34,8 +34,7 @@ typedef void (*json_manifest_per_wal_range_callback) (JsonManifestParseContext *
 													  TimeLineID tli,
 													  XLogRecPtr start_lsn, XLogRecPtr end_lsn);
 typedef void (*json_manifest_error_callback) (JsonManifestParseContext *,
-											  const char *fmt,...) pg_attribute_printf(2, 3)
-			pg_attribute_noreturn();
+											  const char *fmt,...) pg_attribute_printf(2, 3);
 
 struct JsonManifestParseContext
 {
diff --git a/src/include/mb/pg_wchar.h b/src/include/mb/pg_wchar.h
index ff7983ee90a..bfef95baea2 100644
--- a/src/include/mb/pg_wchar.h
+++ b/src/include/mb/pg_wchar.h
@@ -768,9 +768,9 @@ extern void check_encoding_conversion_args(int src_encoding,
 										   int expected_src_encoding,
 										   int expected_dest_encoding);
 
-extern void report_invalid_encoding(int encoding, const char *mbstr, int len) pg_attribute_noreturn();
-extern void report_untranslatable_char(int src_encoding, int dest_encoding,
-									   const char *mbstr, int len) pg_attribute_noreturn();
+pg_noreturn extern void report_invalid_encoding(int encoding, const char *mbstr, int len);
+pg_noreturn extern void report_untranslatable_char(int src_encoding, int dest_encoding,
+												   const char *mbstr, int len);
 
 extern int	local2local(const unsigned char *l, unsigned char *p, int len,
 						int src_encoding, int dest_encoding,
diff --git a/src/include/parser/parse_relation.h b/src/include/parser/parse_relation.h
index 3ece5cd4eef..d59599cf242 100644
--- a/src/include/parser/parse_relation.h
+++ b/src/include/parser/parse_relation.h
@@ -110,9 +110,9 @@ extern bool isLockedRefname(ParseState *pstate, const char *refname);
 extern void addNSItemToQuery(ParseState *pstate, ParseNamespaceItem *nsitem,
 							 bool addToJoinList,
 							 bool addToRelNameSpace, bool addToVarNameSpace);
-extern void errorMissingRTE(ParseState *pstate, RangeVar *relation) pg_attribute_noreturn();
-extern void errorMissingColumn(ParseState *pstate,
-							   const char *relname, const char *colname, int location) pg_attribute_noreturn();
+pg_noreturn extern void errorMissingRTE(ParseState *pstate, RangeVar *relation);
+pg_noreturn extern void errorMissingColumn(ParseState *pstate,
+										   const char *relname, const char *colname, int location);
 extern void expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
 					  VarReturningType returning_type,
 					  int location, bool include_dropped,
diff --git a/src/include/parser/scanner.h b/src/include/parser/scanner.h
index 74ad86698ac..8d202d5b284 100644
--- a/src/include/parser/scanner.h
+++ b/src/include/parser/scanner.h
@@ -145,6 +145,6 @@ extern void setup_scanner_errposition_callback(ScannerCallbackState *scbstate,
 											   core_yyscan_t yyscanner,
 											   int location);
 extern void cancel_scanner_errposition_callback(ScannerCallbackState *scbstate);
-extern void scanner_yyerror(const char *message, core_yyscan_t yyscanner) pg_attribute_noreturn();
+pg_noreturn extern void scanner_yyerror(const char *message, core_yyscan_t yyscanner);
 
 #endif							/* SCANNER_H */
diff --git a/src/include/postmaster/autovacuum.h b/src/include/postmaster/autovacuum.h
index 06d4a593575..ce7bd0df433 100644
--- a/src/include/postmaster/autovacuum.h
+++ b/src/include/postmaster/autovacuum.h
@@ -58,8 +58,8 @@ extern void autovac_init(void);
 /* called from postmaster when a worker could not be forked */
 extern void AutoVacWorkerFailed(void);
 
-extern void AutoVacLauncherMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
-extern void AutoVacWorkerMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+pg_noreturn extern void AutoVacLauncherMain(char *startup_data, size_t startup_data_len);
+pg_noreturn extern void AutoVacWorkerMain(char *startup_data, size_t startup_data_len);
 
 extern bool AutoVacuumRequestWork(AutoVacuumWorkItemType type,
 								  Oid relationId, BlockNumber blkno);
diff --git a/src/include/postmaster/bgworker_internals.h b/src/include/postmaster/bgworker_internals.h
index 092b1610663..a26212d4746 100644
--- a/src/include/postmaster/bgworker_internals.h
+++ b/src/include/postmaster/bgworker_internals.h
@@ -52,6 +52,6 @@ extern void ForgetUnstartedBackgroundWorkers(void);
 extern void ResetBackgroundWorkerCrashTimes(void);
 
 /* Entry point for background worker processes */
-extern void BackgroundWorkerMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+pg_noreturn extern void BackgroundWorkerMain(char *startup_data, size_t startup_data_len);
 
 #endif							/* BGWORKER_INTERNALS_H */
diff --git a/src/include/postmaster/bgwriter.h b/src/include/postmaster/bgwriter.h
index 2d5854e6879..30fbcd54dc8 100644
--- a/src/include/postmaster/bgwriter.h
+++ b/src/include/postmaster/bgwriter.h
@@ -27,8 +27,8 @@ extern PGDLLIMPORT int CheckPointTimeout;
 extern PGDLLIMPORT int CheckPointWarning;
 extern PGDLLIMPORT double CheckPointCompletionTarget;
 
-extern void BackgroundWriterMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
-extern void CheckpointerMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+pg_noreturn extern void BackgroundWriterMain(char *startup_data, size_t startup_data_len);
+pg_noreturn extern void CheckpointerMain(char *startup_data, size_t startup_data_len);
 
 extern void RequestCheckpoint(int flags);
 extern void CheckpointWriteDelay(int flags, double progress);
diff --git a/src/include/postmaster/pgarch.h b/src/include/postmaster/pgarch.h
index 8fc6bfeec1b..66a111f6f65 100644
--- a/src/include/postmaster/pgarch.h
+++ b/src/include/postmaster/pgarch.h
@@ -29,7 +29,7 @@
 extern Size PgArchShmemSize(void);
 extern void PgArchShmemInit(void);
 extern bool PgArchCanRestart(void);
-extern void PgArchiverMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+pg_noreturn extern void PgArchiverMain(char *startup_data, size_t startup_data_len);
 extern void PgArchWakeup(void);
 extern void PgArchForceDirScan(void);
 
diff --git a/src/include/postmaster/postmaster.h b/src/include/postmaster/postmaster.h
index 188a06e2379..b8a10a9723d 100644
--- a/src/include/postmaster/postmaster.h
+++ b/src/include/postmaster/postmaster.h
@@ -91,7 +91,7 @@ extern PGDLLIMPORT const char *progname;
 extern PGDLLIMPORT bool redirection_done;
 extern PGDLLIMPORT bool LoadedSSL;
 
-extern void PostmasterMain(int argc, char *argv[]) pg_attribute_noreturn();
+pg_noreturn extern void PostmasterMain(int argc, char *argv[]);
 extern void ClosePostmasterPorts(bool am_syslogger);
 extern void InitProcessGlobals(void);
 
@@ -114,7 +114,7 @@ extern pid_t postmaster_child_launch(BackendType child_type,
 									 struct ClientSocket *client_sock);
 const char *PostmasterChildName(BackendType child_type);
 #ifdef EXEC_BACKEND
-extern void SubPostmasterMain(int argc, char *argv[]) pg_attribute_noreturn();
+pg_noreturn extern void SubPostmasterMain(int argc, char *argv[]);
 #endif
 
 /* defined in pmchild.c */
diff --git a/src/include/postmaster/startup.h b/src/include/postmaster/startup.h
index 736c97d121a..68fcb54eab0 100644
--- a/src/include/postmaster/startup.h
+++ b/src/include/postmaster/startup.h
@@ -26,7 +26,7 @@
 extern PGDLLIMPORT int log_startup_progress_interval;
 
 extern void HandleStartupProcInterrupts(void);
-extern void StartupProcessMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+pg_noreturn extern void StartupProcessMain(char *startup_data, size_t startup_data_len);
 extern void PreRestoreCommand(void);
 extern void PostRestoreCommand(void);
 extern bool IsPromoteSignaled(void);
diff --git a/src/include/postmaster/syslogger.h b/src/include/postmaster/syslogger.h
index e92d8531478..73fb3730be6 100644
--- a/src/include/postmaster/syslogger.h
+++ b/src/include/postmaster/syslogger.h
@@ -90,7 +90,7 @@ extern int	SysLogger_Start(int child_slot);
 
 extern void write_syslogger_file(const char *buffer, int count, int destination);
 
-extern void SysLoggerMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+pg_noreturn extern void SysLoggerMain(char *startup_data, size_t startup_data_len);
 
 extern bool CheckLogrotateSignal(void);
 extern void RemoveLogrotateSignalFiles(void);
diff --git a/src/include/postmaster/walsummarizer.h b/src/include/postmaster/walsummarizer.h
index bfe86663ccb..98898088ef0 100644
--- a/src/include/postmaster/walsummarizer.h
+++ b/src/include/postmaster/walsummarizer.h
@@ -21,7 +21,7 @@ extern PGDLLIMPORT int wal_summary_keep_time;
 
 extern Size WalSummarizerShmemSize(void);
 extern void WalSummarizerShmemInit(void);
-extern void WalSummarizerMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+pg_noreturn extern void WalSummarizerMain(char *startup_data, size_t startup_data_len);
 
 extern void GetWalSummarizerState(TimeLineID *summarized_tli,
 								  XLogRecPtr *summarized_lsn,
diff --git a/src/include/postmaster/walwriter.h b/src/include/postmaster/walwriter.h
index 9fc3c665774..35f13bc9dd7 100644
--- a/src/include/postmaster/walwriter.h
+++ b/src/include/postmaster/walwriter.h
@@ -18,6 +18,6 @@
 extern PGDLLIMPORT int WalWriterDelay;
 extern PGDLLIMPORT int WalWriterFlushAfter;
 
-extern void WalWriterMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+pg_noreturn extern void WalWriterMain(char *startup_data, size_t startup_data_len);
 
 #endif							/* _WALWRITER_H */
diff --git a/src/include/replication/slotsync.h b/src/include/replication/slotsync.h
index 3fad27f0a63..0f2ec1c00de 100644
--- a/src/include/replication/slotsync.h
+++ b/src/include/replication/slotsync.h
@@ -26,7 +26,7 @@ extern PGDLLIMPORT char *PrimarySlotName;
 extern char *CheckAndGetDbnameFromConninfo(void);
 extern bool ValidateSlotSyncParams(int elevel);
 
-extern void ReplSlotSyncWorkerMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+pg_noreturn extern void ReplSlotSyncWorkerMain(char *startup_data, size_t startup_data_len);
 
 extern void ShutDownSlotSync(void);
 extern bool SlotSyncWorkerCanRestart(void);
diff --git a/src/include/replication/walreceiver.h b/src/include/replication/walreceiver.h
index 204419bd8a3..1be6a026152 100644
--- a/src/include/replication/walreceiver.h
+++ b/src/include/replication/walreceiver.h
@@ -486,7 +486,7 @@ walrcv_clear_result(WalRcvExecResult *walres)
 }
 
 /* prototypes for functions in walreceiver.c */
-extern void WalReceiverMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+pg_noreturn extern void WalReceiverMain(char *startup_data, size_t startup_data_len);
 extern void ProcessWalRcvInterrupts(void);
 extern void WalRcvForceReply(void);
 
diff --git a/src/include/replication/walsender_private.h b/src/include/replication/walsender_private.h
index 814b812432a..0fc77f1b4af 100644
--- a/src/include/replication/walsender_private.h
+++ b/src/include/replication/walsender_private.h
@@ -132,7 +132,7 @@ typedef void *yyscan_t;
 #endif
 extern int	replication_yyparse(Node **replication_parse_result_p, yyscan_t yyscanner);
 extern int	replication_yylex(union YYSTYPE *yylval_param, yyscan_t yyscanner);
-extern void replication_yyerror(Node **replication_parse_result_p, yyscan_t yyscanner, const char *message) pg_attribute_noreturn();
+pg_noreturn extern void replication_yyerror(Node **replication_parse_result_p, yyscan_t yyscanner, const char *message);
 extern void replication_scanner_init(const char *str, yyscan_t *yyscannerp);
 extern void replication_scanner_finish(yyscan_t yyscanner);
 extern bool replication_scanner_is_replication_command(yyscan_t yyscanner);
diff --git a/src/include/storage/ipc.h b/src/include/storage/ipc.h
index e0f5f92e947..3baf418b3d1 100644
--- a/src/include/storage/ipc.h
+++ b/src/include/storage/ipc.h
@@ -65,7 +65,7 @@ typedef void (*shmem_startup_hook_type) (void);
 extern PGDLLIMPORT bool proc_exit_inprogress;
 extern PGDLLIMPORT bool shmem_exit_inprogress;
 
-extern void proc_exit(int code) pg_attribute_noreturn();
+pg_noreturn extern void proc_exit(int code);
 extern void shmem_exit(int code);
 extern void on_proc_exit(pg_on_exit_callback function, Datum arg);
 extern void on_shmem_exit(pg_on_exit_callback function, Datum arg);
diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h
index 1076995518f..c0c0b0f7a2d 100644
--- a/src/include/storage/lock.h
+++ b/src/include/storage/lock.h
@@ -605,7 +605,7 @@ extern void lock_twophase_standby_recover(TransactionId xid, uint16 info,
 
 extern DeadLockState DeadLockCheck(PGPROC *proc);
 extern PGPROC *GetBlockingAutoVacuumPgproc(void);
-extern void DeadLockReport(void) pg_attribute_noreturn();
+pg_noreturn extern void DeadLockReport(void);
 extern void RememberSimpleDeadLock(PGPROC *proc1,
 								   LOCKMODE lockmode,
 								   LOCK *lock,
diff --git a/src/include/tcop/backend_startup.h b/src/include/tcop/backend_startup.h
index 01baf4aad75..bb65f6fff4b 100644
--- a/src/include/tcop/backend_startup.h
+++ b/src/include/tcop/backend_startup.h
@@ -39,6 +39,6 @@ typedef struct BackendStartupData
 	CAC_state	canAcceptConnections;
 } BackendStartupData;
 
-extern void BackendMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+pg_noreturn extern void BackendMain(char *startup_data, size_t startup_data_len);
 
 #endif							/* BACKEND_STARTUP_H */
diff --git a/src/include/tcop/tcopprot.h b/src/include/tcop/tcopprot.h
index a62367f7793..a83cc4f4850 100644
--- a/src/include/tcop/tcopprot.h
+++ b/src/include/tcop/tcopprot.h
@@ -69,19 +69,19 @@ extern List *pg_plan_queries(List *querytrees, const char *query_string,
 							 ParamListInfo boundParams);
 
 extern void die(SIGNAL_ARGS);
-extern void quickdie(SIGNAL_ARGS) pg_attribute_noreturn();
+pg_noreturn extern void quickdie(SIGNAL_ARGS);
 extern void StatementCancelHandler(SIGNAL_ARGS);
-extern void FloatExceptionHandler(SIGNAL_ARGS) pg_attribute_noreturn();
+pg_noreturn extern void FloatExceptionHandler(SIGNAL_ARGS);
 extern void HandleRecoveryConflictInterrupt(ProcSignalReason reason);
 extern void ProcessClientReadInterrupt(bool blocked);
 extern void ProcessClientWriteInterrupt(bool blocked);
 
 extern void process_postgres_switches(int argc, char *argv[],
 									  GucContext ctx, const char **dbname);
-extern void PostgresSingleUserMain(int argc, char *argv[],
-								   const char *username) pg_attribute_noreturn();
-extern void PostgresMain(const char *dbname,
-						 const char *username) pg_attribute_noreturn();
+pg_noreturn extern void PostgresSingleUserMain(int argc, char *argv[],
+											   const char *username);
+pg_noreturn extern void PostgresMain(const char *dbname,
+									 const char *username);
 extern void ResetUsage(void);
 extern void ShowUsage(const char *title);
 extern int	check_log_duration(char *msec_str, bool was_logged);
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
index 7161f5c6ad6..b003a548219 100644
--- a/src/include/utils/elog.h
+++ b/src/include/utils/elog.h
@@ -415,17 +415,8 @@ extern PGDLLIMPORT ErrorContextCallback *error_context_stack;
 		error_context_stack = _save_context_stack##__VA_ARGS__; \
 	} while (0)
 
-/*
- * Some compilers understand pg_attribute_noreturn(); for other compilers,
- * insert pg_unreachable() so that the compiler gets the point.
- */
-#ifdef HAVE_PG_ATTRIBUTE_NORETURN
 #define PG_RE_THROW()  \
 	pg_re_throw()
-#else
-#define PG_RE_THROW()  \
-	(pg_re_throw(), pg_unreachable())
-#endif
 
 extern PGDLLIMPORT sigjmp_buf *PG_exception_stack;
 
@@ -476,9 +467,9 @@ extern void EmitErrorReport(void);
 extern ErrorData *CopyErrorData(void);
 extern void FreeErrorData(ErrorData *edata);
 extern void FlushErrorState(void);
-extern void ReThrowError(ErrorData *edata) pg_attribute_noreturn();
+pg_noreturn extern void ReThrowError(ErrorData *edata);
 extern void ThrowErrorData(ErrorData *edata);
-extern void pg_re_throw(void) pg_attribute_noreturn();
+pg_noreturn extern void pg_re_throw(void);
 
 extern char *GetErrorContextStack(void);
 
diff --git a/src/include/utils/float.h b/src/include/utils/float.h
index 9233fa479c6..0e2e9ec5347 100644
--- a/src/include/utils/float.h
+++ b/src/include/utils/float.h
@@ -37,9 +37,9 @@ extern PGDLLIMPORT int extra_float_digits;
 /*
  * Utility functions in float.c
  */
-extern void float_overflow_error(void) pg_attribute_noreturn();
-extern void float_underflow_error(void) pg_attribute_noreturn();
-extern void float_zero_divide_error(void) pg_attribute_noreturn();
+pg_noreturn extern void float_overflow_error(void);
+pg_noreturn extern void float_underflow_error(void);
+pg_noreturn extern void float_zero_divide_error(void);
 extern int	is_infinite(float8 val);
 extern float8 float8in_internal(char *num, char **endptr_p,
 								const char *type_name, const char *orig_string,
diff --git a/src/include/utils/help_config.h b/src/include/utils/help_config.h
index d4f26eb49d0..4e58f130054 100644
--- a/src/include/utils/help_config.h
+++ b/src/include/utils/help_config.h
@@ -12,6 +12,6 @@
 #ifndef HELP_CONFIG_H
 #define HELP_CONFIG_H 1
 
-extern void GucInfoMain(void) pg_attribute_noreturn();
+pg_noreturn extern void GucInfoMain(void);
 
 #endif
diff --git a/src/include/utils/memutils_internal.h b/src/include/utils/memutils_internal.h
index 693650353c6..a6caa6335e3 100644
--- a/src/include/utils/memutils_internal.h
+++ b/src/include/utils/memutils_internal.h
@@ -160,8 +160,8 @@ extern void MemoryContextCreate(MemoryContext node,
 extern void *MemoryContextAllocationFailure(MemoryContext context, Size size,
 											int flags);
 
-extern void MemoryContextSizeFailure(MemoryContext context, Size size,
-									 int flags) pg_attribute_noreturn();
+pg_noreturn extern void MemoryContextSizeFailure(MemoryContext context, Size size,
+												 int flags);
 
 static inline void
 MemoryContextCheckSize(MemoryContext context, Size size, int flags)
diff --git a/src/interfaces/ecpg/preproc/preproc_extern.h b/src/interfaces/ecpg/preproc/preproc_extern.h
index a60b0381fbb..2c89e30621e 100644
--- a/src/interfaces/ecpg/preproc/preproc_extern.h
+++ b/src/interfaces/ecpg/preproc/preproc_extern.h
@@ -89,7 +89,7 @@ extern char *cat_str(int count,...);
 extern char *make2_str(const char *str1, const char *str2);
 extern char *make3_str(const char *str1, const char *str2, const char *str3);
 extern void mmerror(int error_code, enum errortype type, const char *error,...) pg_attribute_printf(3, 4);
-extern void mmfatal(int error_code, const char *error,...) pg_attribute_printf(2, 3) pg_attribute_noreturn();
+pg_noreturn extern void mmfatal(int error_code, const char *error,...) pg_attribute_printf(2, 3);
 extern void output_get_descr_header(const char *desc_name);
 extern void output_get_descr(const char *desc_name, const char *index);
 extern void output_set_descr_header(const char *desc_name);
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index d73996e09c0..aea0d0f98b2 100644
--- a/src/pl/plpgsql/src/plpgsql.h
+++ b/src/pl/plpgsql/src/plpgsql.h
@@ -1354,7 +1354,7 @@ extern int	plpgsql_peek(yyscan_t yyscanner);
 extern void plpgsql_peek2(int *tok1_p, int *tok2_p, int *tok1_loc,
 						  int *tok2_loc, yyscan_t yyscanner);
 extern int	plpgsql_scanner_errposition(int location, yyscan_t yyscanner);
-extern void plpgsql_yyerror(YYLTYPE *yyllocp, PLpgSQL_stmt_block **plpgsql_parse_result_p, yyscan_t yyscanner, const char *message) pg_attribute_noreturn();
+pg_noreturn extern void plpgsql_yyerror(YYLTYPE *yyllocp, PLpgSQL_stmt_block **plpgsql_parse_result_p, yyscan_t yyscanner, const char *message);
 extern int	plpgsql_location_to_lineno(int location, yyscan_t yyscanner);
 extern int	plpgsql_latest_lineno(yyscan_t yyscanner);
 extern yyscan_t plpgsql_scanner_init(const char *str);
diff --git a/src/test/modules/libpq_pipeline/libpq_pipeline.c b/src/test/modules/libpq_pipeline/libpq_pipeline.c
index 7ff18e91e66..ac9ac95135f 100644
--- a/src/test/modules/libpq_pipeline/libpq_pipeline.c
+++ b/src/test/modules/libpq_pipeline/libpq_pipeline.c
@@ -24,7 +24,7 @@
 
 
 static void exit_nicely(PGconn *conn);
-static void pg_attribute_noreturn() pg_fatal_impl(int line, const char *fmt,...)
+pg_noreturn static void pg_fatal_impl(int line, const char *fmt,...)
 			pg_attribute_printf(2, 3);
 static bool process_result(PGconn *conn, PGresult *res, int results,
 						   int numsent);
@@ -71,8 +71,7 @@ exit_nicely(PGconn *conn)
  * Print an error to stderr and terminate the program.
  */
 #define pg_fatal(...) pg_fatal_impl(__LINE__, __VA_ARGS__)
-static void
-pg_attribute_noreturn()
+pg_noreturn static void
 pg_fatal_impl(int line, const char *fmt,...)
 {
 	va_list		args;
diff --git a/src/test/modules/test_shm_mq/test_shm_mq.h b/src/test/modules/test_shm_mq/test_shm_mq.h
index 9ad9f63b44e..5346557d473 100644
--- a/src/test/modules/test_shm_mq/test_shm_mq.h
+++ b/src/test/modules/test_shm_mq/test_shm_mq.h
@@ -40,6 +40,6 @@ extern void test_shm_mq_setup(int64 queue_size, int32 nworkers,
 							  shm_mq_handle **input);
 
 /* Main entrypoint for a worker. */
-extern PGDLLEXPORT void test_shm_mq_main(Datum) pg_attribute_noreturn();
+pg_noreturn extern PGDLLEXPORT void test_shm_mq_main(Datum);
 
 #endif
diff --git a/src/test/modules/worker_spi/worker_spi.c b/src/test/modules/worker_spi/worker_spi.c
index 5b87d4f7038..9c53d896b6a 100644
--- a/src/test/modules/worker_spi/worker_spi.c
+++ b/src/test/modules/worker_spi/worker_spi.c
@@ -44,7 +44,7 @@ PG_MODULE_MAGIC;
 
 PG_FUNCTION_INFO_V1(worker_spi_launch);
 
-PGDLLEXPORT void worker_spi_main(Datum main_arg) pg_attribute_noreturn();
+PGDLLEXPORT pg_noreturn void worker_spi_main(Datum main_arg);
 
 /* GUC variables */
 static int	worker_spi_naptime = 10;
diff --git a/src/timezone/zic.c b/src/timezone/zic.c
index d605c721ecf..3b70b888180 100644
--- a/src/timezone/zic.c
+++ b/src/timezone/zic.c
@@ -117,11 +117,11 @@ extern int	link(const char *target, const char *linkname);
 	(itssymlink(target) ? (errno = ENOTSUP, -1) : link(target, linkname))
 #endif
 
-static void memory_exhausted(const char *msg) pg_attribute_noreturn();
+pg_noreturn static void memory_exhausted(const char *msg);
 static void verror(const char *string, va_list args) pg_attribute_printf(1, 0);
 static void error(const char *string,...) pg_attribute_printf(1, 2);
 static void warning(const char *string,...) pg_attribute_printf(1, 2);
-static void usage(FILE *stream, int status) pg_attribute_noreturn();
+pg_noreturn static void usage(FILE *stream, int status);
 static void addtt(zic_t starttime, int type);
 static int	addtype(zic_t utoff, char const *abbr,
 					bool isdst, bool ttisstd, bool ttisut);
diff --git a/src/tools/pg_bsd_indent/err.h b/src/tools/pg_bsd_indent/err.h
index a3e8f978255..1083462088e 100644
--- a/src/tools/pg_bsd_indent/err.h
+++ b/src/tools/pg_bsd_indent/err.h
@@ -37,9 +37,9 @@
  * This is cut down to just the minimum that we need to build indent.
  */
 
-void	err(int, const char *, ...)
-  pg_attribute_noreturn() pg_attribute_printf(2, 3);
-void	errx(int, const char *, ...)
-  pg_attribute_noreturn() pg_attribute_printf(2, 3);
+pg_noreturn void err(int, const char *, ...)
+  pg_attribute_printf(2, 3);
+pg_noreturn void errx(int, const char *, ...)
+  pg_attribute_printf(2, 3);
 
 #endif /* !_ERR_H_ */

base-commit: ed5e5f071033c8bdaabc8d9cd015f89aa3ccfeef
-- 
2.48.1

v2-0002-Add-another-pg_noreturn.patchtext/plain; charset=UTF-8; name=v2-0002-Add-another-pg_noreturn.patchDownload
From dbef9fb84b0deceb7ee576958a2d785a1bf15681 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Sat, 28 Dec 2024 11:00:24 +0100
Subject: [PATCH v2 2/4] Add another pg_noreturn

The previous change revealed a compiler warning about possibly
uninitialized variables, which this fixes.

Discussion: https://www.postgresql.org/message-id/flat/pxr5b3z7jmkpenssra5zroxi7qzzp6eswuggokw64axmdixpnk@zbwxuq7gbbcw
---
 src/common/parse_manifest.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/common/parse_manifest.c b/src/common/parse_manifest.c
index 05858578207..71973af199b 100644
--- a/src/common/parse_manifest.c
+++ b/src/common/parse_manifest.c
@@ -114,8 +114,8 @@ static void json_manifest_finalize_wal_range(JsonManifestParseState *parse);
 static void verify_manifest_checksum(JsonManifestParseState *parse,
 									 const char *buffer, size_t size,
 									 pg_cryptohash_ctx *incr_ctx);
-static void json_manifest_parse_failure(JsonManifestParseContext *context,
-										char *msg);
+pg_noreturn static void json_manifest_parse_failure(JsonManifestParseContext *context,
+													char *msg);
 
 static int	hexdecode_char(char c);
 static bool hexdecode_string(uint8 *result, char *input, int nbytes);
@@ -889,6 +889,7 @@ static void
 json_manifest_parse_failure(JsonManifestParseContext *context, char *msg)
 {
 	context->error_cb(context, "could not parse backup manifest: %s", msg);
+	pg_unreachable();
 }
 
 /*
-- 
2.48.1

v2-0003-Swap-order-of-extern-static-and-pg_nodiscard.patchtext/plain; charset=UTF-8; name=v2-0003-Swap-order-of-extern-static-and-pg_nodiscard.patchDownload
From e15b69ae84977894532fd5557c0735a9e7d6bb37 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Sat, 28 Dec 2024 11:00:24 +0100
Subject: [PATCH v2 3/4] Swap order of extern/static and pg_nodiscard

Clang in C23 mode requires all attributes to be before extern or
static.  So just swap these.  This also keeps the order consistent
with the previously introduced pg_noreturn.

Discussion: https://www.postgresql.org/message-id/flat/pxr5b3z7jmkpenssra5zroxi7qzzp6eswuggokw64axmdixpnk@zbwxuq7gbbcw
---
 src/include/common/base64.h   |  4 +--
 src/include/nodes/pg_list.h   | 68 +++++++++++++++++------------------
 src/include/storage/buffile.h |  2 +-
 src/include/utils/guc.h       |  2 +-
 src/include/utils/palloc.h    |  8 ++---
 5 files changed, 42 insertions(+), 42 deletions(-)

diff --git a/src/include/common/base64.h b/src/include/common/base64.h
index b064275bbb4..3f74aa301f0 100644
--- a/src/include/common/base64.h
+++ b/src/include/common/base64.h
@@ -11,8 +11,8 @@
 #define BASE64_H
 
 /* base 64 */
-extern pg_nodiscard int pg_b64_encode(const char *src, int len, char *dst, int dstlen);
-extern pg_nodiscard int pg_b64_decode(const char *src, int len, char *dst, int dstlen);
+pg_nodiscard extern int pg_b64_encode(const char *src, int len, char *dst, int dstlen);
+pg_nodiscard extern int pg_b64_decode(const char *src, int len, char *dst, int dstlen);
 extern int	pg_b64_enc_len(int srclen);
 extern int	pg_b64_dec_len(int srclen);
 
diff --git a/src/include/nodes/pg_list.h b/src/include/nodes/pg_list.h
index a872fc501e0..4d1cdbbcfdd 100644
--- a/src/include/nodes/pg_list.h
+++ b/src/include/nodes/pg_list.h
@@ -608,23 +608,23 @@ extern List *list_make5_impl(NodeTag t, ListCell datum1, ListCell datum2,
 							 ListCell datum3, ListCell datum4,
 							 ListCell datum5);
 
-extern pg_nodiscard List *lappend(List *list, void *datum);
-extern pg_nodiscard List *lappend_int(List *list, int datum);
-extern pg_nodiscard List *lappend_oid(List *list, Oid datum);
-extern pg_nodiscard List *lappend_xid(List *list, TransactionId datum);
+pg_nodiscard extern List *lappend(List *list, void *datum);
+pg_nodiscard extern List *lappend_int(List *list, int datum);
+pg_nodiscard extern List *lappend_oid(List *list, Oid datum);
+pg_nodiscard extern List *lappend_xid(List *list, TransactionId datum);
 
-extern pg_nodiscard List *list_insert_nth(List *list, int pos, void *datum);
-extern pg_nodiscard List *list_insert_nth_int(List *list, int pos, int datum);
-extern pg_nodiscard List *list_insert_nth_oid(List *list, int pos, Oid datum);
+pg_nodiscard extern List *list_insert_nth(List *list, int pos, void *datum);
+pg_nodiscard extern List *list_insert_nth_int(List *list, int pos, int datum);
+pg_nodiscard extern List *list_insert_nth_oid(List *list, int pos, Oid datum);
 
-extern pg_nodiscard List *lcons(void *datum, List *list);
-extern pg_nodiscard List *lcons_int(int datum, List *list);
-extern pg_nodiscard List *lcons_oid(Oid datum, List *list);
+pg_nodiscard extern List *lcons(void *datum, List *list);
+pg_nodiscard extern List *lcons_int(int datum, List *list);
+pg_nodiscard extern List *lcons_oid(Oid datum, List *list);
 
-extern pg_nodiscard List *list_concat(List *list1, const List *list2);
-extern pg_nodiscard List *list_concat_copy(const List *list1, const List *list2);
+pg_nodiscard extern List *list_concat(List *list1, const List *list2);
+pg_nodiscard extern List *list_concat_copy(const List *list1, const List *list2);
 
-extern pg_nodiscard List *list_truncate(List *list, int new_size);
+pg_nodiscard extern List *list_truncate(List *list, int new_size);
 
 extern bool list_member(const List *list, const void *datum);
 extern bool list_member_ptr(const List *list, const void *datum);
@@ -632,15 +632,15 @@ extern bool list_member_int(const List *list, int datum);
 extern bool list_member_oid(const List *list, Oid datum);
 extern bool list_member_xid(const List *list, TransactionId datum);
 
-extern pg_nodiscard List *list_delete(List *list, void *datum);
-extern pg_nodiscard List *list_delete_ptr(List *list, void *datum);
-extern pg_nodiscard List *list_delete_int(List *list, int datum);
-extern pg_nodiscard List *list_delete_oid(List *list, Oid datum);
-extern pg_nodiscard List *list_delete_first(List *list);
-extern pg_nodiscard List *list_delete_last(List *list);
-extern pg_nodiscard List *list_delete_first_n(List *list, int n);
-extern pg_nodiscard List *list_delete_nth_cell(List *list, int n);
-extern pg_nodiscard List *list_delete_cell(List *list, ListCell *cell);
+pg_nodiscard extern List *list_delete(List *list, void *datum);
+pg_nodiscard extern List *list_delete_ptr(List *list, void *datum);
+pg_nodiscard extern List *list_delete_int(List *list, int datum);
+pg_nodiscard extern List *list_delete_oid(List *list, Oid datum);
+pg_nodiscard extern List *list_delete_first(List *list);
+pg_nodiscard extern List *list_delete_last(List *list);
+pg_nodiscard extern List *list_delete_first_n(List *list, int n);
+pg_nodiscard extern List *list_delete_nth_cell(List *list, int n);
+pg_nodiscard extern List *list_delete_cell(List *list, ListCell *cell);
 
 extern List *list_union(const List *list1, const List *list2);
 extern List *list_union_ptr(const List *list1, const List *list2);
@@ -657,25 +657,25 @@ extern List *list_difference_ptr(const List *list1, const List *list2);
 extern List *list_difference_int(const List *list1, const List *list2);
 extern List *list_difference_oid(const List *list1, const List *list2);
 
-extern pg_nodiscard List *list_append_unique(List *list, void *datum);
-extern pg_nodiscard List *list_append_unique_ptr(List *list, void *datum);
-extern pg_nodiscard List *list_append_unique_int(List *list, int datum);
-extern pg_nodiscard List *list_append_unique_oid(List *list, Oid datum);
+pg_nodiscard extern List *list_append_unique(List *list, void *datum);
+pg_nodiscard extern List *list_append_unique_ptr(List *list, void *datum);
+pg_nodiscard extern List *list_append_unique_int(List *list, int datum);
+pg_nodiscard extern List *list_append_unique_oid(List *list, Oid datum);
 
-extern pg_nodiscard List *list_concat_unique(List *list1, const List *list2);
-extern pg_nodiscard List *list_concat_unique_ptr(List *list1, const List *list2);
-extern pg_nodiscard List *list_concat_unique_int(List *list1, const List *list2);
-extern pg_nodiscard List *list_concat_unique_oid(List *list1, const List *list2);
+pg_nodiscard extern List *list_concat_unique(List *list1, const List *list2);
+pg_nodiscard extern List *list_concat_unique_ptr(List *list1, const List *list2);
+pg_nodiscard extern List *list_concat_unique_int(List *list1, const List *list2);
+pg_nodiscard extern List *list_concat_unique_oid(List *list1, const List *list2);
 
 extern void list_deduplicate_oid(List *list);
 
 extern void list_free(List *list);
 extern void list_free_deep(List *list);
 
-extern pg_nodiscard List *list_copy(const List *oldlist);
-extern pg_nodiscard List *list_copy_head(const List *oldlist, int len);
-extern pg_nodiscard List *list_copy_tail(const List *oldlist, int nskip);
-extern pg_nodiscard List *list_copy_deep(const List *oldlist);
+pg_nodiscard extern List *list_copy(const List *oldlist);
+pg_nodiscard extern List *list_copy_head(const List *oldlist, int len);
+pg_nodiscard extern List *list_copy_tail(const List *oldlist, int nskip);
+pg_nodiscard extern List *list_copy_deep(const List *oldlist);
 
 typedef int (*list_sort_comparator) (const ListCell *a, const ListCell *b);
 extern void list_sort(List *list, list_sort_comparator cmp);
diff --git a/src/include/storage/buffile.h b/src/include/storage/buffile.h
index 6b92668d90f..a2f4821f240 100644
--- a/src/include/storage/buffile.h
+++ b/src/include/storage/buffile.h
@@ -38,7 +38,7 @@ typedef struct BufFile BufFile;
 
 extern BufFile *BufFileCreateTemp(bool interXact);
 extern void BufFileClose(BufFile *file);
-extern pg_nodiscard size_t BufFileRead(BufFile *file, void *ptr, size_t size);
+pg_nodiscard extern size_t BufFileRead(BufFile *file, void *ptr, size_t size);
 extern void BufFileReadExact(BufFile *file, void *ptr, size_t size);
 extern size_t BufFileReadMaybeEOF(BufFile *file, void *ptr, size_t size, bool eofOK);
 extern void BufFileWrite(BufFile *file, const void *ptr, size_t size);
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 1233e07d7da..24444cbc365 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -444,7 +444,7 @@ extern ArrayType *GUCArrayDelete(ArrayType *array, const char *name);
 extern ArrayType *GUCArrayReset(ArrayType *array);
 
 extern void *guc_malloc(int elevel, size_t size);
-extern pg_nodiscard void *guc_realloc(int elevel, void *old, size_t size);
+pg_nodiscard extern void *guc_realloc(int elevel, void *old, size_t size);
 extern char *guc_strdup(int elevel, const char *src);
 extern void guc_free(void *ptr);
 
diff --git a/src/include/utils/palloc.h b/src/include/utils/palloc.h
index 84e0fc96d96..e1b42267b22 100644
--- a/src/include/utils/palloc.h
+++ b/src/include/utils/palloc.h
@@ -79,10 +79,10 @@ extern void *palloc(Size size);
 extern void *palloc0(Size size);
 extern void *palloc_extended(Size size, int flags);
 extern void *palloc_aligned(Size size, Size alignto, int flags);
-extern pg_nodiscard void *repalloc(void *pointer, Size size);
-extern pg_nodiscard void *repalloc_extended(void *pointer,
+pg_nodiscard extern void *repalloc(void *pointer, Size size);
+pg_nodiscard extern void *repalloc_extended(void *pointer,
 											Size size, int flags);
-extern pg_nodiscard void *repalloc0(void *pointer, Size oldsize, Size size);
+pg_nodiscard extern void *repalloc0(void *pointer, Size oldsize, Size size);
 extern void pfree(void *pointer);
 
 /*
@@ -110,7 +110,7 @@ extern void pfree(void *pointer);
 
 /* Higher-limit allocators. */
 extern void *MemoryContextAllocHuge(MemoryContext context, Size size);
-extern pg_nodiscard void *repalloc_huge(void *pointer, Size size);
+pg_nodiscard extern void *repalloc_huge(void *pointer, Size size);
 
 /*
  * Although this header file is nominally backend-only, certain frontend
-- 
2.48.1

v2-0004-Support-pg_nodiscard-on-non-GNU-compilers-that-su.patchtext/plain; charset=UTF-8; name=v2-0004-Support-pg_nodiscard-on-non-GNU-compilers-that-su.patchDownload
From 80e2527bf8d55cdb33a7dfa33a888f25e9914850 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Sat, 28 Dec 2024 11:00:24 +0100
Subject: [PATCH v2 4/4] Support pg_nodiscard on non-GNU compilers that support
 C23

Support pg_nodiscard on compilers that support C23 attribute syntax.
Previously, only GCC-compatible compilers were supported.

Also, define pg_noreturn similarly using C23 attribute syntax if the
compiler supports C23.  This doesn't have much of an effect right now,
since all compilers that support C23 surely also support the existing
C11-compatible code.  But it keeps pg_nodiscard and pg_noreturn
consistent.

Discussion: https://www.postgresql.org/message-id/flat/pxr5b3z7jmkpenssra5zroxi7qzzp6eswuggokw64axmdixpnk@zbwxuq7gbbcw
---
 src/include/c.h | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/src/include/c.h b/src/include/c.h
index d42548cb1c1..a63439c9cf4 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -135,11 +135,11 @@
 
 /*
  * pg_nodiscard means the compiler should warn if the result of a function
- * call is ignored.  The name "nodiscard" is chosen in alignment with
- * (possibly future) C and C++ standards.  For maximum compatibility, use it
- * as a function declaration specifier, so it goes before the return type.
+ * call is ignored.
  */
-#ifdef __GNUC__
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
+#define pg_nodiscard [[__nodiscard__]]
+#elif defined(__GNUC__)
 #define pg_nodiscard __attribute__((warn_unused_result))
 #else
 #define pg_nodiscard
@@ -151,7 +151,9 @@
  * uses __attribute__((noreturn)) in headers, which would get confused if
  * "noreturn" is defined to "_Noreturn", as is done by <stdnoreturn.h>.
  */
-#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
+#define pg_noreturn [[__noreturn__]]
+#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
 #define pg_noreturn _Noreturn
 #elif defined(_MSC_VER)
 #define pg_noreturn __declspec(noreturn)
-- 
2.48.1

#12Peter Eisentraut
peter@eisentraut.org
In reply to: Peter Eisentraut (#11)
4 attachment(s)
Re: pg_attribute_noreturn(), MSVC, C11

On 13.02.25 16:34, Peter Eisentraut wrote:

On 22.01.25 19:16, Peter Eisentraut wrote:

On 06.01.25 15:52, Peter Eisentraut wrote:

On 03.01.25 21:51, Dagfinn Ilmari Mannsåker wrote:

Peter Eisentraut <peter@eisentraut.org> writes:

I suggest we define pg_noreturn as

1. If C11 is supported, then _Noreturn, else
2. If GCC-compatible, then __attribute__((noreturn)), else

Would it be worth also checking __has_attribute(noreturn)?  Or do all
compilers that have __attribute__((noreturn)) claim to be GCC?

I don't think that would expand the set of supported compilers in a
significant way.  We can always add it if we find one, of course.

In fact, as another thought, we could even drop #2.  Among the GCC-
compatible compilers, both GCC and Clang have supported #1 for ages,
and the only other candidate I could find on the build farm is the
Solaris compiler, which also supports C11 by default, per its
documentation.

3. If MSVC, then __declspec((noreturn))

Here is an updated patch set that contains the above small change and
fixes some conflicts that have arisen in the meantime.

Another rebased patch set, no further changes.

Attachments:

v3-0001-pg_noreturn-to-replace-pg_attribute_noreturn.patchtext/plain; charset=UTF-8; name=v3-0001-pg_noreturn-to-replace-pg_attribute_noreturn.patchDownload
From e85323c9bfa0406b5cdbf7036671a51722d12fa7 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Thu, 13 Feb 2025 16:01:06 +0100
Subject: [PATCH v3 1/4] pg_noreturn to replace pg_attribute_noreturn()

We want to support a "noreturn" decoration on more compilers besides
just GCC-compatible ones, but for that we need to move the decoration
in front of the function declaration instead of either behind it or
wherever, which is the current style afforded by GCC-style attributes.
Also rename the macro to "pg_noreturn" to be similar to the C11
standard "noreturn".

pg_noreturn is now supported on all compilers that support C11 (using
_Noreturn), as well as MSVC (using __declspec).  (When PostgreSQL
requires C11, the latter variant can be dropped.)  (We don't need the
previously used variant for GCC-compatible compilers using
__attribute__, because all reasonable candidates already support C11,
so that variant would be dead code in practice.)

Now, all supported compilers effectively support pg_noreturn, so the
extra code for !HAVE_PG_ATTRIBUTE_NORETURN can be dropped.

This also fixes a possible problem if third-party code includes
stdnoreturn.h, because then the current definition of

    #define pg_attribute_noreturn() __attribute__((noreturn))

would cause an error.

Note that the C standard does not support a noreturn attribute on
function pointer types.  So we have to drop these here.  There are
only two instances at this time, so it's not a big loss.

Discussion: https://www.postgresql.org/message-id/flat/pxr5b3z7jmkpenssra5zroxi7qzzp6eswuggokw64axmdixpnk@zbwxuq7gbbcw
---
 contrib/dblink/dblink.c                       |  6 ++--
 contrib/pgcrypto/px.h                         |  2 +-
 src/backend/access/transam/xlogrecovery.c     |  3 +-
 src/backend/backup/basebackup_incremental.c   |  6 ++--
 src/backend/postmaster/autovacuum.c           |  2 +-
 src/backend/postmaster/launch_backend.c       |  2 +-
 src/backend/postmaster/postmaster.c           |  2 +-
 src/backend/replication/logical/tablesync.c   |  3 +-
 src/backend/replication/walsender.c           |  2 +-
 src/backend/utils/adt/ri_triggers.c           |  8 +++---
 src/backend/utils/fmgr/dfmgr.c                |  4 +--
 src/backend/utils/hash/dynahash.c             |  2 +-
 src/backend/utils/mmgr/slab.c                 |  2 +-
 src/bin/pg_combinebackup/load_manifest.c      |  6 ++--
 src/bin/pg_dump/pg_backup_utils.h             |  2 +-
 src/bin/pg_upgrade/pg_upgrade.h               |  2 +-
 src/bin/pg_verifybackup/pg_verifybackup.c     |  6 ++--
 src/bin/pg_verifybackup/pg_verifybackup.h     |  4 +--
 src/bin/pgbench/pgbench.h                     | 12 ++++----
 src/include/bootstrap/bootstrap.h             |  4 +--
 src/include/c.h                               | 28 ++++++++++++-------
 src/include/commands/defrem.h                 |  2 +-
 src/include/common/parse_manifest.h           |  3 +-
 src/include/mb/pg_wchar.h                     |  6 ++--
 src/include/parser/parse_relation.h           |  6 ++--
 src/include/parser/scanner.h                  |  2 +-
 src/include/postmaster/autovacuum.h           |  4 +--
 src/include/postmaster/bgworker_internals.h   |  2 +-
 src/include/postmaster/bgwriter.h             |  4 +--
 src/include/postmaster/pgarch.h               |  2 +-
 src/include/postmaster/postmaster.h           |  4 +--
 src/include/postmaster/startup.h              |  2 +-
 src/include/postmaster/syslogger.h            |  2 +-
 src/include/postmaster/walsummarizer.h        |  2 +-
 src/include/postmaster/walwriter.h            |  2 +-
 src/include/replication/slotsync.h            |  2 +-
 src/include/replication/walreceiver.h         |  2 +-
 src/include/replication/walsender_private.h   |  2 +-
 src/include/storage/ipc.h                     |  2 +-
 src/include/storage/lock.h                    |  2 +-
 src/include/tcop/backend_startup.h            |  2 +-
 src/include/tcop/tcopprot.h                   | 12 ++++----
 src/include/utils/elog.h                      | 13 ++-------
 src/include/utils/float.h                     |  6 ++--
 src/include/utils/help_config.h               |  2 +-
 src/include/utils/memutils_internal.h         |  4 +--
 src/interfaces/ecpg/preproc/preproc_extern.h  |  2 +-
 src/pl/plpgsql/src/plpgsql.h                  |  2 +-
 .../modules/libpq_pipeline/libpq_pipeline.c   |  5 ++--
 src/test/modules/test_shm_mq/test_shm_mq.h    |  2 +-
 src/test/modules/worker_spi/worker_spi.c      |  2 +-
 src/timezone/zic.c                            |  4 +--
 src/tools/pg_bsd_indent/err.h                 |  8 +++---
 53 files changed, 109 insertions(+), 116 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index bed2dee3d72..58c1a6221c8 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -160,8 +160,7 @@ xpstrdup(const char *in)
 	return pstrdup(in);
 }
 
-static void
-pg_attribute_noreturn()
+pg_noreturn static void
 dblink_res_internalerror(PGconn *conn, PGresult *res, const char *p2)
 {
 	char	   *msg = pchomp(PQerrorMessage(conn));
@@ -170,8 +169,7 @@ dblink_res_internalerror(PGconn *conn, PGresult *res, const char *p2)
 	elog(ERROR, "%s: %s", p2, msg);
 }
 
-static void
-pg_attribute_noreturn()
+pg_noreturn static void
 dblink_conn_not_avail(const char *conname)
 {
 	if (conname)
diff --git a/contrib/pgcrypto/px.h b/contrib/pgcrypto/px.h
index 37013cd9f82..4b81fceab8e 100644
--- a/contrib/pgcrypto/px.h
+++ b/contrib/pgcrypto/px.h
@@ -181,7 +181,7 @@ int			px_find_hmac(const char *name, PX_HMAC **res);
 int			px_find_cipher(const char *name, PX_Cipher **res);
 int			px_find_combo(const char *name, PX_Combo **res);
 
-void		px_THROW_ERROR(int err) pg_attribute_noreturn();
+pg_noreturn void px_THROW_ERROR(int err);
 const char *px_strerror(int err);
 
 const char *px_resolve_alias(const PX_Alias *list, const char *name);
diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index a829a055a97..2c19013c98b 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -4778,8 +4778,7 @@ check_primary_slot_name(char **newval, void **extra, GucSource source)
  * that we have odd behaviors such as unexpected GUC ordering dependencies.
  */
 
-static void
-pg_attribute_noreturn()
+pg_noreturn static void
 error_multiple_recovery_targets(void)
 {
 	ereport(ERROR,
diff --git a/src/backend/backup/basebackup_incremental.c b/src/backend/backup/basebackup_incremental.c
index c2b7a55e347..76a58068665 100644
--- a/src/backend/backup/basebackup_incremental.c
+++ b/src/backend/backup/basebackup_incremental.c
@@ -139,9 +139,9 @@ static void manifest_process_wal_range(JsonManifestParseContext *context,
 									   TimeLineID tli,
 									   XLogRecPtr start_lsn,
 									   XLogRecPtr end_lsn);
-static void manifest_report_error(JsonManifestParseContext *context,
-								  const char *fmt,...)
-			pg_attribute_printf(2, 3) pg_attribute_noreturn();
+pg_noreturn static void manifest_report_error(JsonManifestParseContext *context,
+											  const char *fmt,...)
+			pg_attribute_printf(2, 3);
 static int	compare_block_numbers(const void *a, const void *b);
 
 /*
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 800815dfbcc..71c34027c88 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -317,7 +317,7 @@ int			AutovacuumLauncherPid = 0;
 
 static Oid	do_start_worker(void);
 static void ProcessAutoVacLauncherInterrupts(void);
-static void AutoVacLauncherShutdown(void) pg_attribute_noreturn();
+pg_noreturn static void AutoVacLauncherShutdown(void);
 static void launcher_determine_sleep(bool canlaunch, bool recursing,
 									 struct timeval *nap);
 static void launch_worker(TimestampTz now);
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 47375e5bfaa..256298e97c1 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -171,7 +171,7 @@ static pid_t internal_forkexec(const char *child_kind, int child_slot,
 typedef struct
 {
 	const char *name;
-	void		(*main_fn) (const void *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+	void		(*main_fn) (const void *startup_data, size_t startup_data_len);
 	bool		shmem_attach;
 } child_process_kind;
 
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index d2a7a7add6f..abebbc39f12 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -426,7 +426,7 @@ static void LogChildExit(int lev, const char *procname,
 static void PostmasterStateMachine(void);
 static void UpdatePMState(PMState newState);
 
-static void ExitPostmaster(int status) pg_attribute_noreturn();
+pg_noreturn static void ExitPostmaster(int status);
 static int	ServerLoop(void);
 static int	BackendStartup(ClientSocket *client_sock);
 static void report_fork_failure_to_client(ClientSocket *client_sock, int errnum);
diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c
index 6af5c9fe16c..65b98aa905f 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -139,8 +139,7 @@ static StringInfo copybuf = NULL;
 /*
  * Exit routine for synchronization worker.
  */
-static void
-pg_attribute_noreturn()
+pg_noreturn static void
 finish_sync_worker(void)
 {
 	/*
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 446d10c1a7d..d96121b3aad 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -237,7 +237,7 @@ typedef void (*WalSndSendDataCallback) (void);
 static void WalSndLoop(WalSndSendDataCallback send_data);
 static void InitWalSenderSlot(void);
 static void WalSndKill(int code, Datum arg);
-static void WalSndShutdown(void) pg_attribute_noreturn();
+pg_noreturn static void WalSndShutdown(void);
 static void XLogSendPhysical(void);
 static void XLogSendLogical(void);
 static void WalSndDone(WalSndSendDataCallback send_data);
diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c
index 8473448849c..c4ff18ce65e 100644
--- a/src/backend/utils/adt/ri_triggers.c
+++ b/src/backend/utils/adt/ri_triggers.c
@@ -235,10 +235,10 @@ static bool ri_PerformCheck(const RI_ConstraintInfo *riinfo,
 static void ri_ExtractValues(Relation rel, TupleTableSlot *slot,
 							 const RI_ConstraintInfo *riinfo, bool rel_is_pk,
 							 Datum *vals, char *nulls);
-static void ri_ReportViolation(const RI_ConstraintInfo *riinfo,
-							   Relation pk_rel, Relation fk_rel,
-							   TupleTableSlot *violatorslot, TupleDesc tupdesc,
-							   int queryno, bool is_restrict, bool partgone) pg_attribute_noreturn();
+pg_noreturn static void ri_ReportViolation(const RI_ConstraintInfo *riinfo,
+										   Relation pk_rel, Relation fk_rel,
+										   TupleTableSlot *violatorslot, TupleDesc tupdesc,
+										   int queryno, bool is_restrict, bool partgone);
 
 
 /*
diff --git a/src/backend/utils/fmgr/dfmgr.c b/src/backend/utils/fmgr/dfmgr.c
index 87b233cb887..4409e3e6fa8 100644
--- a/src/backend/utils/fmgr/dfmgr.c
+++ b/src/backend/utils/fmgr/dfmgr.c
@@ -67,8 +67,8 @@ static DynamicFileList *file_tail = NULL;
 char	   *Dynamic_library_path;
 
 static void *internal_load_library(const char *libname);
-static void incompatible_module_error(const char *libname,
-									  const Pg_magic_struct *module_magic_data) pg_attribute_noreturn();
+pg_noreturn static void incompatible_module_error(const char *libname,
+												  const Pg_magic_struct *module_magic_data);
 static char *expand_dynamic_library_name(const char *name);
 static void check_restricted_library_name(const char *name);
 static char *substitute_libpath_macro(const char *name);
diff --git a/src/backend/utils/hash/dynahash.c b/src/backend/utils/hash/dynahash.c
index cd5a00132fc..3f25929f2d8 100644
--- a/src/backend/utils/hash/dynahash.c
+++ b/src/backend/utils/hash/dynahash.c
@@ -272,7 +272,7 @@ static HASHBUCKET get_hash_entry(HTAB *hashp, int freelist_idx);
 static void hdefault(HTAB *hashp);
 static int	choose_nelem_alloc(Size entrysize);
 static bool init_htab(HTAB *hashp, long nelem);
-static void hash_corrupted(HTAB *hashp) pg_attribute_noreturn();
+pg_noreturn static void hash_corrupted(HTAB *hashp);
 static uint32 hash_initial_lookup(HTAB *hashp, uint32 hashvalue,
 								  HASHBUCKET **bucketptr);
 static long next_pow2_long(long num);
diff --git a/src/backend/utils/mmgr/slab.c b/src/backend/utils/mmgr/slab.c
index ec8eddad863..d32c0d318fb 100644
--- a/src/backend/utils/mmgr/slab.c
+++ b/src/backend/utils/mmgr/slab.c
@@ -601,8 +601,8 @@ SlabAllocFromNewBlock(MemoryContext context, Size size, int flags)
  *		want to avoid that.
  */
 pg_noinline
+pg_noreturn
 static void
-pg_attribute_noreturn()
 SlabAllocInvalidSize(MemoryContext context, Size size)
 {
 	SlabContext *slab = (SlabContext *) context;
diff --git a/src/bin/pg_combinebackup/load_manifest.c b/src/bin/pg_combinebackup/load_manifest.c
index 485fe518e41..8e0d04a26a6 100644
--- a/src/bin/pg_combinebackup/load_manifest.c
+++ b/src/bin/pg_combinebackup/load_manifest.c
@@ -68,9 +68,9 @@ static void combinebackup_per_wal_range_cb(JsonManifestParseContext *context,
 										   TimeLineID tli,
 										   XLogRecPtr start_lsn,
 										   XLogRecPtr end_lsn);
-static void report_manifest_error(JsonManifestParseContext *context,
-								  const char *fmt,...)
-			pg_attribute_printf(2, 3) pg_attribute_noreturn();
+pg_noreturn static void report_manifest_error(JsonManifestParseContext *context,
+											  const char *fmt,...)
+			pg_attribute_printf(2, 3);
 
 /*
  * Load backup_manifest files from an array of backups and produces an array
diff --git a/src/bin/pg_dump/pg_backup_utils.h b/src/bin/pg_dump/pg_backup_utils.h
index 38551944513..ba042016879 100644
--- a/src/bin/pg_dump/pg_backup_utils.h
+++ b/src/bin/pg_dump/pg_backup_utils.h
@@ -29,7 +29,7 @@ extern const char *progname;
 
 extern void set_dump_section(const char *arg, int *dumpSections);
 extern void on_exit_nicely(on_exit_nicely_callback function, void *arg);
-extern void exit_nicely(int code) pg_attribute_noreturn();
+pg_noreturn extern void exit_nicely(int code);
 
 /* In pg_dump, we modify pg_fatal to call exit_nicely instead of exit */
 #undef pg_fatal
diff --git a/src/bin/pg_upgrade/pg_upgrade.h b/src/bin/pg_upgrade/pg_upgrade.h
index f4e375d27c7..4c9d0172149 100644
--- a/src/bin/pg_upgrade/pg_upgrade.h
+++ b/src/bin/pg_upgrade/pg_upgrade.h
@@ -481,7 +481,7 @@ int			get_user_info(char **user_name_p);
 void		check_ok(void);
 void		report_status(eLogType type, const char *fmt,...) pg_attribute_printf(2, 3);
 void		pg_log(eLogType type, const char *fmt,...) pg_attribute_printf(2, 3);
-void		pg_fatal(const char *fmt,...) pg_attribute_printf(1, 2) pg_attribute_noreturn();
+pg_noreturn void pg_fatal(const char *fmt,...) pg_attribute_printf(1, 2);
 void		end_progress_output(void);
 void		cleanup_output_dirs(void);
 void		prep_status(const char *fmt,...) pg_attribute_printf(1, 2);
diff --git a/src/bin/pg_verifybackup/pg_verifybackup.c b/src/bin/pg_verifybackup/pg_verifybackup.c
index 7c720ab98bd..84edd2cdca5 100644
--- a/src/bin/pg_verifybackup/pg_verifybackup.c
+++ b/src/bin/pg_verifybackup/pg_verifybackup.c
@@ -69,9 +69,9 @@ static void verifybackup_per_wal_range_cb(JsonManifestParseContext *context,
 										  TimeLineID tli,
 										  XLogRecPtr start_lsn,
 										  XLogRecPtr end_lsn);
-static void report_manifest_error(JsonManifestParseContext *context,
-								  const char *fmt,...)
-			pg_attribute_printf(2, 3) pg_attribute_noreturn();
+pg_noreturn static void report_manifest_error(JsonManifestParseContext *context,
+											  const char *fmt,...)
+			pg_attribute_printf(2, 3);
 
 static void verify_tar_backup(verifier_context *context, DIR *dir);
 static void verify_plain_backup_directory(verifier_context *context,
diff --git a/src/bin/pg_verifybackup/pg_verifybackup.h b/src/bin/pg_verifybackup/pg_verifybackup.h
index 622c9d82a81..8cb6f9c53ad 100644
--- a/src/bin/pg_verifybackup/pg_verifybackup.h
+++ b/src/bin/pg_verifybackup/pg_verifybackup.h
@@ -98,8 +98,8 @@ typedef struct verifier_context
 extern void report_backup_error(verifier_context *context,
 								const char *pg_restrict fmt,...)
 			pg_attribute_printf(2, 3);
-extern void report_fatal_error(const char *pg_restrict fmt,...)
-			pg_attribute_printf(1, 2) pg_attribute_noreturn();
+pg_noreturn extern void report_fatal_error(const char *pg_restrict fmt,...)
+			pg_attribute_printf(1, 2);
 extern bool should_ignore_relpath(verifier_context *context,
 								  const char *relpath);
 
diff --git a/src/bin/pgbench/pgbench.h b/src/bin/pgbench/pgbench.h
index 0ba216e5f72..e053c9e2eb6 100644
--- a/src/bin/pgbench/pgbench.h
+++ b/src/bin/pgbench/pgbench.h
@@ -140,9 +140,9 @@ struct PgBenchExprList
 
 extern int	expr_yyparse(PgBenchExpr **expr_parse_result_p, yyscan_t yyscanner);
 extern int	expr_yylex(union YYSTYPE *yylval_param, yyscan_t yyscanner);
-extern void expr_yyerror(PgBenchExpr **expr_parse_result_p, yyscan_t yyscanner, const char *message) pg_attribute_noreturn();
-extern void expr_yyerror_more(yyscan_t yyscanner, const char *message,
-							  const char *more) pg_attribute_noreturn();
+pg_noreturn extern void expr_yyerror(PgBenchExpr **expr_parse_result_p, yyscan_t yyscanner, const char *message);
+pg_noreturn extern void expr_yyerror_more(yyscan_t yyscanner, const char *message,
+										  const char *more);
 extern bool expr_lex_one_word(PsqlScanState state, PQExpBuffer word_buf,
 							  int *offset);
 extern yyscan_t expr_scanner_init(PsqlScanState state,
@@ -153,9 +153,9 @@ extern char *expr_scanner_get_substring(PsqlScanState state,
 										int start_offset,
 										bool chomp);
 
-extern void syntax_error(const char *source, int lineno, const char *line,
-						 const char *command, const char *msg,
-						 const char *more, int column) pg_attribute_noreturn();
+pg_noreturn extern void syntax_error(const char *source, int lineno, const char *line,
+									 const char *command, const char *msg,
+									 const char *more, int column);
 
 extern bool strtoint64(const char *str, bool errorOK, int64 *result);
 extern bool strtodouble(const char *str, bool errorOK, double *dv);
diff --git a/src/include/bootstrap/bootstrap.h b/src/include/bootstrap/bootstrap.h
index 69f3d31a4ef..befc4fa1b3d 100644
--- a/src/include/bootstrap/bootstrap.h
+++ b/src/include/bootstrap/bootstrap.h
@@ -33,7 +33,7 @@ extern PGDLLIMPORT Form_pg_attribute attrtypes[MAXATTR];
 extern PGDLLIMPORT int numattr;
 
 
-extern void BootstrapModeMain(int argc, char *argv[], bool check_only) pg_attribute_noreturn();
+pg_noreturn extern void BootstrapModeMain(int argc, char *argv[], bool check_only);
 
 extern void closerel(char *relname);
 extern void boot_openrel(char *relname);
@@ -64,6 +64,6 @@ typedef void *yyscan_t;
 extern int	boot_yyparse(yyscan_t yyscanner);
 extern int	boot_yylex_init(yyscan_t *yyscannerp);
 extern int	boot_yylex(union YYSTYPE *yylval_param, yyscan_t yyscanner);
-extern void boot_yyerror(yyscan_t yyscanner, const char *message) pg_attribute_noreturn();
+pg_noreturn extern void boot_yyerror(yyscan_t yyscanner, const char *message);
 
 #endif							/* BOOTSTRAP_H */
diff --git a/src/include/c.h b/src/include/c.h
index a14c6315162..d42548cb1c1 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -145,6 +145,20 @@
 #define pg_nodiscard
 #endif
 
+/*
+ * pg_noreturn corresponds to the C11 noreturn/_Noreturn function specifier.
+ * We can't use the standard name "noreturn" because some third-party code
+ * uses __attribute__((noreturn)) in headers, which would get confused if
+ * "noreturn" is defined to "_Noreturn", as is done by <stdnoreturn.h>.
+ */
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
+#define pg_noreturn _Noreturn
+#elif defined(_MSC_VER)
+#define pg_noreturn __declspec(noreturn)
+#else
+#define pg_noreturn
+#endif
+
 /*
  * This macro will disable address safety instrumentation for a function
  * when running with "-fsanitize=address". Think twice before using this!
@@ -213,30 +227,24 @@
 #define pg_attribute_printf(f,a)
 #endif
 
-/* GCC and Sunpro support aligned, packed and noreturn */
+/* GCC and Sunpro support aligned and packed */
 #if defined(__GNUC__) || defined(__SUNPRO_C)
 #define pg_attribute_aligned(a) __attribute__((aligned(a)))
-#define pg_attribute_noreturn() __attribute__((noreturn))
 #define pg_attribute_packed() __attribute__((packed))
-#define HAVE_PG_ATTRIBUTE_NORETURN 1
 #elif defined(_MSC_VER)
 /*
- * MSVC supports aligned.  noreturn is also possible but in MSVC it is
- * declared before the definition while pg_attribute_noreturn() macro
- * is currently used after the definition.
+ * MSVC supports aligned.
  *
  * Packing is also possible but only by wrapping the entire struct definition
  * which doesn't fit into our current macro declarations.
  */
 #define pg_attribute_aligned(a) __declspec(align(a))
-#define pg_attribute_noreturn()
 #else
 /*
  * NB: aligned and packed are not given default definitions because they
  * affect code functionality; they *must* be implemented by the compiler
  * if they are to be used.
  */
-#define pg_attribute_noreturn()
 #endif
 
 /*
@@ -858,8 +866,8 @@ typedef NameData *Name;
  * we should declare it as long as !FRONTEND.
  */
 #ifndef FRONTEND
-extern void ExceptionalCondition(const char *conditionName,
-								 const char *fileName, int lineNumber) pg_attribute_noreturn();
+pg_noreturn extern void ExceptionalCondition(const char *conditionName,
+											 const char *fileName, int lineNumber);
 #endif
 
 /*
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index 6d9348bac80..dd22b5efdfd 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -160,6 +160,6 @@ extern List *defGetQualifiedName(DefElem *def);
 extern TypeName *defGetTypeName(DefElem *def);
 extern int	defGetTypeLength(DefElem *def);
 extern List *defGetStringList(DefElem *def);
-extern void errorConflictingDefElem(DefElem *defel, ParseState *pstate) pg_attribute_noreturn();
+pg_noreturn extern void errorConflictingDefElem(DefElem *defel, ParseState *pstate);
 
 #endif							/* DEFREM_H */
diff --git a/src/include/common/parse_manifest.h b/src/include/common/parse_manifest.h
index 255cab5c2a9..6172d1d5224 100644
--- a/src/include/common/parse_manifest.h
+++ b/src/include/common/parse_manifest.h
@@ -34,8 +34,7 @@ typedef void (*json_manifest_per_wal_range_callback) (JsonManifestParseContext *
 													  TimeLineID tli,
 													  XLogRecPtr start_lsn, XLogRecPtr end_lsn);
 typedef void (*json_manifest_error_callback) (JsonManifestParseContext *,
-											  const char *fmt,...) pg_attribute_printf(2, 3)
-			pg_attribute_noreturn();
+											  const char *fmt,...) pg_attribute_printf(2, 3);
 
 struct JsonManifestParseContext
 {
diff --git a/src/include/mb/pg_wchar.h b/src/include/mb/pg_wchar.h
index ff7983ee90a..bfef95baea2 100644
--- a/src/include/mb/pg_wchar.h
+++ b/src/include/mb/pg_wchar.h
@@ -768,9 +768,9 @@ extern void check_encoding_conversion_args(int src_encoding,
 										   int expected_src_encoding,
 										   int expected_dest_encoding);
 
-extern void report_invalid_encoding(int encoding, const char *mbstr, int len) pg_attribute_noreturn();
-extern void report_untranslatable_char(int src_encoding, int dest_encoding,
-									   const char *mbstr, int len) pg_attribute_noreturn();
+pg_noreturn extern void report_invalid_encoding(int encoding, const char *mbstr, int len);
+pg_noreturn extern void report_untranslatable_char(int src_encoding, int dest_encoding,
+												   const char *mbstr, int len);
 
 extern int	local2local(const unsigned char *l, unsigned char *p, int len,
 						int src_encoding, int dest_encoding,
diff --git a/src/include/parser/parse_relation.h b/src/include/parser/parse_relation.h
index 3ece5cd4eef..d59599cf242 100644
--- a/src/include/parser/parse_relation.h
+++ b/src/include/parser/parse_relation.h
@@ -110,9 +110,9 @@ extern bool isLockedRefname(ParseState *pstate, const char *refname);
 extern void addNSItemToQuery(ParseState *pstate, ParseNamespaceItem *nsitem,
 							 bool addToJoinList,
 							 bool addToRelNameSpace, bool addToVarNameSpace);
-extern void errorMissingRTE(ParseState *pstate, RangeVar *relation) pg_attribute_noreturn();
-extern void errorMissingColumn(ParseState *pstate,
-							   const char *relname, const char *colname, int location) pg_attribute_noreturn();
+pg_noreturn extern void errorMissingRTE(ParseState *pstate, RangeVar *relation);
+pg_noreturn extern void errorMissingColumn(ParseState *pstate,
+										   const char *relname, const char *colname, int location);
 extern void expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
 					  VarReturningType returning_type,
 					  int location, bool include_dropped,
diff --git a/src/include/parser/scanner.h b/src/include/parser/scanner.h
index 74ad86698ac..8d202d5b284 100644
--- a/src/include/parser/scanner.h
+++ b/src/include/parser/scanner.h
@@ -145,6 +145,6 @@ extern void setup_scanner_errposition_callback(ScannerCallbackState *scbstate,
 											   core_yyscan_t yyscanner,
 											   int location);
 extern void cancel_scanner_errposition_callback(ScannerCallbackState *scbstate);
-extern void scanner_yyerror(const char *message, core_yyscan_t yyscanner) pg_attribute_noreturn();
+pg_noreturn extern void scanner_yyerror(const char *message, core_yyscan_t yyscanner);
 
 #endif							/* SCANNER_H */
diff --git a/src/include/postmaster/autovacuum.h b/src/include/postmaster/autovacuum.h
index 6a95e5f55bd..e8135f41a1c 100644
--- a/src/include/postmaster/autovacuum.h
+++ b/src/include/postmaster/autovacuum.h
@@ -58,8 +58,8 @@ extern void autovac_init(void);
 /* called from postmaster when a worker could not be forked */
 extern void AutoVacWorkerFailed(void);
 
-extern void AutoVacLauncherMain(const void *startup_data, size_t startup_data_len) pg_attribute_noreturn();
-extern void AutoVacWorkerMain(const void *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+pg_noreturn extern void AutoVacLauncherMain(const void *startup_data, size_t startup_data_len);
+pg_noreturn extern void AutoVacWorkerMain(const void *startup_data, size_t startup_data_len);
 
 extern bool AutoVacuumRequestWork(AutoVacuumWorkItemType type,
 								  Oid relationId, BlockNumber blkno);
diff --git a/src/include/postmaster/bgworker_internals.h b/src/include/postmaster/bgworker_internals.h
index 29e6f44cf08..26cbc821edf 100644
--- a/src/include/postmaster/bgworker_internals.h
+++ b/src/include/postmaster/bgworker_internals.h
@@ -52,6 +52,6 @@ extern void ForgetUnstartedBackgroundWorkers(void);
 extern void ResetBackgroundWorkerCrashTimes(void);
 
 /* Entry point for background worker processes */
-extern void BackgroundWorkerMain(const void *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+pg_noreturn extern void BackgroundWorkerMain(const void *startup_data, size_t startup_data_len);
 
 #endif							/* BGWORKER_INTERNALS_H */
diff --git a/src/include/postmaster/bgwriter.h b/src/include/postmaster/bgwriter.h
index 4fd717169f0..800ecbfd13b 100644
--- a/src/include/postmaster/bgwriter.h
+++ b/src/include/postmaster/bgwriter.h
@@ -27,8 +27,8 @@ extern PGDLLIMPORT int CheckPointTimeout;
 extern PGDLLIMPORT int CheckPointWarning;
 extern PGDLLIMPORT double CheckPointCompletionTarget;
 
-extern void BackgroundWriterMain(const void *startup_data, size_t startup_data_len) pg_attribute_noreturn();
-extern void CheckpointerMain(const void *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+pg_noreturn extern void BackgroundWriterMain(const void *startup_data, size_t startup_data_len);
+pg_noreturn extern void CheckpointerMain(const void *startup_data, size_t startup_data_len);
 
 extern void RequestCheckpoint(int flags);
 extern void CheckpointWriteDelay(int flags, double progress);
diff --git a/src/include/postmaster/pgarch.h b/src/include/postmaster/pgarch.h
index a32d78feb27..ef7b1252086 100644
--- a/src/include/postmaster/pgarch.h
+++ b/src/include/postmaster/pgarch.h
@@ -29,7 +29,7 @@
 extern Size PgArchShmemSize(void);
 extern void PgArchShmemInit(void);
 extern bool PgArchCanRestart(void);
-extern void PgArchiverMain(const void *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+pg_noreturn extern void PgArchiverMain(const void *startup_data, size_t startup_data_len);
 extern void PgArchWakeup(void);
 extern void PgArchForceDirScan(void);
 
diff --git a/src/include/postmaster/postmaster.h b/src/include/postmaster/postmaster.h
index b6a3f275a1b..1c30c7bd0ec 100644
--- a/src/include/postmaster/postmaster.h
+++ b/src/include/postmaster/postmaster.h
@@ -91,7 +91,7 @@ extern PGDLLIMPORT const char *progname;
 extern PGDLLIMPORT bool redirection_done;
 extern PGDLLIMPORT bool LoadedSSL;
 
-extern void PostmasterMain(int argc, char *argv[]) pg_attribute_noreturn();
+pg_noreturn extern void PostmasterMain(int argc, char *argv[]);
 extern void ClosePostmasterPorts(bool am_syslogger);
 extern void InitProcessGlobals(void);
 
@@ -114,7 +114,7 @@ extern pid_t postmaster_child_launch(BackendType child_type,
 									 struct ClientSocket *client_sock);
 const char *PostmasterChildName(BackendType child_type);
 #ifdef EXEC_BACKEND
-extern void SubPostmasterMain(int argc, char *argv[]) pg_attribute_noreturn();
+pg_noreturn extern void SubPostmasterMain(int argc, char *argv[]);
 #endif
 
 /* defined in pmchild.c */
diff --git a/src/include/postmaster/startup.h b/src/include/postmaster/startup.h
index 158f52255a6..ec2c8d3bff5 100644
--- a/src/include/postmaster/startup.h
+++ b/src/include/postmaster/startup.h
@@ -26,7 +26,7 @@
 extern PGDLLIMPORT int log_startup_progress_interval;
 
 extern void ProcessStartupProcInterrupts(void);
-extern void StartupProcessMain(const void *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+pg_noreturn extern void StartupProcessMain(const void *startup_data, size_t startup_data_len);
 extern void PreRestoreCommand(void);
 extern void PostRestoreCommand(void);
 extern bool IsPromoteSignaled(void);
diff --git a/src/include/postmaster/syslogger.h b/src/include/postmaster/syslogger.h
index 197d8e43fdd..15fca58ff5d 100644
--- a/src/include/postmaster/syslogger.h
+++ b/src/include/postmaster/syslogger.h
@@ -90,7 +90,7 @@ extern int	SysLogger_Start(int child_slot);
 
 extern void write_syslogger_file(const char *buffer, int count, int destination);
 
-extern void SysLoggerMain(const void *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+pg_noreturn extern void SysLoggerMain(const void *startup_data, size_t startup_data_len);
 
 extern bool CheckLogrotateSignal(void);
 extern void RemoveLogrotateSignalFiles(void);
diff --git a/src/include/postmaster/walsummarizer.h b/src/include/postmaster/walsummarizer.h
index e1086d02c8b..34dda607c69 100644
--- a/src/include/postmaster/walsummarizer.h
+++ b/src/include/postmaster/walsummarizer.h
@@ -21,7 +21,7 @@ extern PGDLLIMPORT int wal_summary_keep_time;
 
 extern Size WalSummarizerShmemSize(void);
 extern void WalSummarizerShmemInit(void);
-extern void WalSummarizerMain(const void *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+pg_noreturn extern void WalSummarizerMain(const void *startup_data, size_t startup_data_len);
 
 extern void GetWalSummarizerState(TimeLineID *summarized_tli,
 								  XLogRecPtr *summarized_lsn,
diff --git a/src/include/postmaster/walwriter.h b/src/include/postmaster/walwriter.h
index ea8c22b174f..58e5c913d5a 100644
--- a/src/include/postmaster/walwriter.h
+++ b/src/include/postmaster/walwriter.h
@@ -18,6 +18,6 @@
 extern PGDLLIMPORT int WalWriterDelay;
 extern PGDLLIMPORT int WalWriterFlushAfter;
 
-extern void WalWriterMain(const void *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+pg_noreturn extern void WalWriterMain(const void *startup_data, size_t startup_data_len);
 
 #endif							/* _WALWRITER_H */
diff --git a/src/include/replication/slotsync.h b/src/include/replication/slotsync.h
index 6cde7f81cec..16b721463dd 100644
--- a/src/include/replication/slotsync.h
+++ b/src/include/replication/slotsync.h
@@ -26,7 +26,7 @@ extern PGDLLIMPORT char *PrimarySlotName;
 extern char *CheckAndGetDbnameFromConninfo(void);
 extern bool ValidateSlotSyncParams(int elevel);
 
-extern void ReplSlotSyncWorkerMain(const void *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+pg_noreturn extern void ReplSlotSyncWorkerMain(const void *startup_data, size_t startup_data_len);
 
 extern void ShutDownSlotSync(void);
 extern bool SlotSyncWorkerCanRestart(void);
diff --git a/src/include/replication/walreceiver.h b/src/include/replication/walreceiver.h
index 992be93cce8..ecca21fecb4 100644
--- a/src/include/replication/walreceiver.h
+++ b/src/include/replication/walreceiver.h
@@ -486,7 +486,7 @@ walrcv_clear_result(WalRcvExecResult *walres)
 }
 
 /* prototypes for functions in walreceiver.c */
-extern void WalReceiverMain(const void *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+pg_noreturn extern void WalReceiverMain(const void *startup_data, size_t startup_data_len);
 extern void ProcessWalRcvInterrupts(void);
 extern void WalRcvForceReply(void);
 
diff --git a/src/include/replication/walsender_private.h b/src/include/replication/walsender_private.h
index 814b812432a..0fc77f1b4af 100644
--- a/src/include/replication/walsender_private.h
+++ b/src/include/replication/walsender_private.h
@@ -132,7 +132,7 @@ typedef void *yyscan_t;
 #endif
 extern int	replication_yyparse(Node **replication_parse_result_p, yyscan_t yyscanner);
 extern int	replication_yylex(union YYSTYPE *yylval_param, yyscan_t yyscanner);
-extern void replication_yyerror(Node **replication_parse_result_p, yyscan_t yyscanner, const char *message) pg_attribute_noreturn();
+pg_noreturn extern void replication_yyerror(Node **replication_parse_result_p, yyscan_t yyscanner, const char *message);
 extern void replication_scanner_init(const char *str, yyscan_t *yyscannerp);
 extern void replication_scanner_finish(yyscan_t yyscanner);
 extern bool replication_scanner_is_replication_command(yyscan_t yyscanner);
diff --git a/src/include/storage/ipc.h b/src/include/storage/ipc.h
index e0f5f92e947..3baf418b3d1 100644
--- a/src/include/storage/ipc.h
+++ b/src/include/storage/ipc.h
@@ -65,7 +65,7 @@ typedef void (*shmem_startup_hook_type) (void);
 extern PGDLLIMPORT bool proc_exit_inprogress;
 extern PGDLLIMPORT bool shmem_exit_inprogress;
 
-extern void proc_exit(int code) pg_attribute_noreturn();
+pg_noreturn extern void proc_exit(int code);
 extern void shmem_exit(int code);
 extern void on_proc_exit(pg_on_exit_callback function, Datum arg);
 extern void on_shmem_exit(pg_on_exit_callback function, Datum arg);
diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h
index 1076995518f..c0c0b0f7a2d 100644
--- a/src/include/storage/lock.h
+++ b/src/include/storage/lock.h
@@ -605,7 +605,7 @@ extern void lock_twophase_standby_recover(TransactionId xid, uint16 info,
 
 extern DeadLockState DeadLockCheck(PGPROC *proc);
 extern PGPROC *GetBlockingAutoVacuumPgproc(void);
-extern void DeadLockReport(void) pg_attribute_noreturn();
+pg_noreturn extern void DeadLockReport(void);
 extern void RememberSimpleDeadLock(PGPROC *proc1,
 								   LOCKMODE lockmode,
 								   LOCK *lock,
diff --git a/src/include/tcop/backend_startup.h b/src/include/tcop/backend_startup.h
index 73285611203..6dc59738889 100644
--- a/src/include/tcop/backend_startup.h
+++ b/src/include/tcop/backend_startup.h
@@ -39,6 +39,6 @@ typedef struct BackendStartupData
 	CAC_state	canAcceptConnections;
 } BackendStartupData;
 
-extern void BackendMain(const void *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+pg_noreturn extern void BackendMain(const void *startup_data, size_t startup_data_len);
 
 #endif							/* BACKEND_STARTUP_H */
diff --git a/src/include/tcop/tcopprot.h b/src/include/tcop/tcopprot.h
index a62367f7793..a83cc4f4850 100644
--- a/src/include/tcop/tcopprot.h
+++ b/src/include/tcop/tcopprot.h
@@ -69,19 +69,19 @@ extern List *pg_plan_queries(List *querytrees, const char *query_string,
 							 ParamListInfo boundParams);
 
 extern void die(SIGNAL_ARGS);
-extern void quickdie(SIGNAL_ARGS) pg_attribute_noreturn();
+pg_noreturn extern void quickdie(SIGNAL_ARGS);
 extern void StatementCancelHandler(SIGNAL_ARGS);
-extern void FloatExceptionHandler(SIGNAL_ARGS) pg_attribute_noreturn();
+pg_noreturn extern void FloatExceptionHandler(SIGNAL_ARGS);
 extern void HandleRecoveryConflictInterrupt(ProcSignalReason reason);
 extern void ProcessClientReadInterrupt(bool blocked);
 extern void ProcessClientWriteInterrupt(bool blocked);
 
 extern void process_postgres_switches(int argc, char *argv[],
 									  GucContext ctx, const char **dbname);
-extern void PostgresSingleUserMain(int argc, char *argv[],
-								   const char *username) pg_attribute_noreturn();
-extern void PostgresMain(const char *dbname,
-						 const char *username) pg_attribute_noreturn();
+pg_noreturn extern void PostgresSingleUserMain(int argc, char *argv[],
+											   const char *username);
+pg_noreturn extern void PostgresMain(const char *dbname,
+									 const char *username);
 extern void ResetUsage(void);
 extern void ShowUsage(const char *title);
 extern int	check_log_duration(char *msec_str, bool was_logged);
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
index a0244bff1fc..855c147325b 100644
--- a/src/include/utils/elog.h
+++ b/src/include/utils/elog.h
@@ -415,17 +415,8 @@ extern PGDLLIMPORT ErrorContextCallback *error_context_stack;
 		error_context_stack = _save_context_stack##__VA_ARGS__; \
 	} while (0)
 
-/*
- * Some compilers understand pg_attribute_noreturn(); for other compilers,
- * insert pg_unreachable() so that the compiler gets the point.
- */
-#ifdef HAVE_PG_ATTRIBUTE_NORETURN
 #define PG_RE_THROW()  \
 	pg_re_throw()
-#else
-#define PG_RE_THROW()  \
-	(pg_re_throw(), pg_unreachable())
-#endif
 
 extern PGDLLIMPORT sigjmp_buf *PG_exception_stack;
 
@@ -476,9 +467,9 @@ extern void EmitErrorReport(void);
 extern ErrorData *CopyErrorData(void);
 extern void FreeErrorData(ErrorData *edata);
 extern void FlushErrorState(void);
-extern void ReThrowError(ErrorData *edata) pg_attribute_noreturn();
+pg_noreturn extern void ReThrowError(ErrorData *edata);
 extern void ThrowErrorData(ErrorData *edata);
-extern void pg_re_throw(void) pg_attribute_noreturn();
+pg_noreturn extern void pg_re_throw(void);
 
 extern char *GetErrorContextStack(void);
 
diff --git a/src/include/utils/float.h b/src/include/utils/float.h
index 9233fa479c6..0e2e9ec5347 100644
--- a/src/include/utils/float.h
+++ b/src/include/utils/float.h
@@ -37,9 +37,9 @@ extern PGDLLIMPORT int extra_float_digits;
 /*
  * Utility functions in float.c
  */
-extern void float_overflow_error(void) pg_attribute_noreturn();
-extern void float_underflow_error(void) pg_attribute_noreturn();
-extern void float_zero_divide_error(void) pg_attribute_noreturn();
+pg_noreturn extern void float_overflow_error(void);
+pg_noreturn extern void float_underflow_error(void);
+pg_noreturn extern void float_zero_divide_error(void);
 extern int	is_infinite(float8 val);
 extern float8 float8in_internal(char *num, char **endptr_p,
 								const char *type_name, const char *orig_string,
diff --git a/src/include/utils/help_config.h b/src/include/utils/help_config.h
index d4f26eb49d0..4e58f130054 100644
--- a/src/include/utils/help_config.h
+++ b/src/include/utils/help_config.h
@@ -12,6 +12,6 @@
 #ifndef HELP_CONFIG_H
 #define HELP_CONFIG_H 1
 
-extern void GucInfoMain(void) pg_attribute_noreturn();
+pg_noreturn extern void GucInfoMain(void);
 
 #endif
diff --git a/src/include/utils/memutils_internal.h b/src/include/utils/memutils_internal.h
index 693650353c6..a6caa6335e3 100644
--- a/src/include/utils/memutils_internal.h
+++ b/src/include/utils/memutils_internal.h
@@ -160,8 +160,8 @@ extern void MemoryContextCreate(MemoryContext node,
 extern void *MemoryContextAllocationFailure(MemoryContext context, Size size,
 											int flags);
 
-extern void MemoryContextSizeFailure(MemoryContext context, Size size,
-									 int flags) pg_attribute_noreturn();
+pg_noreturn extern void MemoryContextSizeFailure(MemoryContext context, Size size,
+												 int flags);
 
 static inline void
 MemoryContextCheckSize(MemoryContext context, Size size, int flags)
diff --git a/src/interfaces/ecpg/preproc/preproc_extern.h b/src/interfaces/ecpg/preproc/preproc_extern.h
index a60b0381fbb..2c89e30621e 100644
--- a/src/interfaces/ecpg/preproc/preproc_extern.h
+++ b/src/interfaces/ecpg/preproc/preproc_extern.h
@@ -89,7 +89,7 @@ extern char *cat_str(int count,...);
 extern char *make2_str(const char *str1, const char *str2);
 extern char *make3_str(const char *str1, const char *str2, const char *str3);
 extern void mmerror(int error_code, enum errortype type, const char *error,...) pg_attribute_printf(3, 4);
-extern void mmfatal(int error_code, const char *error,...) pg_attribute_printf(2, 3) pg_attribute_noreturn();
+pg_noreturn extern void mmfatal(int error_code, const char *error,...) pg_attribute_printf(2, 3);
 extern void output_get_descr_header(const char *desc_name);
 extern void output_get_descr(const char *desc_name, const char *index);
 extern void output_set_descr_header(const char *desc_name);
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index d73996e09c0..aea0d0f98b2 100644
--- a/src/pl/plpgsql/src/plpgsql.h
+++ b/src/pl/plpgsql/src/plpgsql.h
@@ -1354,7 +1354,7 @@ extern int	plpgsql_peek(yyscan_t yyscanner);
 extern void plpgsql_peek2(int *tok1_p, int *tok2_p, int *tok1_loc,
 						  int *tok2_loc, yyscan_t yyscanner);
 extern int	plpgsql_scanner_errposition(int location, yyscan_t yyscanner);
-extern void plpgsql_yyerror(YYLTYPE *yyllocp, PLpgSQL_stmt_block **plpgsql_parse_result_p, yyscan_t yyscanner, const char *message) pg_attribute_noreturn();
+pg_noreturn extern void plpgsql_yyerror(YYLTYPE *yyllocp, PLpgSQL_stmt_block **plpgsql_parse_result_p, yyscan_t yyscanner, const char *message);
 extern int	plpgsql_location_to_lineno(int location, yyscan_t yyscanner);
 extern int	plpgsql_latest_lineno(yyscan_t yyscanner);
 extern yyscan_t plpgsql_scanner_init(const char *str);
diff --git a/src/test/modules/libpq_pipeline/libpq_pipeline.c b/src/test/modules/libpq_pipeline/libpq_pipeline.c
index 7ff18e91e66..ac9ac95135f 100644
--- a/src/test/modules/libpq_pipeline/libpq_pipeline.c
+++ b/src/test/modules/libpq_pipeline/libpq_pipeline.c
@@ -24,7 +24,7 @@
 
 
 static void exit_nicely(PGconn *conn);
-static void pg_attribute_noreturn() pg_fatal_impl(int line, const char *fmt,...)
+pg_noreturn static void pg_fatal_impl(int line, const char *fmt,...)
 			pg_attribute_printf(2, 3);
 static bool process_result(PGconn *conn, PGresult *res, int results,
 						   int numsent);
@@ -71,8 +71,7 @@ exit_nicely(PGconn *conn)
  * Print an error to stderr and terminate the program.
  */
 #define pg_fatal(...) pg_fatal_impl(__LINE__, __VA_ARGS__)
-static void
-pg_attribute_noreturn()
+pg_noreturn static void
 pg_fatal_impl(int line, const char *fmt,...)
 {
 	va_list		args;
diff --git a/src/test/modules/test_shm_mq/test_shm_mq.h b/src/test/modules/test_shm_mq/test_shm_mq.h
index 9ad9f63b44e..5346557d473 100644
--- a/src/test/modules/test_shm_mq/test_shm_mq.h
+++ b/src/test/modules/test_shm_mq/test_shm_mq.h
@@ -40,6 +40,6 @@ extern void test_shm_mq_setup(int64 queue_size, int32 nworkers,
 							  shm_mq_handle **input);
 
 /* Main entrypoint for a worker. */
-extern PGDLLEXPORT void test_shm_mq_main(Datum) pg_attribute_noreturn();
+pg_noreturn extern PGDLLEXPORT void test_shm_mq_main(Datum);
 
 #endif
diff --git a/src/test/modules/worker_spi/worker_spi.c b/src/test/modules/worker_spi/worker_spi.c
index 5b87d4f7038..9c53d896b6a 100644
--- a/src/test/modules/worker_spi/worker_spi.c
+++ b/src/test/modules/worker_spi/worker_spi.c
@@ -44,7 +44,7 @@ PG_MODULE_MAGIC;
 
 PG_FUNCTION_INFO_V1(worker_spi_launch);
 
-PGDLLEXPORT void worker_spi_main(Datum main_arg) pg_attribute_noreturn();
+PGDLLEXPORT pg_noreturn void worker_spi_main(Datum main_arg);
 
 /* GUC variables */
 static int	worker_spi_naptime = 10;
diff --git a/src/timezone/zic.c b/src/timezone/zic.c
index d605c721ecf..3b70b888180 100644
--- a/src/timezone/zic.c
+++ b/src/timezone/zic.c
@@ -117,11 +117,11 @@ extern int	link(const char *target, const char *linkname);
 	(itssymlink(target) ? (errno = ENOTSUP, -1) : link(target, linkname))
 #endif
 
-static void memory_exhausted(const char *msg) pg_attribute_noreturn();
+pg_noreturn static void memory_exhausted(const char *msg);
 static void verror(const char *string, va_list args) pg_attribute_printf(1, 0);
 static void error(const char *string,...) pg_attribute_printf(1, 2);
 static void warning(const char *string,...) pg_attribute_printf(1, 2);
-static void usage(FILE *stream, int status) pg_attribute_noreturn();
+pg_noreturn static void usage(FILE *stream, int status);
 static void addtt(zic_t starttime, int type);
 static int	addtype(zic_t utoff, char const *abbr,
 					bool isdst, bool ttisstd, bool ttisut);
diff --git a/src/tools/pg_bsd_indent/err.h b/src/tools/pg_bsd_indent/err.h
index a3e8f978255..1083462088e 100644
--- a/src/tools/pg_bsd_indent/err.h
+++ b/src/tools/pg_bsd_indent/err.h
@@ -37,9 +37,9 @@
  * This is cut down to just the minimum that we need to build indent.
  */
 
-void	err(int, const char *, ...)
-  pg_attribute_noreturn() pg_attribute_printf(2, 3);
-void	errx(int, const char *, ...)
-  pg_attribute_noreturn() pg_attribute_printf(2, 3);
+pg_noreturn void err(int, const char *, ...)
+  pg_attribute_printf(2, 3);
+pg_noreturn void errx(int, const char *, ...)
+  pg_attribute_printf(2, 3);
 
 #endif /* !_ERR_H_ */

base-commit: e033696596566d422a0eae47adca371a210ed730
-- 
2.48.1

v3-0002-Add-another-pg_noreturn.patchtext/plain; charset=UTF-8; name=v3-0002-Add-another-pg_noreturn.patchDownload
From f0f2ed0af115725d68610ad0ccb83b9f1bd9cde8 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Sat, 28 Dec 2024 11:00:24 +0100
Subject: [PATCH v3 2/4] Add another pg_noreturn

The previous change revealed a compiler warning about possibly
uninitialized variables, which this fixes.

Discussion: https://www.postgresql.org/message-id/flat/pxr5b3z7jmkpenssra5zroxi7qzzp6eswuggokw64axmdixpnk@zbwxuq7gbbcw
---
 src/common/parse_manifest.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/common/parse_manifest.c b/src/common/parse_manifest.c
index 05858578207..71973af199b 100644
--- a/src/common/parse_manifest.c
+++ b/src/common/parse_manifest.c
@@ -114,8 +114,8 @@ static void json_manifest_finalize_wal_range(JsonManifestParseState *parse);
 static void verify_manifest_checksum(JsonManifestParseState *parse,
 									 const char *buffer, size_t size,
 									 pg_cryptohash_ctx *incr_ctx);
-static void json_manifest_parse_failure(JsonManifestParseContext *context,
-										char *msg);
+pg_noreturn static void json_manifest_parse_failure(JsonManifestParseContext *context,
+													char *msg);
 
 static int	hexdecode_char(char c);
 static bool hexdecode_string(uint8 *result, char *input, int nbytes);
@@ -889,6 +889,7 @@ static void
 json_manifest_parse_failure(JsonManifestParseContext *context, char *msg)
 {
 	context->error_cb(context, "could not parse backup manifest: %s", msg);
+	pg_unreachable();
 }
 
 /*
-- 
2.48.1

v3-0003-Swap-order-of-extern-static-and-pg_nodiscard.patchtext/plain; charset=UTF-8; name=v3-0003-Swap-order-of-extern-static-and-pg_nodiscard.patchDownload
From d9baec2998a5f88364eaa6c3866a1fe6f1356aa4 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Sat, 28 Dec 2024 11:00:24 +0100
Subject: [PATCH v3 3/4] Swap order of extern/static and pg_nodiscard

Clang in C23 mode requires all attributes to be before extern or
static.  So just swap these.  This also keeps the order consistent
with the previously introduced pg_noreturn.

Discussion: https://www.postgresql.org/message-id/flat/pxr5b3z7jmkpenssra5zroxi7qzzp6eswuggokw64axmdixpnk@zbwxuq7gbbcw
---
 src/include/common/base64.h   |  4 +--
 src/include/nodes/pg_list.h   | 68 +++++++++++++++++------------------
 src/include/storage/buffile.h |  2 +-
 src/include/utils/guc.h       |  2 +-
 src/include/utils/palloc.h    |  8 ++---
 5 files changed, 42 insertions(+), 42 deletions(-)

diff --git a/src/include/common/base64.h b/src/include/common/base64.h
index b064275bbb4..3f74aa301f0 100644
--- a/src/include/common/base64.h
+++ b/src/include/common/base64.h
@@ -11,8 +11,8 @@
 #define BASE64_H
 
 /* base 64 */
-extern pg_nodiscard int pg_b64_encode(const char *src, int len, char *dst, int dstlen);
-extern pg_nodiscard int pg_b64_decode(const char *src, int len, char *dst, int dstlen);
+pg_nodiscard extern int pg_b64_encode(const char *src, int len, char *dst, int dstlen);
+pg_nodiscard extern int pg_b64_decode(const char *src, int len, char *dst, int dstlen);
 extern int	pg_b64_enc_len(int srclen);
 extern int	pg_b64_dec_len(int srclen);
 
diff --git a/src/include/nodes/pg_list.h b/src/include/nodes/pg_list.h
index a872fc501e0..4d1cdbbcfdd 100644
--- a/src/include/nodes/pg_list.h
+++ b/src/include/nodes/pg_list.h
@@ -608,23 +608,23 @@ extern List *list_make5_impl(NodeTag t, ListCell datum1, ListCell datum2,
 							 ListCell datum3, ListCell datum4,
 							 ListCell datum5);
 
-extern pg_nodiscard List *lappend(List *list, void *datum);
-extern pg_nodiscard List *lappend_int(List *list, int datum);
-extern pg_nodiscard List *lappend_oid(List *list, Oid datum);
-extern pg_nodiscard List *lappend_xid(List *list, TransactionId datum);
+pg_nodiscard extern List *lappend(List *list, void *datum);
+pg_nodiscard extern List *lappend_int(List *list, int datum);
+pg_nodiscard extern List *lappend_oid(List *list, Oid datum);
+pg_nodiscard extern List *lappend_xid(List *list, TransactionId datum);
 
-extern pg_nodiscard List *list_insert_nth(List *list, int pos, void *datum);
-extern pg_nodiscard List *list_insert_nth_int(List *list, int pos, int datum);
-extern pg_nodiscard List *list_insert_nth_oid(List *list, int pos, Oid datum);
+pg_nodiscard extern List *list_insert_nth(List *list, int pos, void *datum);
+pg_nodiscard extern List *list_insert_nth_int(List *list, int pos, int datum);
+pg_nodiscard extern List *list_insert_nth_oid(List *list, int pos, Oid datum);
 
-extern pg_nodiscard List *lcons(void *datum, List *list);
-extern pg_nodiscard List *lcons_int(int datum, List *list);
-extern pg_nodiscard List *lcons_oid(Oid datum, List *list);
+pg_nodiscard extern List *lcons(void *datum, List *list);
+pg_nodiscard extern List *lcons_int(int datum, List *list);
+pg_nodiscard extern List *lcons_oid(Oid datum, List *list);
 
-extern pg_nodiscard List *list_concat(List *list1, const List *list2);
-extern pg_nodiscard List *list_concat_copy(const List *list1, const List *list2);
+pg_nodiscard extern List *list_concat(List *list1, const List *list2);
+pg_nodiscard extern List *list_concat_copy(const List *list1, const List *list2);
 
-extern pg_nodiscard List *list_truncate(List *list, int new_size);
+pg_nodiscard extern List *list_truncate(List *list, int new_size);
 
 extern bool list_member(const List *list, const void *datum);
 extern bool list_member_ptr(const List *list, const void *datum);
@@ -632,15 +632,15 @@ extern bool list_member_int(const List *list, int datum);
 extern bool list_member_oid(const List *list, Oid datum);
 extern bool list_member_xid(const List *list, TransactionId datum);
 
-extern pg_nodiscard List *list_delete(List *list, void *datum);
-extern pg_nodiscard List *list_delete_ptr(List *list, void *datum);
-extern pg_nodiscard List *list_delete_int(List *list, int datum);
-extern pg_nodiscard List *list_delete_oid(List *list, Oid datum);
-extern pg_nodiscard List *list_delete_first(List *list);
-extern pg_nodiscard List *list_delete_last(List *list);
-extern pg_nodiscard List *list_delete_first_n(List *list, int n);
-extern pg_nodiscard List *list_delete_nth_cell(List *list, int n);
-extern pg_nodiscard List *list_delete_cell(List *list, ListCell *cell);
+pg_nodiscard extern List *list_delete(List *list, void *datum);
+pg_nodiscard extern List *list_delete_ptr(List *list, void *datum);
+pg_nodiscard extern List *list_delete_int(List *list, int datum);
+pg_nodiscard extern List *list_delete_oid(List *list, Oid datum);
+pg_nodiscard extern List *list_delete_first(List *list);
+pg_nodiscard extern List *list_delete_last(List *list);
+pg_nodiscard extern List *list_delete_first_n(List *list, int n);
+pg_nodiscard extern List *list_delete_nth_cell(List *list, int n);
+pg_nodiscard extern List *list_delete_cell(List *list, ListCell *cell);
 
 extern List *list_union(const List *list1, const List *list2);
 extern List *list_union_ptr(const List *list1, const List *list2);
@@ -657,25 +657,25 @@ extern List *list_difference_ptr(const List *list1, const List *list2);
 extern List *list_difference_int(const List *list1, const List *list2);
 extern List *list_difference_oid(const List *list1, const List *list2);
 
-extern pg_nodiscard List *list_append_unique(List *list, void *datum);
-extern pg_nodiscard List *list_append_unique_ptr(List *list, void *datum);
-extern pg_nodiscard List *list_append_unique_int(List *list, int datum);
-extern pg_nodiscard List *list_append_unique_oid(List *list, Oid datum);
+pg_nodiscard extern List *list_append_unique(List *list, void *datum);
+pg_nodiscard extern List *list_append_unique_ptr(List *list, void *datum);
+pg_nodiscard extern List *list_append_unique_int(List *list, int datum);
+pg_nodiscard extern List *list_append_unique_oid(List *list, Oid datum);
 
-extern pg_nodiscard List *list_concat_unique(List *list1, const List *list2);
-extern pg_nodiscard List *list_concat_unique_ptr(List *list1, const List *list2);
-extern pg_nodiscard List *list_concat_unique_int(List *list1, const List *list2);
-extern pg_nodiscard List *list_concat_unique_oid(List *list1, const List *list2);
+pg_nodiscard extern List *list_concat_unique(List *list1, const List *list2);
+pg_nodiscard extern List *list_concat_unique_ptr(List *list1, const List *list2);
+pg_nodiscard extern List *list_concat_unique_int(List *list1, const List *list2);
+pg_nodiscard extern List *list_concat_unique_oid(List *list1, const List *list2);
 
 extern void list_deduplicate_oid(List *list);
 
 extern void list_free(List *list);
 extern void list_free_deep(List *list);
 
-extern pg_nodiscard List *list_copy(const List *oldlist);
-extern pg_nodiscard List *list_copy_head(const List *oldlist, int len);
-extern pg_nodiscard List *list_copy_tail(const List *oldlist, int nskip);
-extern pg_nodiscard List *list_copy_deep(const List *oldlist);
+pg_nodiscard extern List *list_copy(const List *oldlist);
+pg_nodiscard extern List *list_copy_head(const List *oldlist, int len);
+pg_nodiscard extern List *list_copy_tail(const List *oldlist, int nskip);
+pg_nodiscard extern List *list_copy_deep(const List *oldlist);
 
 typedef int (*list_sort_comparator) (const ListCell *a, const ListCell *b);
 extern void list_sort(List *list, list_sort_comparator cmp);
diff --git a/src/include/storage/buffile.h b/src/include/storage/buffile.h
index 6b92668d90f..a2f4821f240 100644
--- a/src/include/storage/buffile.h
+++ b/src/include/storage/buffile.h
@@ -38,7 +38,7 @@ typedef struct BufFile BufFile;
 
 extern BufFile *BufFileCreateTemp(bool interXact);
 extern void BufFileClose(BufFile *file);
-extern pg_nodiscard size_t BufFileRead(BufFile *file, void *ptr, size_t size);
+pg_nodiscard extern size_t BufFileRead(BufFile *file, void *ptr, size_t size);
 extern void BufFileReadExact(BufFile *file, void *ptr, size_t size);
 extern size_t BufFileReadMaybeEOF(BufFile *file, void *ptr, size_t size, bool eofOK);
 extern void BufFileWrite(BufFile *file, const void *ptr, size_t size);
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 1233e07d7da..24444cbc365 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -444,7 +444,7 @@ extern ArrayType *GUCArrayDelete(ArrayType *array, const char *name);
 extern ArrayType *GUCArrayReset(ArrayType *array);
 
 extern void *guc_malloc(int elevel, size_t size);
-extern pg_nodiscard void *guc_realloc(int elevel, void *old, size_t size);
+pg_nodiscard extern void *guc_realloc(int elevel, void *old, size_t size);
 extern char *guc_strdup(int elevel, const char *src);
 extern void guc_free(void *ptr);
 
diff --git a/src/include/utils/palloc.h b/src/include/utils/palloc.h
index 84e0fc96d96..e1b42267b22 100644
--- a/src/include/utils/palloc.h
+++ b/src/include/utils/palloc.h
@@ -79,10 +79,10 @@ extern void *palloc(Size size);
 extern void *palloc0(Size size);
 extern void *palloc_extended(Size size, int flags);
 extern void *palloc_aligned(Size size, Size alignto, int flags);
-extern pg_nodiscard void *repalloc(void *pointer, Size size);
-extern pg_nodiscard void *repalloc_extended(void *pointer,
+pg_nodiscard extern void *repalloc(void *pointer, Size size);
+pg_nodiscard extern void *repalloc_extended(void *pointer,
 											Size size, int flags);
-extern pg_nodiscard void *repalloc0(void *pointer, Size oldsize, Size size);
+pg_nodiscard extern void *repalloc0(void *pointer, Size oldsize, Size size);
 extern void pfree(void *pointer);
 
 /*
@@ -110,7 +110,7 @@ extern void pfree(void *pointer);
 
 /* Higher-limit allocators. */
 extern void *MemoryContextAllocHuge(MemoryContext context, Size size);
-extern pg_nodiscard void *repalloc_huge(void *pointer, Size size);
+pg_nodiscard extern void *repalloc_huge(void *pointer, Size size);
 
 /*
  * Although this header file is nominally backend-only, certain frontend
-- 
2.48.1

v3-0004-Support-pg_nodiscard-on-non-GNU-compilers-that-su.patchtext/plain; charset=UTF-8; name=v3-0004-Support-pg_nodiscard-on-non-GNU-compilers-that-su.patchDownload
From 0d9f2f63e2166592bd703320cf18dfb61a47ab28 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Sat, 28 Dec 2024 11:00:24 +0100
Subject: [PATCH v3 4/4] Support pg_nodiscard on non-GNU compilers that support
 C23

Support pg_nodiscard on compilers that support C23 attribute syntax.
Previously, only GCC-compatible compilers were supported.

Also, define pg_noreturn similarly using C23 attribute syntax if the
compiler supports C23.  This doesn't have much of an effect right now,
since all compilers that support C23 surely also support the existing
C11-compatible code.  But it keeps pg_nodiscard and pg_noreturn
consistent.

Discussion: https://www.postgresql.org/message-id/flat/pxr5b3z7jmkpenssra5zroxi7qzzp6eswuggokw64axmdixpnk@zbwxuq7gbbcw
---
 src/include/c.h | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/src/include/c.h b/src/include/c.h
index d42548cb1c1..a63439c9cf4 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -135,11 +135,11 @@
 
 /*
  * pg_nodiscard means the compiler should warn if the result of a function
- * call is ignored.  The name "nodiscard" is chosen in alignment with
- * (possibly future) C and C++ standards.  For maximum compatibility, use it
- * as a function declaration specifier, so it goes before the return type.
+ * call is ignored.
  */
-#ifdef __GNUC__
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
+#define pg_nodiscard [[__nodiscard__]]
+#elif defined(__GNUC__)
 #define pg_nodiscard __attribute__((warn_unused_result))
 #else
 #define pg_nodiscard
@@ -151,7 +151,9 @@
  * uses __attribute__((noreturn)) in headers, which would get confused if
  * "noreturn" is defined to "_Noreturn", as is done by <stdnoreturn.h>.
  */
-#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
+#define pg_noreturn [[__noreturn__]]
+#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
 #define pg_noreturn _Noreturn
 #elif defined(_MSC_VER)
 #define pg_noreturn __declspec(noreturn)
-- 
2.48.1

#13Andres Freund
andres@anarazel.de
In reply to: Peter Eisentraut (#12)
Re: pg_attribute_noreturn(), MSVC, C11

Hi,

On 2025-03-10 13:27:07 +0100, Peter Eisentraut wrote:

From: Peter Eisentraut <peter@eisentraut.org>
Date: Thu, 13 Feb 2025 16:01:06 +0100
Subject: [PATCH v3 1/4] pg_noreturn to replace pg_attribute_noreturn()

We want to support a "noreturn" decoration on more compilers besides
just GCC-compatible ones, but for that we need to move the decoration
in front of the function declaration instead of either behind it or
wherever, which is the current style afforded by GCC-style attributes.
Also rename the macro to "pg_noreturn" to be similar to the C11
standard "noreturn".

pg_noreturn is now supported on all compilers that support C11 (using
_Noreturn), as well as MSVC (using __declspec). (When PostgreSQL
requires C11, the latter variant can be dropped.) (We don't need the
previously used variant for GCC-compatible compilers using
__attribute__, because all reasonable candidates already support C11,
so that variant would be dead code in practice.)

Now, all supported compilers effectively support pg_noreturn, so the
extra code for !HAVE_PG_ATTRIBUTE_NORETURN can be dropped.

This also fixes a possible problem if third-party code includes
stdnoreturn.h, because then the current definition of

#define pg_attribute_noreturn() __attribute__((noreturn))

would cause an error.

Note that the C standard does not support a noreturn attribute on
function pointer types. So we have to drop these here. There are
only two instances at this time, so it's not a big loss.

That's still somewhat sad, but it's probably not worth having a separate
attribute just for those cases...

With the minor comment suggestion below, I think this looks good.

diff --git a/src/backend/utils/mmgr/slab.c b/src/backend/utils/mmgr/slab.c
index ec8eddad863..d32c0d318fb 100644
--- a/src/backend/utils/mmgr/slab.c
+++ b/src/backend/utils/mmgr/slab.c
@@ -601,8 +601,8 @@ SlabAllocFromNewBlock(MemoryContext context, Size size, int flags)
*		want to avoid that.
*/
pg_noinline
+pg_noreturn
static void
-pg_attribute_noreturn()
SlabAllocInvalidSize(MemoryContext context, Size size)
{
SlabContext *slab = (SlabContext *) context;

Hm, is it good to put the pg_noreturn after the pg_noinline?

+/*
+ * pg_noreturn corresponds to the C11 noreturn/_Noreturn function specifier.
+ * We can't use the standard name "noreturn" because some third-party code
+ * uses __attribute__((noreturn)) in headers, which would get confused if
+ * "noreturn" is defined to "_Noreturn", as is done by <stdnoreturn.h>.
+ */
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
+#define pg_noreturn _Noreturn
+#elif defined(_MSC_VER)
+#define pg_noreturn __declspec(noreturn)
+#else
+#define pg_noreturn
+#endif

I think it'd be good to add a comment explaining the placement of pg_noreturn
in a declaration, it's getting pickier...

Subject: [PATCH v3 2/4] Add another pg_noreturn

WFM

Subject: [PATCH v3 3/4] Swap order of extern/static and pg_nodiscard

Clang in C23 mode requires all attributes to be before extern or
static. So just swap these. This also keeps the order consistent
with the previously introduced pg_noreturn.

WFM.

From 0d9f2f63e2166592bd703320cf18dfb61a47ab28 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Sat, 28 Dec 2024 11:00:24 +0100
Subject: [PATCH v3 4/4] Support pg_nodiscard on non-GNU compilers that support
C23

Support pg_nodiscard on compilers that support C23 attribute syntax.
Previously, only GCC-compatible compilers were supported.

Also, define pg_noreturn similarly using C23 attribute syntax if the
compiler supports C23. This doesn't have much of an effect right now,
since all compilers that support C23 surely also support the existing
C11-compatible code. But it keeps pg_nodiscard and pg_noreturn
consistent.

This is a bit unexciting, but I guess worth it.

Greetings,

Andres Freund

#14Peter Eisentraut
peter@eisentraut.org
In reply to: Andres Freund (#13)
Re: pg_attribute_noreturn(), MSVC, C11

On 10.03.25 14:58, Andres Freund wrote:

diff --git a/src/backend/utils/mmgr/slab.c b/src/backend/utils/mmgr/slab.c
index ec8eddad863..d32c0d318fb 100644
--- a/src/backend/utils/mmgr/slab.c
+++ b/src/backend/utils/mmgr/slab.c
@@ -601,8 +601,8 @@ SlabAllocFromNewBlock(MemoryContext context, Size size, int flags)
*		want to avoid that.
*/
pg_noinline
+pg_noreturn
static void
-pg_attribute_noreturn()
SlabAllocInvalidSize(MemoryContext context, Size size)
{
SlabContext *slab = (SlabContext *) context;

Hm, is it good to put the pg_noreturn after the pg_noinline?

I probably just did them alphabetically. I don't think there would be a
problem, since pg_noinline is an attribute, and they can generally be
put everywhere. At least until we learn otherwise.

#15Andres Freund
andres@anarazel.de
In reply to: Peter Eisentraut (#14)
Re: pg_attribute_noreturn(), MSVC, C11

Hi,

On March 10, 2025 10:37:43 AM EDT, Peter Eisentraut <peter@eisentraut.org> wrote:

On 10.03.25 14:58, Andres Freund wrote:

diff --git a/src/backend/utils/mmgr/slab.c b/src/backend/utils/mmgr/slab.c
index ec8eddad863..d32c0d318fb 100644
--- a/src/backend/utils/mmgr/slab.c
+++ b/src/backend/utils/mmgr/slab.c
@@ -601,8 +601,8 @@ SlabAllocFromNewBlock(MemoryContext context, Size size, int flags)
*		want to avoid that.
*/
pg_noinline
+pg_noreturn
static void
-pg_attribute_noreturn()
SlabAllocInvalidSize(MemoryContext context, Size size)
{
SlabContext *slab = (SlabContext *) context;

Hm, is it good to put the pg_noreturn after the pg_noinline?

I probably just did them alphabetically. I don't think there would be a problem, since pg_noinline is an attribute, and they can generally be put everywhere. At least until we learn otherwise.

Just seems easier to document that no return etc should go first. But it's not important.

Andres
--
Sent from my Android device with K-9 Mail. Please excuse my brevity.

#16Peter Eisentraut
peter@eisentraut.org
In reply to: Andres Freund (#15)
Re: pg_attribute_noreturn(), MSVC, C11

I committed the first two patches (squashed together) (about
pg_noreturn). I had to make one change: I put back the GCC fallback
that I had removed between v1 and v2. This is needed for GCC versions
before C11 became the default (gcc 5) and also for situations like
buildfarm member mylodon that builds with -std=c99 explicitly.
(Otherwise, that configuration would get a bunch of compiler warnings
about uninitialized variables etc.) I also added the additional comment
about placement that you had requested.

I'm going to postpone the remaining two patches (about pg_nodiscard).
After experimenting a bit more, I'm less sure about what the correct
placement of C23 attributes is meant to be, and without understanding
that, I fear this would make the earlier question about the correct
placement of pg_noreturn unnecessarily more complicated. This can be a
future project.

#17Peter Eisentraut
peter@eisentraut.org
In reply to: Peter Eisentraut (#16)
Re: pg_attribute_noreturn(), MSVC, C11

On 13.03.25 13:43, Peter Eisentraut wrote:

I committed the first two patches (squashed together) (about
pg_noreturn).  I had to make one change: I put back the GCC fallback
that I had removed between v1 and v2.  This is needed for GCC versions
before C11 became the default (gcc 5) and also for situations like
buildfarm member mylodon that builds with -std=c99 explicitly.
(Otherwise, that configuration would get a bunch of compiler warnings
about uninitialized variables etc.)  I also added the additional comment
about placement that you had requested.

I'm going to postpone the remaining two patches (about pg_nodiscard).
After experimenting a bit more, I'm less sure about what the correct
placement of C23 attributes is meant to be, and without understanding
that, I fear this would make the earlier question about the correct
placement of pg_noreturn unnecessarily more complicated.  This can be a
future project.

After some reflection, I committed the middle patch ("Swap order of
extern/static and pg_nodiscard") after all. The code comment about the
provenance of the name needed updating anyway, and it made sense in that
context to adjust the order to make it more future-proof and make it
consistent with pg_noreturn.

I'll leave the last patch out for now, though.