Allow arbitrary const expressions in backed enums

Closes GH-7821
Closes GH-8190
Closes GH-8418
This commit is contained in:
Ilija Tovilo 2022-03-10 22:35:01 +01:00
parent 5a855ee8d6
commit ddc0b490f7
No known key found for this signature in database
GPG key ID: A4F5D403F118200A
23 changed files with 287 additions and 144 deletions

2
NEWS
View file

@ -7,6 +7,8 @@ PHP NEWS
references). (Nicolas Grekas) references). (Nicolas Grekas)
. Fixed bug GH-8661 (Nullsafe in coalesce triggers undefined variable . Fixed bug GH-8661 (Nullsafe in coalesce triggers undefined variable
warning). (ilutov) warning). (ilutov)
. Fixed bug GH-7821 and GH-8418 (Allow arbitrary const expressions in backed
enums). (ilutov)
- MBString: - MBString:
. Backwards-compatible mappings for 0x5C/0x7E in Shift-JIS are restored, . Backwards-compatible mappings for 0x5C/0x7E in Shift-JIS are restored,

View file

@ -8,6 +8,33 @@ enum Foo: int {
case Baz = 0; case Baz = 0;
} }
try {
var_dump(Foo::Bar);
} catch (Error $e) {
echo $e->getMessage(), "\n";
}
try {
var_dump(Foo::Bar);
} catch (Error $e) {
echo $e->getMessage(), "\n";
}
try {
var_dump(Foo::from(42));
} catch (Error $e) {
echo $e->getMessage(), "\n";
}
try {
var_dump(Foo::tryFrom('bar'));
} catch (Error $e) {
echo $e->getMessage(), "\n";
}
?> ?>
--EXPECTF-- --EXPECT--
Fatal error: Duplicate value in enum Foo for cases Bar and Baz in %s on line %s Duplicate value in enum Foo for cases Bar and Baz
Duplicate value in enum Foo for cases Bar and Baz
Duplicate value in enum Foo for cases Bar and Baz
Foo::tryFrom(): Argument #1 ($value) must be of type int, string given

View file

@ -10,6 +10,33 @@ enum Suit: string {
case Spades = 'H'; case Spades = 'H';
} }
try {
var_dump(Suit::Hearts);
} catch (Error $e) {
echo $e->getMessage(), "\n";
}
try {
var_dump(Suit::Hearts);
} catch (Error $e) {
echo $e->getMessage(), "\n";
}
try {
var_dump(Suit::from(42));
} catch (Error $e) {
echo $e->getMessage(), "\n";
}
try {
var_dump(Suit::tryFrom('bar'));
} catch (Error $e) {
echo $e->getMessage(), "\n";
}
?> ?>
--EXPECTF-- --EXPECT--
Fatal error: Duplicate value in enum Suit for cases Hearts and Spades in %s on line %s Duplicate value in enum Suit for cases Hearts and Spades
Duplicate value in enum Suit for cases Hearts and Spades
Duplicate value in enum Suit for cases Hearts and Spades
Duplicate value in enum Suit for cases Hearts and Spades

View file

@ -11,4 +11,4 @@ var_dump(Foo::Bar->value);
?> ?>
--EXPECTF-- --EXPECTF--
Fatal error: Enum case value must be compile-time evaluatable in %s on line %d Fatal error: Constant expression contains invalid operations in %s on line %d

View file

@ -7,6 +7,33 @@ enum Foo: int {
case Bar = 'bar'; case Bar = 'bar';
} }
try {
var_dump(Foo::Bar);
} catch (Error $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}
try {
var_dump(Foo::Bar);
} catch (Error $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}
try {
var_dump(Foo::from(42));
} catch (Error $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}
try {
var_dump(Foo::from('bar'));
} catch (Error $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}
?> ?>
--EXPECTF-- --EXPECT--
Fatal error: Enum case type string does not match enum backing type int in %s on line %d TypeError: Enum case type string does not match enum backing type int
TypeError: Enum case type string does not match enum backing type int
TypeError: Enum case type string does not match enum backing type int
TypeError: Foo::from(): Argument #1 ($value) must be of type int, string given

View file

