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);
} /* }}} */