From 2fcdddabab7696c271427de9fa026ea4d55f1f9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Thu, 12 Feb 2026 12:10:54 +0100 Subject: [PATCH 1/5] zend_compile: Bundle function type constants into an `zend_function_type` enum This clarifies the relationship between these constants and improves type safety a little. --- Zend/zend_compile.h | 31 ++++++++++++++++++++++--------- Zend/zend_language_scanner.l | 2 +- Zend/zend_opcode.c | 2 +- 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 587ae485ec821..2c5b3a8743710 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -497,6 +497,23 @@ typedef struct _zend_class_constant { #define ZEND_CLASS_CONST_FLAGS(c) Z_CONSTANT_FLAGS((c)->value) +#if __STDC_VERSION__ >= 202311L || defined(__cplusplus) +enum zend_function_type: uint8_t +#else +enum zend_function_type +#endif +{ + ZEND_INTERNAL_FUNCTION = 1, + ZEND_USER_FUNCTION = 2, + ZEND_EVAL_CODE = 4, +}; + +#if __STDC_VERSION__ >= 202311L || defined(__cplusplus) +typedef enum zend_function_type zend_function_type; +#else +typedef uint8_t zend_function_type; +#endif + /* arg_info for internal functions */ typedef struct _zend_internal_arg_info { const char *name; @@ -524,7 +541,7 @@ typedef struct _zend_internal_function_info { struct _zend_op_array { /* Common elements */ - uint8_t type; + zend_function_type type; uint8_t arg_flags[3]; /* bitset of arg_info.pass_by_reference */ uint32_t fn_flags; zend_string *function_name; @@ -584,7 +601,7 @@ typedef void (ZEND_FASTCALL *zif_handler)(INTERNAL_FUNCTION_PARAMETERS); typedef struct _zend_internal_function { /* Common elements */ - uint8_t type; + zend_function_type type; uint8_t arg_flags[3]; /* bitset of arg_info.pass_by_reference */ uint32_t fn_flags; zend_string* function_name; @@ -610,11 +627,11 @@ typedef struct _zend_internal_function { #define ZEND_FN_SCOPE_NAME(function) ((function) && (function)->common.scope ? ZSTR_VAL((function)->common.scope->name) : "") union _zend_function { - uint8_t type; /* MUST be the first element of this struct! */ + zend_function_type type; /* MUST be the first element of this struct! */ uint32_t quick_arg_flags; struct { - uint8_t type; /* never used */ + zend_function_type type; /* never used */ uint8_t arg_flags[3]; /* bitset of arg_info.pass_by_reference */ uint32_t fn_flags; zend_string *function_name; @@ -956,7 +973,7 @@ ZEND_API zend_ast *zend_compile_string_to_ast( ZEND_API zend_result zend_execute_scripts(int type, zval *retval, int file_count, ...); ZEND_API zend_result zend_execute_script(int type, zval *retval, zend_file_handle *file_handle); ZEND_API zend_result open_file_for_scanning(zend_file_handle *file_handle); -ZEND_API void init_op_array(zend_op_array *op_array, uint8_t type, int initial_ops_size); +ZEND_API void init_op_array(zend_op_array *op_array, zend_function_type type, int initial_ops_size); ZEND_API void destroy_op_array(zend_op_array *op_array); ZEND_API void zend_destroy_static_vars(zend_op_array *op_array); ZEND_API void zend_destroy_file_handle(zend_file_handle *file_handle); @@ -1071,10 +1088,6 @@ ZEND_API zend_string *zend_type_to_string(zend_type type); #define BP_VAR_FUNC_ARG 4 #define BP_VAR_UNSET 5 -#define ZEND_INTERNAL_FUNCTION 1 -#define ZEND_USER_FUNCTION 2 -#define ZEND_EVAL_CODE 4 - #define ZEND_USER_CODE(type) ((type) != ZEND_INTERNAL_FUNCTION) #define ZEND_INTERNAL_CLASS 1 diff --git a/Zend/zend_language_scanner.l b/Zend/zend_language_scanner.l index 5a8a78cc3bd7b..1c985189fd3c0 100644 --- a/Zend/zend_language_scanner.l +++ b/Zend/zend_language_scanner.l @@ -591,7 +591,7 @@ ZEND_API zend_result open_file_for_scanning(zend_file_handle *file_handle) return SUCCESS; } -static zend_op_array *zend_compile(int type) +static zend_op_array *zend_compile(zend_function_type type) { zend_op_array *op_array = NULL; bool original_in_compilation = CG(in_compilation); diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index d874f566dc87d..24b480ad71e66 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -45,7 +45,7 @@ static void zend_extension_op_array_dtor_handler(zend_extension *extension, zend } } -void init_op_array(zend_op_array *op_array, uint8_t type, int initial_ops_size) +void init_op_array(zend_op_array *op_array, zend_function_type type, int initial_ops_size) { op_array->type = type; op_array->arg_flags[0] = 0; From 3f2a11764a8b77f3026fefe2b3ced1aad2e2a3c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Sun, 15 Feb 2026 13:39:45 +0100 Subject: [PATCH 2/5] Add C23_ENUM() helper macro --- UPGRADING.INTERNALS | 2 ++ Zend/zend_compile.h | 13 +------------ Zend/zend_portability.h | 13 +++++++++++++ 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index 06c1d52826229..0c8e10e17f084 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -72,6 +72,8 @@ PHP 8.6 INTERNALS UPGRADE NOTES zend_string* parameter. . EG(in_autoload) was renamed to EG(autoload_current_classnames) and no longer is a pointer, but a directly embedded HashTable struct. + . Added a C23_ENUM() helper macro to define forward-compatible fixed-size + enums. ======================== 2. Build system changes diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 2c5b3a8743710..9991667f313aa 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -497,23 +497,12 @@ typedef struct _zend_class_constant { #define ZEND_CLASS_CONST_FLAGS(c) Z_CONSTANT_FLAGS((c)->value) -#if __STDC_VERSION__ >= 202311L || defined(__cplusplus) -enum zend_function_type: uint8_t -#else -enum zend_function_type -#endif -{ +enum C23_ENUM(zend_function_type, uint8_t) { ZEND_INTERNAL_FUNCTION = 1, ZEND_USER_FUNCTION = 2, ZEND_EVAL_CODE = 4, }; -#if __STDC_VERSION__ >= 202311L || defined(__cplusplus) -typedef enum zend_function_type zend_function_type; -#else -typedef uint8_t zend_function_type; -#endif - /* arg_info for internal functions */ typedef struct _zend_internal_arg_info { const char *name; diff --git a/Zend/zend_portability.h b/Zend/zend_portability.h index 6546ebfb5b790..4c25391816fd1 100644 --- a/Zend/zend_portability.h +++ b/Zend/zend_portability.h @@ -146,6 +146,19 @@ #define zend_quiet_write(...) ZEND_IGNORE_VALUE(write(__VA_ARGS__)) +/* Define a fixed-size enum as enum C23_ENUM(name, size) { }. */ +#if __STDC_VERSION__ >= 202311L || defined(__cplusplus) +# define C23_ENUM(name, size) \ + name: size; \ + typedef enum name name; \ + enum name: size +#else +# define C23_ENUM(name, size) \ + name; \ + typedef size name; \ + enum name +#endif + /* all HAVE_XXX test have to be after the include of zend_config above */ #if defined(HAVE_LIBDL) && !defined(ZEND_WIN32) From 90d356fdf24b1cce45842b2504516a7ee2e4e040 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Mon, 16 Feb 2026 13:37:31 +0100 Subject: [PATCH 3/5] zend_portability: Rename `size` to `underlying_type` in `C23_ENUM()` --- Zend/zend_portability.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Zend/zend_portability.h b/Zend/zend_portability.h index 4c25391816fd1..d3bfddcbfac76 100644 --- a/Zend/zend_portability.h +++ b/Zend/zend_portability.h @@ -148,14 +148,14 @@ /* Define a fixed-size enum as enum C23_ENUM(name, size) { }. */ #if __STDC_VERSION__ >= 202311L || defined(__cplusplus) -# define C23_ENUM(name, size) \ - name: size; \ +# define C23_ENUM(name, underlying_type) \ + name: underlying_type; \ typedef enum name name; \ - enum name: size + enum name: underlying_type #else -# define C23_ENUM(name, size) \ +# define C23_ENUM(name, underlying_type) \ name; \ - typedef size name; \ + typedef underlying_type name; \ enum name #endif From 7ae597fe32eaf0c622361705d001e96f36fd1b80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Mon, 16 Feb 2026 13:38:18 +0100 Subject: [PATCH 4/5] zend_portability: Include the leading `enum` in the `C23_ENUM` macro --- Zend/zend_compile.h | 2 +- Zend/zend_portability.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 9991667f313aa..41bbdde5a38de 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -497,7 +497,7 @@ typedef struct _zend_class_constant { #define ZEND_CLASS_CONST_FLAGS(c) Z_CONSTANT_FLAGS((c)->value) -enum C23_ENUM(zend_function_type, uint8_t) { +C23_ENUM(zend_function_type, uint8_t) { ZEND_INTERNAL_FUNCTION = 1, ZEND_USER_FUNCTION = 2, ZEND_EVAL_CODE = 4, diff --git a/Zend/zend_portability.h b/Zend/zend_portability.h index d3bfddcbfac76..c92e653c7cb22 100644 --- a/Zend/zend_portability.h +++ b/Zend/zend_portability.h @@ -146,15 +146,15 @@ #define zend_quiet_write(...) ZEND_IGNORE_VALUE(write(__VA_ARGS__)) -/* Define a fixed-size enum as enum C23_ENUM(name, size) { }. */ +/* Define a fixed-size enum as C23_ENUM(name, size) { }. */ #if __STDC_VERSION__ >= 202311L || defined(__cplusplus) # define C23_ENUM(name, underlying_type) \ - name: underlying_type; \ + enum name: underlying_type; \ typedef enum name name; \ enum name: underlying_type #else # define C23_ENUM(name, underlying_type) \ - name; \ + enum name; \ typedef underlying_type name; \ enum name #endif From 908a84423e0e5b8249a283d136264db5cf811ceb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Mon, 16 Feb 2026 14:03:25 +0100 Subject: [PATCH 5/5] [skip ci] Fix comment for C23_ENUM() --- Zend/zend_portability.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zend/zend_portability.h b/Zend/zend_portability.h index c92e653c7cb22..c8a6dfa871b5a 100644 --- a/Zend/zend_portability.h +++ b/Zend/zend_portability.h @@ -146,7 +146,7 @@ #define zend_quiet_write(...) ZEND_IGNORE_VALUE(write(__VA_ARGS__)) -/* Define a fixed-size enum as C23_ENUM(name, size) { }. */ +/* Define an enum with a fixed underlying type as C23_ENUM(name, underlying_type) { }. */ #if __STDC_VERSION__ >= 202311L || defined(__cplusplus) # define C23_ENUM(name, underlying_type) \ enum name: underlying_type; \