@ -0,0 +1,26 @@
--TEST--
GH-7821: Can't use arbitrary constant expressions in enum cases
--FILE--
<?php
interface I {
public const A = 'A';
public const B = 'B';
}
enum B: string implements I {
case C = I::A;
case D = self::B;
}
var_dump(B::A);
var_dump(B::B);
var_dump(B::C->value);
var_dump(B::D->value);
?>
--EXPECT--
string(1) "A"
string(1) "B"
string(1) "A"
string(1) "B"

View file

@ -0,0 +1,20 @@
--TEST--
GH-8418: Enum constant expression evaluation doesn't work with warmed cache
--FILE--
<?php
class ExampleClass
{
public const EXAMPLE_CONST = 42;
}
enum ExampleEnum: int
{
case ENUM_CASE = ExampleClass::EXAMPLE_CONST;
}
var_dump(ExampleEnum::ENUM_CASE->value);
?>
--EXPECT--
int(42)

View file

@ -9,4 +9,4 @@ enum Foo {
?> ?>
--EXPECTF-- --EXPECTF--
Fatal error: Case Bar of non-backed enum Foo must not have a value, try adding ": int" to the enum declaration in %s on line %d Fatal error: Case Bar of non-backed enum Foo must not have a value in %s on line %d

View file

@ -9,4 +9,4 @@ enum Foo {
?> ?>
--EXPECTF-- --EXPECTF--
Fatal error: Case Bar of non-backed enum Foo must not have a value, try adding ": int" to the enum declaration in %s on line %d Fatal error: Case Bar of non-backed enum Foo must not have a value in %s on line %d

View file

@ -9,4 +9,4 @@ enum Foo {
?> ?>
--EXPECTF-- --EXPECTF--
Fatal error: Case Bar of non-backed enum Foo must not have a value, try adding ": string" to the enum declaration in %s on line %d Fatal error: Case Bar of non-backed enum Foo must not have a value in %s on line %d

View file

@ -0,0 +1,17 @@
--TEST--
Test failure of updating class constants
--FILE--
<?php
enum Foo: string {
const Bar = NONEXISTENT;
}
var_dump(Foo::Bar);
?>
--EXPECTF--
Fatal error: Uncaught Error: Undefined constant "NONEXISTENT" in %s:%d
Stack trace:
#0 {main}
thrown in %s on line %d

View file

@ -30,6 +30,7 @@
#include "zend_closures.h" #include "zend_closures.h"
#include "zend_inheritance.h" #include "zend_inheritance.h"
#include "zend_ini.h" #include "zend_ini.h"
#include "zend_enum.h"
#include <stdarg.h> #include <stdarg.h>
@ -1493,6 +1494,12 @@ ZEND_API zend_result zend_update_class_constants(zend_class_entry *class_type) /
} }
} }
if (class_type->type == ZEND_USER_CLASS && class_type->ce_flags & ZEND_ACC_ENUM && class_type->enum_backing_type != IS_UNDEF) {
if (zend_enum_build_backed_enum_table(class_type) == FAILURE) {
return FAILURE;
}
}
ce_flags |= ZEND_ACC_CONSTANTS_UPDATED; ce_flags |= ZEND_ACC_CONSTANTS_UPDATED;
ce_flags &= ~ZEND_ACC_HAS_AST_CONSTANTS; ce_flags &= ~ZEND_ACC_HAS_AST_CONSTANTS;
ce_flags &= ~ZEND_ACC_HAS_AST_PROPERTIES; ce_flags &= ~ZEND_ACC_HAS_AST_PROPERTIES;

View file

@ -776,12 +776,18 @@ ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate(zval *result, zend_ast *ast
zend_string *case_name = zend_ast_get_str(case_name_ast); zend_string *case_name = zend_ast_get_str(case_name_ast);
zend_ast *case_value_ast = ast->child[2]; zend_ast *case_value_ast = ast->child[2];
zval *case_value_zv = case_value_ast != NULL
? zend_ast_get_zval(case_value_ast) zval case_value_zv;
: NULL; ZVAL_UNDEF(&case_value_zv);
if (case_value_ast != NULL) {
if (UNEXPECTED(zend_ast_evaluate(&case_value_zv, case_value_ast, scope) != SUCCESS)) {
return FAILURE;
}
}
zend_class_entry *ce = zend_lookup_class(class_name); zend_class_entry *ce = zend_lookup_class(class_name);
zend_enum_new(result, ce, case_name, case_value_zv); zend_enum_new(result, ce, case_name, case_value_ast != NULL ? &case_value_zv : NULL);
zval_ptr_dtor_nogc(&case_value_zv);
break; break;
} }
case ZEND_AST_CLASS_CONST: case ZEND_AST_CLASS_CONST:

