Commit 83e2394dc77 for php

commit 83e2394dc77c33b70b14d1e746492ed82b859e64
Author: Tim Düsterhus <tim@tideways-gmbh.com>
Date:   Tue Sep 29 14:24:35 2026 +0200

    zend_portability: Simplify definition of `ZEND_NORETURN` (#23908)

diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS
index e542dcfec57..0f79ee786aa 100644
--- a/UPGRADING.INTERNALS
+++ b/UPGRADING.INTERNALS
@@ -21,6 +21,12 @@ PHP 8.7 INTERNALS UPGRADE NOTES
 - The sapi_force_http_10() function was removed.
 - The sapi_get_fd() function was removed.
 - The sapi_get_target_uid() and sapi_get_target_gid() functions were removed.
+- Removed HAVE_NORETURN and HAVE_NORETURN_ALIAS. ZEND_NORETURN is guaranteed to
+  work.
+- Redefined ZEND_NORETURN to make use of the [[noreturn]] attribute for C++
+  and C23, which means that ZEND_NORETURN needs to come first in the modifier
+  list. Consider using noreturn (C11) / [[noreturn]] (C23) directly if
+  header interoperability is not required.

 ========================
 2. Build system changes
diff --git a/Zend/zend.c b/Zend/zend.c
index 3b16dc9c315..22be95d59fb 100644
--- a/Zend/zend.c
+++ b/Zend/zend.c
@@ -1264,7 +1264,7 @@ ZEND_COLD void zenderror(const char *error) /* {{{ */
 }
 /* }}} */

