From: Nikita Popov Date: Fri, 4 Jan 2019 10:28:07 +0000 (+0100) Subject: Handle self::class separately from __CLASS__ in const eval X-Git-Tag: php-7.4.0alpha1~1292 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f58846a15d0460d1f2dcee92540c5c639c937ee9;p=php Handle self::class separately from __CLASS__ in const eval --- diff --git a/Zend/tests/self_class_const_in_unknown_scope.phpt b/Zend/tests/self_class_const_in_unknown_scope.phpt index 240644dea8..2eb3a89d71 100644 --- a/Zend/tests/self_class_const_in_unknown_scope.phpt +++ b/Zend/tests/self_class_const_in_unknown_scope.phpt @@ -13,11 +13,14 @@ class Test { } (new Test)->foobar(); -// This should error, but doesn't const BAR = self::class; var_dump(BAR); ?> ---EXPECT-- +--EXPECTF-- string(4) "Test" -string(0) "" + +Fatal error: Uncaught Error: Cannot use "self" when no class scope is active in %s:%d +Stack trace: +#0 {main} + thrown in %s on line %d diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index 597dcc3edd..bea20f646b 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -511,13 +511,21 @@ ZEND_API int ZEND_FASTCALL zend_ast_evaluate(zval *result, zend_ast *ast, zend_c break; } case ZEND_AST_CONSTANT_CLASS: - ZEND_ASSERT(EG(current_execute_data)); if (scope && scope->name) { 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) { + ZVAL_STR_COPY(result, scope->name); + } else { + zend_throw_error(NULL, "Cannot use \"self\" when no class scope is active"); + ret = FAILURE; + } + break; case ZEND_AST_AND: if (UNEXPECTED(zend_ast_evaluate(&op1, ast->child[0], scope) != SUCCESS)) { ret = FAILURE; diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index f3f12ddbf1..30a648f326 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -7953,14 +7953,16 @@ void zend_compile_const_expr_class_const(zend_ast **ast_ptr) /* {{{ */ void zend_compile_const_expr_class_name(zend_ast **ast_ptr) /* {{{ */ { - zend_ast *class_ast = (*ast_ptr)->child[0]; - uint32_t fetch_type = zend_get_class_fetch_type(zend_ast_get_str(class_ast)); + zend_ast *ast = *ast_ptr; + zend_ast *class_ast = ast->child[0]; + zend_string *class_name = zend_ast_get_str(class_ast); + uint32_t fetch_type = zend_get_class_fetch_type(class_name); - /* TODO We should not use AST_CONSTANT_CLASS for this, because the semantics are slightly - * different. */ + /* For the const-eval representation store the fetch type instead of the name. */ if (fetch_type == ZEND_FETCH_CLASS_SELF) { - zend_ast_destroy(*ast_ptr); - *ast_ptr = zend_ast_create(ZEND_AST_CONSTANT_CLASS); + zend_string_release(class_name); + ast->child[0] = NULL; + ast->attr = fetch_type; return; }