View file

@ -7578,9 +7578,6 @@ static void zend_compile_enum_backing_type(zend_class_entry *ce, zend_ast *enum_
ce->enum_backing_type = IS_STRING; ce->enum_backing_type = IS_STRING;
} }
zend_type_release(type, 0); zend_type_release(type, 0);
ce->backed_enum_table = emalloc(sizeof(HashTable));
zend_hash_init(ce->backed_enum_table, 0, NULL, ZVAL_PTR_DTOR, 0);
} }
static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel) /* {{{ */ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel) /* {{{ */
@ -7792,69 +7789,20 @@ static void zend_compile_enum_case(zend_ast *ast)
ZVAL_STR_COPY(&case_name_zval, enum_case_name); ZVAL_STR_COPY(&case_name_zval, enum_case_name);
zend_ast *case_name_ast = zend_ast_create_zval(&case_name_zval); zend_ast *case_name_ast = zend_ast_create_zval(&case_name_zval);
zend_ast *case_value_zval_ast = NULL;
zend_ast *case_value_ast = ast->child[1]; zend_ast *case_value_ast = ast->child[1];
// Remove case_value_ast from the original AST to avoid freeing it, as it will be freed by zend_const_expr_to_zval
ast->child[1] = NULL;
if (enum_class->enum_backing_type != IS_UNDEF && case_value_ast == NULL) { if (enum_class->enum_backing_type != IS_UNDEF && case_value_ast == NULL) {
zend_error_noreturn(E_COMPILE_ERROR, "Case %s of backed enum %s must have a value", zend_error_noreturn(E_COMPILE_ERROR, "Case %s of backed enum %s must have a value",
ZSTR_VAL(enum_case_name), ZSTR_VAL(enum_case_name),
ZSTR_VAL(enum_class_name)); ZSTR_VAL(enum_class_name));
} } else if (enum_class->enum_backing_type == IS_UNDEF && case_value_ast != NULL) {
if (case_value_ast != NULL) { zend_error_noreturn(E_COMPILE_ERROR, "Case %s of non-backed enum %s must not have a value",
zend_eval_const_expr(&ast->child[1]); ZSTR_VAL(enum_case_name),
case_value_ast = ast->child[1]; ZSTR_VAL(enum_class_name));
if (case_value_ast->kind != ZEND_AST_ZVAL) {
zend_error_noreturn(
E_COMPILE_ERROR, "Enum case value must be compile-time evaluatable");
}
zval case_value_zv;
ZVAL_COPY(&case_value_zv, zend_ast_get_zval(case_value_ast));
if (enum_class->enum_backing_type == IS_UNDEF) {
if (Z_TYPE(case_value_zv) == IS_LONG || Z_TYPE(case_value_zv) == IS_STRING) {
zend_error_noreturn(E_COMPILE_ERROR, "Case %s of non-backed enum %s must not have a value, try adding \": %s\" to the enum declaration",
ZSTR_VAL(enum_case_name),
ZSTR_VAL(enum_class_name),
zend_zval_type_name(&case_value_zv));
} else {
zend_error_noreturn(E_COMPILE_ERROR, "Case %s of non-backed enum %s must not have a value",
ZSTR_VAL(enum_case_name),
ZSTR_VAL(enum_class_name));
}
}
if (enum_class->enum_backing_type != Z_TYPE(case_value_zv)) {
zend_error_noreturn(E_COMPILE_ERROR, "Enum case type %s does not match enum backing type %s",
zend_get_type_by_const(Z_TYPE(case_value_zv)),
zend_get_type_by_const(enum_class->enum_backing_type));
}
case_value_zval_ast = zend_ast_create_zval(&case_value_zv);
Z_TRY_ADDREF(case_name_zval);
if (enum_class->enum_backing_type == IS_LONG) {
zend_long long_key = Z_LVAL(case_value_zv);
zval *existing_case_name = zend_hash_index_find(enum_class->backed_enum_table, long_key);
if (existing_case_name) {
zend_error_noreturn(E_COMPILE_ERROR, "Duplicate value in enum %s for cases %s and %s",
ZSTR_VAL(enum_class_name),
Z_STRVAL_P(existing_case_name),
ZSTR_VAL(enum_case_name));
}
zend_hash_index_add_new(enum_class->backed_enum_table, long_key, &case_name_zval);
} else {
ZEND_ASSERT(enum_class->enum_backing_type == IS_STRING);
zend_string *string_key = Z_STR(case_value_zv);
zval *existing_case_name = zend_hash_find(enum_class->backed_enum_table, string_key);
if (existing_case_name != NULL) {
zend_error_noreturn(E_COMPILE_ERROR, "Duplicate value in enum %s for cases %s and %s",
ZSTR_VAL(enum_class_name),
Z_STRVAL_P(existing_case_name),
ZSTR_VAL(enum_case_name));
}
zend_hash_add_new(enum_class->backed_enum_table, string_key, &case_name_zval);
}
} }
zend_ast *const_enum_init_ast = zend_ast_create(ZEND_AST_CONST_ENUM_INIT, class_name_ast, case_name_ast, case_value_zval_ast); zend_ast *const_enum_init_ast = zend_ast_create(ZEND_AST_CONST_ENUM_INIT, class_name_ast, case_name_ast, case_value_ast);
zval value_zv; zval value_zv;
zend_const_expr_to_zval(&value_zv, &const_enum_init_ast, /* allow_dynamic */ false); zend_const_expr_to_zval(&value_zv, &const_enum_init_ast, /* allow_dynamic */ false);

