Commit 9c900b6e348 for php.net
commit 9c900b6e3485d49b4fc5d677ff3d139926f61644
Author: Tim Düsterhus <tim@tideways-gmbh.com>
Date: Mon Feb 16 14:19:29 2026 +0100
zend_compile: Bundle function type constants into an `zend_function_type` enum (#21208)
* 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.
* Add C23_ENUM() helper macro
* zend_portability: Rename `size` to `underlying_type` in `C23_ENUM()`
* zend_portability: Include the leading `enum` in the `C23_ENUM` macro
* Fix comment for C23_ENUM()
diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS
index 06c1d528262..0c8e10e17f0 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 587ae485ec8..41bbdde5a38 100644
--- a/Zend/zend_compile.h
+++ b/Zend/zend_compile.h
@@ -497,6 +497,12 @@ typedef struct _zend_class_constant {
#define ZEND_CLASS_CONST_FLAGS(c) Z_CONSTANT_FLAGS((c)->value)
+C23_ENUM(zend_function_type, uint8_t) {
+ ZEND_INTERNAL_FUNCTION = 1,
+ ZEND_USER_FUNCTION = 2,
+ ZEND_EVAL_CODE = 4,
+};
+
/* arg_info for internal functions */
typedef struct _zend_internal_arg_info {
const char *name;
@@ -524,7 +530,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 +590,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 +616,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 +962,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 +1077,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 5a8a78cc3bd..1c985189fd3 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 d874f566dc8..24b480ad71e 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;
diff --git a/Zend/zend_portability.h b/Zend/zend_portability.h
index 6546ebfb5b7..c8a6dfa871b 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 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; \
+ typedef enum name name; \
+ enum name: underlying_type
+#else
+# define C23_ENUM(name, underlying_type) \
+ enum name; \
+ typedef underlying_type 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)