return (zend_ast *) ast;
}
+ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_class_const_or_name(zend_ast *class, zend_ast *name) {
+ zend_string *name_str = zend_ast_get_str(name);
+ if (zend_string_equals_literal_ci(name_str, "class")) {
+ zend_string_release(name_str);
+ return zend_ast_create(ZEND_AST_CLASS_NAME, class);
+ } else {
+ return zend_ast_create(ZEND_AST_CLASS_CONST, class, name);
+ }
+}
+
ZEND_API zend_ast *zend_ast_create_decl(
zend_ast_kind kind, uint32_t flags, uint32_t start_lineno, zend_string *doc_comment,
zend_string *name, zend_ast *child0, zend_ast *child1, zend_ast *child2, zend_ast *child3
smart_str_appends(str, "::");
zend_ast_export_name(str, ast->child[1], 0, indent);
break;
+ case ZEND_AST_CLASS_NAME:
+ zend_ast_export_ns_name(str, ast->child[0], 0, indent);
+ smart_str_appends(str, "::class");
+ break;
case ZEND_AST_ASSIGN: BINARY_OP(" = ", 90, 91, 90);
case ZEND_AST_ASSIGN_REF: BINARY_OP(" =& ", 90, 91, 90);
case ZEND_AST_ASSIGN_OP:
}
/* }}} */
-static zend_bool zend_try_compile_const_expr_resolve_class_name(zval *zv, zend_ast *class_ast, zend_ast *name_ast, zend_bool constant) /* {{{ */
+static zend_bool zend_try_compile_const_expr_resolve_class_name(zval *zv, zend_ast *class_ast, zend_bool constant) /* {{{ */
{
uint32_t fetch_type;
- if (name_ast->kind != ZEND_AST_ZVAL) {
- return 0;
- }
-
- if (!zend_string_equals_literal_ci(zend_ast_get_str(name_ast), "class")) {
- return 0;
- }
-
if (class_ast->kind != ZEND_AST_ZVAL) {
- zend_error_noreturn(E_COMPILE_ERROR,
- "Dynamic class names are not allowed in compile-time ::class fetch");
+ zend_error_noreturn(E_COMPILE_ERROR, "Cannot use ::class with dynamic class name");
}
fetch_type = zend_get_class_fetch_type(zend_ast_get_str(class_ast));
case ZEND_FETCH_CLASS_SELF:
if (CG(active_class_entry) && zend_is_scope_known()) {
ZVAL_STR_COPY(zv, CG(active_class_entry)->name);
- } else {
- ZVAL_NULL(zv);
+ return 1;
}
- return 1;
+ return 0;
case ZEND_FETCH_CLASS_STATIC:
case ZEND_FETCH_CLASS_PARENT:
if (constant) {
"%s::class cannot be used for compile-time class name resolution",
fetch_type == ZEND_FETCH_CLASS_STATIC ? "static" : "parent"
);
- } else {
- ZVAL_NULL(zv);
}
- return 1;
+ return 0;
case ZEND_FETCH_CLASS_DEFAULT:
ZVAL_STR(zv, zend_resolve_class_name_ast(class_ast));
return 1;
znode class_node, const_node;
zend_op *opline;
- if (zend_try_compile_const_expr_resolve_class_name(&result->u.constant, class_ast, const_ast, 0)) {
- if (Z_TYPE(result->u.constant) == IS_NULL) {
- zend_op *opline = zend_emit_op_tmp(result, ZEND_FETCH_CLASS_NAME, NULL, NULL);
- opline->op1.num = zend_get_class_fetch_type(zend_ast_get_str(class_ast));
- } else {
- result->op_type = IS_CONST;
- }
- return;
- }
-
zend_eval_const_expr(&ast->child[0]);
zend_eval_const_expr(&ast->child[1]);
}
zend_string_release_ex(resolved_name, 0);
}
- if (const_ast->kind == ZEND_AST_ZVAL && zend_string_equals_literal_ci(zend_ast_get_str(const_ast), "class")) {
- zend_error_noreturn(E_COMPILE_ERROR,
- "Dynamic class names are not allowed in compile-time ::class fetch");
- }
zend_compile_class_ref(&class_node, class_ast, ZEND_FETCH_CLASS_EXCEPTION);
}
/* }}} */
+void zend_compile_class_name(znode *result, zend_ast *ast) /* {{{ */
+{
+ zend_ast *class_ast = ast->child[0];
+ zend_op *opline;
+
+ if (zend_try_compile_const_expr_resolve_class_name(&result->u.constant, class_ast, 0)) {
+ result->op_type = IS_CONST;
+ return;
+ }
+
+ opline = zend_emit_op_tmp(result, ZEND_FETCH_CLASS_NAME, NULL, NULL);
+ opline->op1.num = zend_get_class_fetch_type(zend_ast_get_str(class_ast));
+}
+/* }}} */
+
void zend_compile_resolve_class_name(znode *result, zend_ast *ast) /* {{{ */
{
zend_ast *name_ast = ast->child[0];
|| kind == ZEND_AST_CONDITIONAL || kind == ZEND_AST_DIM
|| kind == ZEND_AST_ARRAY || kind == ZEND_AST_ARRAY_ELEM
|| kind == ZEND_AST_CONST || kind == ZEND_AST_CLASS_CONST
+ || kind == ZEND_AST_CLASS_NAME
|| kind == ZEND_AST_MAGIC_CONST || kind == ZEND_AST_COALESCE;
}
/* }}} */
zend_string *class_name;
zend_string *const_name = zend_ast_get_str(const_ast);
zend_string *name;
- zval result;
int fetch_type;
if (class_ast->kind != ZEND_AST_ZVAL) {
"Dynamic class names are not allowed in compile-time class constant references");
}
- if (zend_try_compile_const_expr_resolve_class_name(&result, class_ast, const_ast, 1)) {
- *ast_ptr = zend_ast_create_zval(&result);
- return;
- }
-
class_name = zend_ast_get_str(class_ast);
fetch_type = zend_get_class_fetch_type(class_name);
}
/* }}} */
+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));
+
+ /* If we reach here, ::class should have either been constant evaluated or replaced
+ * by a AST_MAGIC_CONST, so only the error case is left here. */
+ 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) /* {{{ */
{
zend_ast *ast = *ast_ptr;
case ZEND_AST_CLASS_CONST:
zend_compile_const_expr_class_const(ast_ptr);
break;
+ case ZEND_AST_CLASS_NAME:
+ zend_compile_const_expr_class_name(ast_ptr);
+ break;
case ZEND_AST_CONST:
zend_compile_const_expr_const(ast_ptr);
break;
case ZEND_AST_CLASS_CONST:
zend_compile_class_const(result, ast);
return;
+ case ZEND_AST_CLASS_NAME:
+ zend_compile_class_name(result, ast);
+ return;
case ZEND_AST_ENCAPS_LIST:
zend_compile_encaps_list(result, ast);
return;
}
case ZEND_AST_CLASS_CONST:
{
- zend_ast *class_ast = ast->child[0];
- zend_ast *name_ast = ast->child[1];
+ zend_ast *class_ast;
+ zend_ast *name_ast;
zend_string *resolved_name;
- if (zend_try_compile_const_expr_resolve_class_name(&result, class_ast, name_ast, 0)) {
- if (Z_TYPE(result) == IS_NULL) {
- if (zend_get_class_fetch_type(zend_ast_get_str(class_ast)) == ZEND_FETCH_CLASS_SELF) {
- zend_ast_destroy(ast);
- *ast_ptr = zend_ast_create_ex(ZEND_AST_MAGIC_CONST, T_CLASS_C);
- }
- return;
- }
- break;
- }
-
zend_eval_const_expr(&ast->child[0]);
zend_eval_const_expr(&ast->child[1]);
class_ast = ast->child[0];
name_ast = ast->child[1];
- if (name_ast->kind == ZEND_AST_ZVAL && zend_string_equals_literal_ci(zend_ast_get_str(name_ast), "class")) {
- zend_error_noreturn(E_COMPILE_ERROR,
- "Dynamic class names are not allowed in compile-time ::class fetch");
- }
-
if (class_ast->kind != ZEND_AST_ZVAL || name_ast->kind != ZEND_AST_ZVAL) {
return;
}
zend_string_release_ex(resolved_name, 0);
break;
}
-
+ case ZEND_AST_CLASS_NAME:
+ {
+ zend_ast *class_ast = ast->child[0];
+ if (zend_try_compile_const_expr_resolve_class_name(&result, class_ast, 0)) {
+ break;
+ }
+ /* TODO We should not use AST_MAGIC_CONST for this, because the semantics are slightly
+ * different. */
+ if (zend_get_class_fetch_type(zend_ast_get_str(class_ast)) == ZEND_FETCH_CLASS_SELF) {
+ zend_ast_destroy(ast);
+ *ast_ptr = zend_ast_create_ex(ZEND_AST_MAGIC_CONST, T_CLASS_C);
+ }
+ return;
+ }
default:
return;
}