View file

@ -21,6 +21,7 @@
#include "zend_compile.h" #include "zend_compile.h"
#include "zend_enum_arginfo.h" #include "zend_enum_arginfo.h"
#include "zend_interfaces.h" #include "zend_interfaces.h"
#include "zend_enum.h"
#define ZEND_ENUM_DISALLOW_MAGIC_METHOD(propertyName, methodName) \ #define ZEND_ENUM_DISALLOW_MAGIC_METHOD(propertyName, methodName) \
do { \ do { \
@ -183,6 +184,72 @@ void zend_enum_add_interfaces(zend_class_entry *ce)
} }
} }
zend_result zend_enum_build_backed_enum_table(zend_class_entry *ce)
{
ZEND_ASSERT(ce->ce_flags & ZEND_ACC_ENUM);
ZEND_ASSERT(ce->type == ZEND_USER_CLASS);
uint32_t backing_type = ce->enum_backing_type;
ZEND_ASSERT(backing_type != IS_UNDEF);
ce->backed_enum_table = emalloc(sizeof(HashTable));
zend_hash_init(ce->backed_enum_table, 0, NULL, ZVAL_PTR_DTOR, 0);
zend_string *enum_class_name = ce->name;
zend_string *name;
zval *val;
ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(&ce->constants_table, name, val) {
zend_class_constant *c = Z_PTR_P(val);
if ((ZEND_CLASS_CONST_FLAGS(c) & ZEND_CLASS_CONST_IS_CASE) == 0) {
continue;
}
zval *c_value = &c->value;
zval *case_name = zend_enum_fetch_case_name(Z_OBJ_P(c_value));
zval *case_value = zend_enum_fetch_case_value(Z_OBJ_P(c_value));
if (ce->enum_backing_type != Z_TYPE_P(case_value)) {
zend_type_error("Enum case type %s does not match enum backing type %s",
zend_get_type_by_const(Z_TYPE_P(case_value)),
zend_get_type_by_const(ce->enum_backing_type));
goto failure;
}
if (ce->enum_backing_type == IS_LONG) {
zend_long long_key = Z_LVAL_P(case_value);
zval *existing_case_name = zend_hash_index_find(ce->backed_enum_table, long_key);
if (existing_case_name) {
zend_throw_error(NULL, "Duplicate value in enum %s for cases %s and %s",
ZSTR_VAL(enum_class_name),
Z_STRVAL_P(existing_case_name),
ZSTR_VAL(name));
goto failure;
}
zend_hash_index_add_new(ce->backed_enum_table, long_key, case_name);
} else {
ZEND_ASSERT(ce->enum_backing_type == IS_STRING);
zend_string *string_key = Z_STR_P(case_value);
zval *existing_case_name = zend_hash_find(ce->backed_enum_table, string_key);
if (existing_case_name != NULL) {
zend_throw_error(NULL, "Duplicate value in enum %s for cases %s and %s",
ZSTR_VAL(enum_class_name),
Z_STRVAL_P(existing_case_name),
ZSTR_VAL(name));
goto failure;
}
zend_hash_add_new(ce->backed_enum_table, string_key, case_name);
}
} ZEND_HASH_FOREACH_END();
return SUCCESS;
failure:
zend_hash_release(ce->backed_enum_table);
ce->backed_enum_table = NULL;
return FAILURE;
}
static ZEND_NAMED_FUNCTION(zend_enum_cases_func) static ZEND_NAMED_FUNCTION(zend_enum_cases_func)
{ {
zend_class_entry *ce = execute_data->func->common.scope; zend_class_entry *ce = execute_data->func->common.scope;
@ -209,6 +276,12 @@ static ZEND_NAMED_FUNCTION(zend_enum_cases_func)
ZEND_API zend_result zend_enum_get_case_by_value(zend_object **result, zend_class_entry *ce, zend_long long_key, zend_string *string_key, bool try) ZEND_API zend_result zend_enum_get_case_by_value(zend_object **result, zend_class_entry *ce, zend_long long_key, zend_string *string_key, bool try)
{ {
if (ce->type == ZEND_USER_CLASS && !(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
if (zend_update_class_constants(ce) == FAILURE) {
return FAILURE;
}
}
zval *case_name_zv; zval *case_name_zv;
if (ce->enum_backing_type == IS_LONG) { if (ce->enum_backing_type == IS_LONG) {
case_name_zv = zend_hash_index_find(ce->backed_enum_table, long_key); case_name_zv = zend_hash_index_find(ce->backed_enum_table, long_key);

View file

@ -29,6 +29,7 @@ extern ZEND_API zend_class_entry *zend_ce_backed_enum;
void zend_register_enum_ce(void); void zend_register_enum_ce(void);
void zend_enum_add_interfaces(zend_class_entry *ce); void zend_enum_add_interfaces(zend_class_entry *ce);
zend_result zend_enum_build_backed_enum_table(zend_class_entry *ce);
zend_object *zend_enum_new(zval *result, zend_class_entry *ce, zend_string *case_name, zval *backing_value_zv); zend_object *zend_enum_new(zval *result, zend_class_entry *ce, zend_string *case_name, zval *backing_value_zv);
void zend_verify_enum(zend_class_entry *ce); void zend_verify_enum(zend_class_entry *ce);
void zend_enum_register_funcs(zend_class_entry *ce); void zend_enum_register_funcs(zend_class_entry *ce);

View file

@ -330,9 +330,6 @@ ZEND_API void destroy_zend_class(zval *zv)
if (ce->attributes) { if (ce->attributes) {
zend_hash_release(ce->attributes); zend_hash_release(ce->attributes);
} }
if (ce->backed_enum_table) {
zend_hash_release(ce->backed_enum_table);
}
if (ce->num_interfaces > 0 && !(ce->ce_flags & ZEND_ACC_RESOLVED_INTERFACES)) { if (ce->num_interfaces > 0 && !(ce->ce_flags & ZEND_ACC_RESOLVED_INTERFACES)) {
uint32_t i; uint32_t i;
@ -403,6 +400,9 @@ ZEND_API void destroy_zend_class(zval *zv)
if (ce->num_interfaces > 0 && (ce->ce_flags & ZEND_ACC_RESOLVED_INTERFACES)) { if (ce->num_interfaces > 0 && (ce->ce_flags & ZEND_ACC_RESOLVED_INTERFACES)) {
efree(ce->interfaces); efree(ce->interfaces);
} }
if (ce->backed_enum_table) {
zend_hash_release(ce->backed_enum_table);
}
break; break;
case ZEND_INTERNAL_CLASS: case ZEND_INTERNAL_CLASS:
if (ce->backed_enum_table) { if (ce->backed_enum_table) {

View file

@ -5896,6 +5896,13 @@ ZEND_VM_HANDLER(181, ZEND_FETCH_CLASS_CONSTANT, VAR|CONST|UNUSED|CLASS_FETCH, CO
HANDLE_EXCEPTION(); HANDLE_EXCEPTION();
} }
value = &c->value; value = &c->value;
// Enums require loading of all class constants to build the backed enum table
if (ce->ce_flags & ZEND_ACC_ENUM && ce->enum_backing_type != IS_UNDEF && ce->type == ZEND_USER_CLASS && !(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
if (UNEXPECTED(zend_update_class_constants(ce) == FAILURE)) {
ZVAL_UNDEF(EX_VAR(opline->result.var));
HANDLE_EXCEPTION();
}
}
if (Z_TYPE_P(value) == IS_CONSTANT_AST) { if (Z_TYPE_P(value) == IS_CONSTANT_AST) {
zval_update_constant_ex(value, c->ce); zval_update_constant_ex(value, c->ce);
if (UNEXPECTED(EG(exception) != NULL)) { if (UNEXPECTED(EG(exception) != NULL)) {

21
Zend/zend_vm_execute.h generated
View file

@ -7069,6 +7069,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_CONS
HANDLE_EXCEPTION(); HANDLE_EXCEPTION();
} }
value = &c->value; value = &c->value;
// Enums require loading of all class constants to build the backed enum table
if (ce->ce_flags & ZEND_ACC_ENUM && ce->enum_backing_type != IS_UNDEF && ce->type == ZEND_USER_CLASS && !(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
if (UNEXPECTED(zend_update_class_constants(ce) == FAILURE)) {
ZVAL_UNDEF(EX_VAR(opline->result.var));
HANDLE_EXCEPTION();
}
}
if (Z_TYPE_P(value) == IS_CONSTANT_AST) { if (Z_TYPE_P(value) == IS_CONSTANT_AST) {
zval_update_constant_ex(value, c->ce); zval_update_constant_ex(value, c->ce);
if (UNEXPECTED(EG(exception) != NULL)) { if (UNEXPECTED(EG(exception) != NULL)) {
@ -24622,6 +24629,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_VAR_
HANDLE_EXCEPTION(); HANDLE_EXCEPTION();
} }
value = &c->value; value = &c->value;
// Enums require loading of all class constants to build the backed enum table
if (ce->ce_flags & ZEND_ACC_ENUM && ce->enum_backing_type != IS_UNDEF && ce->type == ZEND_USER_CLASS && !(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
if (UNEXPECTED(zend_update_class_constants(ce) == FAILURE)) {
ZVAL_UNDEF(EX_VAR(opline->result.var));
HANDLE_EXCEPTION();
}
}
if (Z_TYPE_P(value) == IS_CONSTANT_AST) { if (Z_TYPE_P(value) == IS_CONSTANT_AST) {
zval_update_constant_ex(value, c->ce); zval_update_constant_ex(value, c->ce);
if (UNEXPECTED(EG(exception) != NULL)) { if (UNEXPECTED(EG(exception) != NULL)) {
@ -33460,6 +33474,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_UNUS
HANDLE_EXCEPTION(); HANDLE_EXCEPTION();
} }
value = &c->value; value = &c->value;
// Enums require loading of all class constants to build the backed enum table
if (ce->ce_flags & ZEND_ACC_ENUM && ce->enum_backing_type != IS_UNDEF && ce->type == ZEND_USER_CLASS && !(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
if (UNEXPECTED(zend_update_class_constants(ce) == FAILURE)) {
ZVAL_UNDEF(EX_VAR(opline->result.var));
HANDLE_EXCEPTION();
}
}
if (Z_TYPE_P(value) == IS_CONSTANT_AST) { if (Z_TYPE_P(value) == IS_CONSTANT_AST) {
zval_update_constant_ex(value, c->ce); zval_update_constant_ex(value, c->ce);
if (UNEXPECTED(EG(exception) != NULL)) { if (UNEXPECTED(EG(exception) != NULL)) {

View file

@ -848,14 +848,6 @@ static void zend_file_cache_serialize_class(zval *zv,
} }
} }
if (ce->backed_enum_table) {
HashTable *ht;
SERIALIZE_PTR(ce->backed_enum_table);
ht = ce->backed_enum_table;
UNSERIALIZE_PTR(ht);
zend_file_cache_serialize_hash(ht, script, info, buf, zend_file_cache_serialize_zval);
}
SERIALIZE_PTR(ce->constructor); SERIALIZE_PTR(ce->constructor);
SERIALIZE_PTR(ce->destructor); SERIALIZE_PTR(ce->destructor);
SERIALIZE_PTR(ce->clone); SERIALIZE_PTR(ce->clone);
@ -1645,12 +1637,6 @@ static void zend_file_cache_unserialize_class(zval *zv,
} }
} }
if (ce->backed_enum_table) {
UNSERIALIZE_PTR(ce->backed_enum_table);
zend_file_cache_unserialize_hash(
ce->backed_enum_table, script, buf, zend_file_cache_unserialize_zval, ZVAL_PTR_DTOR);
}
UNSERIALIZE_PTR(ce->constructor); UNSERIALIZE_PTR(ce->constructor);
UNSERIALIZE_PTR(ce->destructor); UNSERIALIZE_PTR(ce->destructor);
UNSERIALIZE_PTR(ce->clone); UNSERIALIZE_PTR(ce->clone);

View file

@ -336,35 +336,6 @@ uint32_t zend_accel_get_class_name_map_ptr(zend_string *type_name)
return 0; return 0;
} }
static HashTable *zend_persist_backed_enum_table(HashTable *backed_enum_table)
{
HashTable *ptr;
zend_hash_persist(backed_enum_table);
if (HT_IS_PACKED(backed_enum_table)) {
zval *zv;
ZEND_HASH_PACKED_FOREACH_VAL(backed_enum_table, zv) {
zend_persist_zval(zv);
} ZEND_HASH_FOREACH_END();
} else {
Bucket *p;
ZEND_HASH_MAP_FOREACH_BUCKET(backed_enum_table, p) {
if (p->key != NULL) {
zend_accel_store_interned_string(p->key);
}
zend_persist_zval(&p->val);
} ZEND_HASH_FOREACH_END();
}
ptr = zend_shared_memdup_free(backed_enum_table, sizeof(HashTable));
GC_SET_REFCOUNT(ptr, 2);
GC_TYPE_INFO(ptr) = GC_ARRAY | ((IS_ARRAY_IMMUTABLE|GC_NOT_COLLECTABLE) << GC_FLAGS_SHIFT);
return ptr;
}
static void zend_persist_type(zend_type *type) { static void zend_persist_type(zend_type *type) {
if (ZEND_TYPE_HAS_LIST(*type)) { if (ZEND_TYPE_HAS_LIST(*type)) {
zend_type_list *list = ZEND_TYPE_LIST(*type); zend_type_list *list = ZEND_TYPE_LIST(*type);
@ -1072,9 +1043,7 @@ zend_class_entry *zend_persist_class_entry(zend_class_entry *orig_ce)
} }
} }
if (ce->backed_enum_table) { ZEND_ASSERT(ce->backed_enum_table == NULL);
ce->backed_enum_table = zend_persist_backed_enum_table(ce->backed_enum_table);
}
} }
return ce; return ce;

View file

@ -547,27 +547,6 @@ void zend_persist_class_entry_calc(zend_class_entry *ce)
ADD_SIZE(sizeof(zend_trait_precedence*) * (i + 1)); ADD_SIZE(sizeof(zend_trait_precedence*) * (i + 1));
} }
} }
if (ce->backed_enum_table) {
ADD_SIZE(sizeof(HashTable));
zend_hash_persist_calc(ce->backed_enum_table);
if (HT_IS_PACKED(ce->backed_enum_table)) {
zval *zv;
ZEND_HASH_PACKED_FOREACH_VAL(ce->backed_enum_table, zv) {
zend_persist_zval_calc(zv);
} ZEND_HASH_FOREACH_END();
} else {
Bucket *p;
ZEND_HASH_MAP_FOREACH_BUCKET(ce->backed_enum_table, p) {
if (p->key != NULL) {
ADD_INTERNED_STRING(p->key);
}
zend_persist_zval_calc(&p->val);
} ZEND_HASH_FOREACH_END();
}
}
} }
} }

View file

@ -1485,7 +1485,7 @@ static void reflection_enum_case_factory(zend_class_entry *ce, zend_string *name
{ {
reflection_object *intern; reflection_object *intern;
zend_class_entry *case_reflection_class = ce->backed_enum_table == IS_UNDEF zend_class_entry *case_reflection_class = ce->enum_backing_type == IS_UNDEF
? reflection_enum_unit_case_ptr ? reflection_enum_unit_case_ptr
: reflection_enum_backed_case_ptr; : reflection_enum_backed_case_ptr;
reflection_instantiate(case_reflection_class, object); reflection_instantiate(case_reflection_class, object);