-ZEND_API ZEND_COLD ZEND_NORETURN void _zend_bailout(const char *filename, uint32_t lineno) /* {{{ */
+ZEND_NORETURN ZEND_API ZEND_COLD void _zend_bailout(const char *filename, uint32_t lineno) /* {{{ */
 {

 	if (!EG(bailout)) {
@@ -1715,7 +1715,7 @@ ZEND_API ZEND_COLD void zend_error_unchecked(int type, const char *format, ...)
 	zend_error_impl(type, format);
 }

-ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_at_noreturn(
+ZEND_NORETURN ZEND_API ZEND_COLD void zend_error_at_noreturn(
 		int type, zend_string *filename, uint32_t lineno, const char *format, ...)
 {
 	va_list args;
@@ -1744,17 +1744,17 @@ ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_at_noreturn(
 		abort(); \
 	} while (0)

-ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_noreturn(int type, const char *format, ...)
+ZEND_NORETURN ZEND_API ZEND_COLD void zend_error_noreturn(int type, const char *format, ...)
 {
 	zend_error_noreturn_impl(type, format);
 }

-ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_noreturn_unchecked(int type, const char *format, ...)
+ZEND_NORETURN ZEND_API ZEND_COLD void zend_error_noreturn_unchecked(int type, const char *format, ...)
 {
 	zend_error_noreturn_impl(type, format);
 }

-ZEND_API ZEND_COLD ZEND_NORETURN void zend_strerror_noreturn(int type, int errn, const char *message)
+ZEND_NORETURN ZEND_API ZEND_COLD void zend_strerror_noreturn(int type, int errn, const char *message)
 {
 #ifdef HAVE_STRERROR_R
 	char b[1024];
diff --git a/Zend/zend.h b/Zend/zend.h
index 6faab635392..f700c3bddcb 100644
--- a/Zend/zend.h
+++ b/Zend/zend.h
@@ -298,7 +298,7 @@ zend_result zend_post_startup(void);
 void zend_set_utility_values(zend_utility_values *utility_values);
 void zend_unload_modules(void);

-ZEND_API ZEND_COLD ZEND_NORETURN void _zend_bailout(const char *filename, uint32_t lineno);
+ZEND_NORETURN ZEND_API ZEND_COLD void _zend_bailout(const char *filename, uint32_t lineno);
 ZEND_API size_t zend_get_page_size(void);

 ZEND_API size_t zend_vspprintf(char **pbuf, size_t max_len, const char *format, va_list ap);
@@ -387,13 +387,13 @@ extern ZEND_API void (*zend_post_shutdown_cb)(void);
 extern ZEND_API void (*zend_accel_schedule_restart_hook)(int reason);

 ZEND_API ZEND_COLD void zend_error(int type, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3);
-ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_noreturn(int type, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3);
-ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_noreturn_unchecked(int type, const char *format, ...);
+ZEND_NORETURN ZEND_API ZEND_COLD void zend_error_noreturn(int type, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3);
+ZEND_NORETURN ZEND_API ZEND_COLD void zend_error_noreturn_unchecked(int type, const char *format, ...);
 /* For custom format specifiers like H */
 ZEND_API ZEND_COLD void zend_error_unchecked(int type, const char *format, ...);
 /* If filename is NULL the default filename is used. */
 ZEND_API ZEND_COLD void zend_error_at(int type, zend_string *filename, uint32_t lineno, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 4, 5);
-ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_at_noreturn(int type, zend_string *filename, uint32_t lineno, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 4, 5);
+ZEND_NORETURN ZEND_API ZEND_COLD void zend_error_at_noreturn(int type, zend_string *filename, uint32_t lineno, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 4, 5);
 ZEND_API ZEND_COLD void zend_error_zstr(int type, zend_string *message);
 ZEND_API ZEND_COLD void zend_error_zstr_at(int type, zend_string *filename, uint32_t lineno, zend_string *message);

@@ -407,7 +407,7 @@ ZEND_API ZEND_COLD void zend_illegal_container_offset(const zend_string *contain
 ZEND_COLD void zenderror(const char *error);

 /* For internal C errors */
-ZEND_API ZEND_COLD ZEND_NORETURN void zend_strerror_noreturn(int type, int errn, const char *message);
+ZEND_NORETURN ZEND_API ZEND_COLD void zend_strerror_noreturn(int type, int errn, const char *message);

 /* The following #define is used for code duality in PHP for Engine 1 & 2 */
 #define ZEND_STANDARD_CLASS_DEF_PTR zend_standard_class_def
diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c
index c652cbd39ce..7988ddf3f4a 100644
--- a/Zend/zend_alloc.c
+++ b/Zend/zend_alloc.c
@@ -380,7 +380,7 @@ static const uint32_t bin_pages[] = {
 	ZEND_MM_BINS_INFO(_BIN_DATA_PAGES, x, y)
 };

-static ZEND_COLD ZEND_NORETURN void zend_mm_panic(const char *message)
+ZEND_NORETURN static ZEND_COLD void zend_mm_panic(const char *message)
 {
 	fprintf(stderr, "%s\n", message);
 /* See http://support.microsoft.com/kb/190351 */
@@ -393,7 +393,7 @@ static ZEND_COLD ZEND_NORETURN void zend_mm_panic(const char *message)
 	abort();
 }

-static ZEND_COLD ZEND_NORETURN void zend_mm_safe_error(zend_mm_heap *heap,
+ZEND_NORETURN static ZEND_COLD void zend_mm_safe_error(zend_mm_heap *heap,
 	const char *format,
 	size_t limit,
 #if ZEND_DEBUG
@@ -2995,7 +2995,7 @@ ZEND_API char* ZEND_FASTCALL _estrndup(const char *s, size_t length ZEND_FILE_LI
 	return p;
 }

-static ZEND_COLD ZEND_NORETURN void zend_out_of_memory(void);
+ZEND_NORETURN static ZEND_COLD void zend_out_of_memory(void);

 ZEND_API char* ZEND_FASTCALL zend_strndup(const char *s, size_t length)
 {
@@ -3091,7 +3091,7 @@ ZEND_API void refresh_memory_manager(void)
 	zend_mm_refresh_key_child(AG(mm_heap));
 }

-static ZEND_COLD ZEND_NORETURN void zend_out_of_memory(void)
+ZEND_NORETURN static ZEND_COLD void zend_out_of_memory(void)
 {
 	fprintf(stderr, "Out of memory\n");
 	abort();
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index 8d65f1e9139..fa1ebe53afe 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -1295,7 +1295,7 @@ ZEND_API void function_add_ref(zend_function *function) /* {{{ */
 }
 /* }}} */

-static zend_never_inline ZEND_COLD ZEND_NORETURN void do_bind_function_error(const zend_string *lcname, const zend_op_array *op_array, bool compile_time) /* {{{ */
+ZEND_NORETURN static zend_never_inline ZEND_COLD void do_bind_function_error(const zend_string *lcname, const zend_op_array *op_array, bool compile_time) /* {{{ */
 {
 	const zval *zv = zend_hash_find_known_hash(compile_time ? CG(function_table) : EG(function_table), lcname);
 	int error_level = compile_time ? E_COMPILE_ERROR : E_ERROR;
diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h
index 5d573f68b8b..78f33e2b5bd 100644
--- a/Zend/zend_execute.h
+++ b/Zend/zend_execute.h
@@ -526,7 +526,7 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_cannot_pass_by_reference_ex(const zen

 ZEND_API void zend_set_timeout(zend_long seconds, bool reset_signals);
 ZEND_API void zend_unset_timeout(void);
-ZEND_API ZEND_NORETURN void ZEND_FASTCALL zend_timeout(void);
+ZEND_NORETURN ZEND_API void ZEND_FASTCALL zend_timeout(void);
 ZEND_API zend_class_entry *zend_fetch_class(zend_string *class_name, uint32_t fetch_type);
 ZEND_API zend_class_entry *zend_fetch_class_with_scope(zend_string *class_name, uint32_t fetch_type, zend_class_entry *scope);
 ZEND_API zend_class_entry *zend_fetch_class_by_name(zend_string *class_name, zend_string *lcname, uint32_t fetch_type);
diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c
index 59fb717b5d2..900487cf389 100644
--- a/Zend/zend_execute_API.c
+++ b/Zend/zend_execute_API.c
@@ -1467,7 +1467,7 @@ ZEND_API zend_result zend_eval_string_ex(const char *str, zval *retval_ptr, cons

 static void zend_set_timeout_ex(zend_long seconds, bool reset_signals);

-ZEND_API ZEND_NORETURN void ZEND_FASTCALL zend_timeout(void) /* {{{ */
+ZEND_NORETURN ZEND_API void ZEND_FASTCALL zend_timeout(void) /* {{{ */
 {
 #if defined(PHP_WIN32)
 # ifndef ZTS
diff --git a/Zend/zend_fibers.c b/Zend/zend_fibers.c
index c9143605085..6d392f3dcc3 100644
--- a/Zend/zend_fibers.c
+++ b/Zend/zend_fibers.c
@@ -358,9 +358,9 @@ ZEND_API void* zend_fiber_stack_base(zend_fiber_stack *stack)
 #endif

 #ifdef ZEND_FIBER_UCONTEXT
-static ZEND_NORETURN void zend_fiber_trampoline(void)
+ZEND_NORETURN static void zend_fiber_trampoline(void)
 #else
-static ZEND_NORETURN void zend_fiber_trampoline(boost_context_data data)
+ZEND_NORETURN static void zend_fiber_trampoline(boost_context_data data)
 #endif
 {
 	/* Initialize transfer struct with a copy of passed data. */
diff --git a/Zend/zend_gc.c b/Zend/zend_gc.c
index 5de2b69bf56..6c7e2a728e9 100644
--- a/Zend/zend_gc.c
+++ b/Zend/zend_gc.c
@@ -1857,12 +1857,12 @@ static void zend_gc_remove_root_tmpvars(void);

 static zend_internal_function gc_destructor_fiber;

-static ZEND_COLD ZEND_NORETURN void gc_create_destructor_fiber_error(void)
+ZEND_NORETURN static ZEND_COLD void gc_create_destructor_fiber_error(void)
 {
 	zend_error_noreturn(E_ERROR, "Unable to create destructor fiber");
 }

-static ZEND_COLD ZEND_NORETURN void gc_start_destructor_fiber_error(void)
+ZEND_NORETURN static ZEND_COLD void gc_start_destructor_fiber_error(void)
 {
 	zend_error_noreturn(E_ERROR, "Unable to start destructor fiber");
 }
diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c
index 4424c9a1a3a..99b88c90f91 100644
--- a/Zend/zend_inheritance.c
+++ b/Zend/zend_inheritance.c
@@ -1779,13 +1779,13 @@ ZEND_API void zend_verify_hooked_property(const zend_class_entry *ce, zend_prope
 	}
 }

-ZEND_API ZEND_COLD ZEND_NORETURN void zend_hooked_property_variance_error_ex(zend_string *value_param_name, zend_string *class_name, zend_string *prop_name)
+ZEND_NORETURN ZEND_API ZEND_COLD void zend_hooked_property_variance_error_ex(zend_string *value_param_name, zend_string *class_name, zend_string *prop_name)
 {
 	zend_error_noreturn(E_COMPILE_ERROR, "Type of parameter $%s of hook %s::$%s::set must be compatible with property type",
 		ZSTR_VAL(value_param_name), ZSTR_VAL(class_name), zend_get_unmangled_property_name(prop_name));
 }

-ZEND_API ZEND_COLD ZEND_NORETURN void zend_hooked_property_variance_error(const zend_property_info *prop_info)
+ZEND_NORETURN ZEND_API ZEND_COLD void zend_hooked_property_variance_error(const zend_property_info *prop_info)
 {
 	zend_string *value_param_name = prop_info->hooks[ZEND_PROPERTY_HOOK_SET]->op_array.arg_info[0].name;
 	zend_hooked_property_variance_error_ex(value_param_name, prop_info->ce->name, prop_info->name);
diff --git a/Zend/zend_inheritance.h b/Zend/zend_inheritance.h
index fdcbd95764b..49e022c4dfb 100644
--- a/Zend/zend_inheritance.h
+++ b/Zend/zend_inheritance.h
@@ -50,8 +50,8 @@ typedef enum {
 } zend_inheritance_status;

 ZEND_API zend_inheritance_status zend_verify_property_hook_variance(const zend_property_info *prop_info, const zend_function *func);
-ZEND_API ZEND_COLD ZEND_NORETURN void zend_hooked_property_variance_error(const zend_property_info *prop_info);
-ZEND_API ZEND_COLD ZEND_NORETURN void zend_hooked_property_variance_error_ex(zend_string *value_param_name, zend_string *class_name, zend_string *prop_name);
+ZEND_NORETURN ZEND_API ZEND_COLD void zend_hooked_property_variance_error(const zend_property_info *prop_info);
+ZEND_NORETURN ZEND_API ZEND_COLD void zend_hooked_property_variance_error_ex(zend_string *value_param_name, zend_string *class_name, zend_string *prop_name);
 ZEND_API void zend_verify_hooked_property(const zend_class_entry *ce, zend_property_info *prop_info, zend_string *prop_name);

 END_EXTERN_C()
diff --git a/Zend/zend_portability.h b/Zend/zend_portability.h
index a4f72d76881..0ffd8baa2cf 100644
--- a/Zend/zend_portability.h
+++ b/Zend/zend_portability.h
@@ -357,14 +357,10 @@ char *alloca();
 # endif
 #endif

-#if (defined(__GNUC__) && __GNUC__ >= 3 && !defined(__INTEL_COMPILER) && !defined(__APPLE__) && !defined(__hpux) && !defined(_AIX) && !defined(__osf__)) || __has_attribute(noreturn)
-# define HAVE_NORETURN
-# define ZEND_NORETURN __attribute__((noreturn))
-#elif defined(ZEND_WIN32)
-# define HAVE_NORETURN
-# define ZEND_NORETURN __declspec(noreturn)
+#if __STDC_VERSION__ >= 202311L || defined(__cplusplus)
+# define ZEND_NORETURN [[noreturn]]
 #else
-# define ZEND_NORETURN
+# define ZEND_NORETURN _Noreturn
 #endif

 #if __has_attribute(force_align_arg_pointer)
@@ -374,7 +370,6 @@ char *alloca();
 #endif

 #if (defined(__GNUC__) && __GNUC__ >= 3 && !defined(__INTEL_COMPILER) && !defined(__APPLE__) && !defined(__hpux) && !defined(_AIX) && !defined(__osf__))
-# define HAVE_NORETURN_ALIAS
 # define HAVE_ATTRIBUTE_WEAK
 #endif

diff --git a/Zend/zend_string.h b/Zend/zend_string.h
index ad66fe168c8..dfdf73a2e35 100644
--- a/Zend/zend_string.h
+++ b/Zend/zend_string.h
@@ -26,7 +26,7 @@

 BEGIN_EXTERN_C()

-ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_noreturn(int type, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3);
+ZEND_NORETURN ZEND_API ZEND_COLD void zend_error_noreturn(int type, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3);

 #include "zend_multiply.h"

diff --git a/ext/ffi/php_ffi.h b/ext/ffi/php_ffi.h
index 02fdb221c3d..d56dc5a5552 100644
--- a/ext/ffi/php_ffi.h
+++ b/ext/ffi/php_ffi.h
@@ -209,7 +209,7 @@ zend_result zend_ffi_parse_type(const char *str, size_t len, zend_ffi_dcl *dcl);
 void zend_ffi_cleanup_dcl(zend_ffi_dcl *dcl);

 /* parser callbacks */
-void ZEND_NORETURN zend_ffi_parser_error(const char *msg, ...);
+ZEND_NORETURN void zend_ffi_parser_error(const char *msg, ...);
 bool zend_ffi_is_typedef_name(const char *name, size_t name_len);
 void zend_ffi_resolve_typedef(const char *name, size_t name_len, zend_ffi_dcl *dcl);
 void zend_ffi_resolve_const(const char *name, size_t name_len, zend_ffi_val *val);
diff --git a/ext/soap/soap.c b/ext/soap/soap.c
index 97a65395582..a96a21162c2 100644
--- a/ext/soap/soap.c
+++ b/ext/soap/soap.c
@@ -51,9 +51,9 @@ static void set_soap_fault(zval *obj, const char *fault_code_ns, const char *fau
 static void add_soap_fault_en(zval *obj, const char *fault_code, const char *fault_string);
 static void add_soap_fault_ex(zval *fault, zval *obj, const char *fault_code, const char *fault_string, zend_string *fault_actor, zval *fault_detail, zend_string *lang);
 static void add_soap_fault_ex_en(zval *fault, zval *obj, const char *fault_code, const char *fault_string);
-static ZEND_NORETURN void soap_server_fault(const char *code, const char *string, zend_string *actor, zval* details, zend_string *name, zend_string *lang);
+ZEND_NORETURN static void soap_server_fault(const char *code, const char *string, zend_string *actor, zval* details, zend_string *name, zend_string *lang);
 static void soap_server_fault_ex(sdlFunctionPtr function, zval* fault, soapHeader* hdr);
-static ZEND_NORETURN void soap_server_fault_en(const char *code, const char *string);
+ZEND_NORETURN static void soap_server_fault_en(const char *code, const char *string);

 static sdlParamPtr get_param(sdlFunctionPtr function, const char *param_name, zend_ulong index, int);
 static sdlFunctionPtr get_function(sdlPtr sdl, const char *function_name, size_t function_name_length);
@@ -1944,7 +1944,7 @@ static void soap_server_fault_ex(sdlFunctionPtr function, zval* fault, soapHeade
 }
 /* }}} */

-static ZEND_NORETURN void soap_server_fault(const char *code, const char *string, zend_string *actor, zval* details, zend_string* name, zend_string *lang) /* {{{ */
+ZEND_NORETURN static void soap_server_fault(const char *code, const char *string, zend_string *actor, zval* details, zend_string* name, zend_string *lang) /* {{{ */
 {
 	zval ret;

@@ -1956,7 +1956,7 @@ static ZEND_NORETURN void soap_server_fault(const char *code, const char *string
 }
 /* }}} */

-static ZEND_NORETURN void soap_server_fault_en(const char *code, const char *string)
+ZEND_NORETURN static void soap_server_fault_en(const char *code, const char *string)
 {
 	soap_server_fault(code, string, NULL, NULL, NULL, soap_lang_en);
 }
diff --git a/sapi/phpdbg/phpdbg.c b/sapi/phpdbg/phpdbg.c
index 834948e6815..eb003e8a2ea 100644
--- a/sapi/phpdbg/phpdbg.c
+++ b/sapi/phpdbg/phpdbg.c
@@ -1060,7 +1060,7 @@ static void phpdbg_signal_handler(int sig, siginfo_t *info, void *context) /* {{
 } /* }}} */


-static ZEND_NORETURN void phpdbg_sighup_handler(int sig) /* {{{ */
+ZEND_NORETURN static void phpdbg_sighup_handler(int sig) /* {{{ */
 {
 	exit(0);
 } /* }}} */