From: Nikita Popov Date: Fri, 4 Jan 2019 10:38:35 +0000 (+0100) Subject: Support parent::class inside constexpr contexts X-Git-Tag: php-7.4.0alpha1~1291 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=447b3470de43bf2435ad5a138a964c2f2c4fc4a6;p=php Support parent::class inside constexpr contexts --- diff --git a/Zend/tests/class_name_as_scalar_error_002.phpt b/Zend/tests/class_name_as_scalar_error_002.phpt index 59b7a2edc9..3abba7f7fe 100644 --- a/Zend/tests/class_name_as_scalar_error_002.phpt +++ b/Zend/tests/class_name_as_scalar_error_002.phpt @@ -7,7 +7,11 @@ namespace Foo\Bar { class One { const Baz = parent::class; } + var_dump(One::Baz); } ?> --EXPECTF-- -Fatal error: parent::class cannot be used for compile-time class name resolution in %s on line %d +Fatal error: Uncaught Error: Cannot use "parent" when current class scope has no parent in %s:%d +Stack trace: +#0 {main} + thrown in %s on line %d diff --git a/Zend/tests/class_name_as_scalar_error_004.phpt b/Zend/tests/class_name_as_scalar_error_004.phpt index c00037fca3..5b743df2db 100644 --- a/Zend/tests/class_name_as_scalar_error_004.phpt +++ b/Zend/tests/class_name_as_scalar_error_004.phpt @@ -4,10 +4,14 @@ class name as scalar from ::class keyword error using parent in method signature baz(); } ?> ---EXPECTF-- -Fatal error: parent::class cannot be used for compile-time class name resolution in %s on line %d +--EXPECT-- +string(11) "Foo\Bar\One" diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index bea20f646b..08fde1d1b0 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -511,19 +511,28 @@ ZEND_API int ZEND_FASTCALL zend_ast_evaluate(zval *result, zend_ast *ast, zend_c break; } case ZEND_AST_CONSTANT_CLASS: - if (scope && scope->name) { + if (scope) { ZVAL_STR_COPY(result, scope->name); } else { ZVAL_EMPTY_STRING(result); } break; case ZEND_AST_CLASS_NAME: - ZEND_ASSERT(ast->attr == ZEND_FETCH_CLASS_SELF); - if (scope && scope->name) { + if (!scope) { + zend_throw_error(NULL, "Cannot use \"self\" when no class scope is active"); + return FAILURE; + } + if (ast->attr == ZEND_FETCH_CLASS_SELF) { ZVAL_STR_COPY(result, scope->name); + } else if (ast->attr == ZEND_FETCH_CLASS_PARENT) { + if (!scope->parent) { + zend_throw_error(NULL, + "Cannot use \"parent\" when current class scope has no parent"); + return FAILURE; + } + ZVAL_STR_COPY(result, scope->parent->name); } else { - zend_throw_error(NULL, "Cannot use \"self\" when no class scope is active"); - ret = FAILURE; + ZEND_ASSERT(0 && "Should have errored during compilation"); } break; case ZEND_AST_AND: diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 30a648f326..3dc19a30b1 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -7958,18 +7958,20 @@ void zend_compile_const_expr_class_name(zend_ast **ast_ptr) /* {{{ */ zend_string *class_name = zend_ast_get_str(class_ast); uint32_t fetch_type = zend_get_class_fetch_type(class_name); - /* For the const-eval representation store the fetch type instead of the name. */ - if (fetch_type == ZEND_FETCH_CLASS_SELF) { - zend_string_release(class_name); - ast->child[0] = NULL; - ast->attr = fetch_type; - return; + switch (fetch_type) { + case ZEND_FETCH_CLASS_SELF: + case ZEND_FETCH_CLASS_PARENT: + /* For the const-eval representation store the fetch type instead of the name. */ + zend_string_release(class_name); + ast->child[0] = NULL; + ast->attr = fetch_type; + return; + case ZEND_FETCH_CLASS_STATIC: + zend_error_noreturn(E_COMPILE_ERROR, + "static::class cannot be used for compile-time class name resolution"); + return; + EMPTY_SWITCH_DEFAULT_CASE() } - - zend_error_noreturn(E_COMPILE_ERROR, - "%s::class cannot be used for compile-time class name resolution", - fetch_type == ZEND_FETCH_CLASS_STATIC ? "static" : "parent" - ); } void zend_compile_const_expr_const(zend_ast **ast_ptr) /* {{{ */