Skip to content

Commit 69b54ba

Browse files
committed
Also unreserve T_CLASS
1 parent 36c3c47 commit 69b54ba

File tree

6 files changed

+152
-145
lines changed

6 files changed

+152
-145
lines changed

Zend/tests/grammar/regression_003.phpt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@ class Obj
88
const CLASS = 'class';
99
}
1010

11+
?>
1112
--EXPECTF--
12-
Parse error: syntax error, unexpected 'CLASS' (T_CLASS) in %s on line 5
13+
Fatal error: A class constant must not be called 'class'; it is reserved for class name fetching in %s on line %d

Zend/zend_ast.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1149,9 +1149,6 @@ static void zend_ast_export_ex(smart_str *str, zend_ast *ast, int priority, int
11491149
case ZEND_AST_CONST:
11501150
zend_ast_export_ns_name(str, ast->child[0], 0, indent);
11511151
break;
1152-
case ZEND_AST_RESOLVE_CLASS_NAME:
1153-
zend_ast_export_ns_name(str, ast->child[0], 0, indent);
1154-
APPEND_STR("::class");
11551152
case ZEND_AST_UNPACK:
11561153
smart_str_appends(str, "...");
11571154
ast = ast->child[0];

Zend/zend_ast.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@ enum _zend_ast_kind {
6666
/* 1 child node */
6767
ZEND_AST_VAR = 1 << ZEND_AST_NUM_CHILDREN_SHIFT,
6868
ZEND_AST_CONST,
69-
ZEND_AST_RESOLVE_CLASS_NAME,
7069
ZEND_AST_UNPACK,
7170
ZEND_AST_UNARY_PLUS,
7271
ZEND_AST_UNARY_MINUS,

Zend/zend_compile.c

Lines changed: 116 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1347,6 +1347,88 @@ static inline zend_bool class_name_refers_to_active_ce(zend_string *class_name,
13471347
}
13481348
/* }}} */
13491349

1350+
uint32_t zend_get_class_fetch_type(zend_string *name) /* {{{ */
1351+
{
1352+
if (zend_string_equals_literal_ci(name, "self")) {
1353+
return ZEND_FETCH_CLASS_SELF;
1354+
} else if (zend_string_equals_literal_ci(name, "parent")) {
1355+
return ZEND_FETCH_CLASS_PARENT;
1356+
} else if (zend_string_equals_literal_ci(name, "static")) {
1357+
return ZEND_FETCH_CLASS_STATIC;
1358+
} else {
1359+
return ZEND_FETCH_CLASS_DEFAULT;
1360+
}
1361+
}
1362+
/* }}} */
1363+
1364+
static uint32_t zend_get_class_fetch_type_ast(zend_ast *name_ast) /* {{{ */
1365+
{
1366+
/* Fully qualified names are always default refs */
1367+
if (name_ast->attr == ZEND_NAME_FQ) {
1368+
return ZEND_FETCH_CLASS_DEFAULT;
1369+
}
1370+
1371+
return zend_get_class_fetch_type(zend_ast_get_str(name_ast));
1372+
}
1373+
/* }}} */
1374+
1375+
static void zend_ensure_valid_class_fetch_type(uint32_t fetch_type) /* {{{ */
1376+
{
1377+
if (fetch_type != ZEND_FETCH_CLASS_DEFAULT && !CG(active_class_entry) && zend_is_scope_known()) {
1378+
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use \"%s\" when no class scope is active",
1379+
fetch_type == ZEND_FETCH_CLASS_SELF ? "self" :
1380+
fetch_type == ZEND_FETCH_CLASS_PARENT ? "parent" : "static");
1381+
}
1382+
}
1383+
/* }}} */
1384+
1385+
static zend_bool zend_try_compile_const_expr_resolve_class_name(zval *zv, zend_ast *class_ast, zend_ast *name_ast, zend_bool constant) /* {{{ */
1386+
{
1387+
uint32_t fetch_type;
1388+
1389+
if (name_ast->kind != ZEND_AST_ZVAL) {
1390+
return 0;
1391+
}
1392+
1393+
if (!zend_string_equals_literal_ci(zend_ast_get_str(name_ast), "class")) {
1394+
return 0;
1395+
}
1396+
1397+
if (class_ast->kind != ZEND_AST_ZVAL) {
1398+
zend_error_noreturn(E_COMPILE_ERROR,
1399+
"Dynamic class names are not allowed in compile-time ::class fetch");
1400+
}
1401+
1402+
fetch_type = zend_get_class_fetch_type(zend_ast_get_str(class_ast));
1403+
zend_ensure_valid_class_fetch_type(fetch_type);
1404+
1405+
switch (fetch_type) {
1406+
case ZEND_FETCH_CLASS_SELF:
1407+
if (constant || (CG(active_class_entry) && zend_is_scope_known())) {
1408+
ZVAL_STR_COPY(zv, CG(active_class_entry)->name);
1409+
} else {
1410+
ZVAL_NULL(zv);
1411+
}
1412+
return 1;
1413+
case ZEND_FETCH_CLASS_STATIC:
1414+
case ZEND_FETCH_CLASS_PARENT:
1415+
if (constant) {
1416+
zend_error_noreturn(E_COMPILE_ERROR,
1417+
"%s::class cannot be used for compile-time class name resolution",
1418+
fetch_type == ZEND_FETCH_CLASS_STATIC ? "static" : "parent"
1419+
);
1420+
} else {
1421+
ZVAL_NULL(zv);
1422+
}
1423+
return 1;
1424+
case ZEND_FETCH_CLASS_DEFAULT:
1425+
ZVAL_STR(zv, zend_resolve_class_name_ast(class_ast));
1426+
return 1;
1427+
EMPTY_SWITCH_DEFAULT_CASE()
1428+
}
1429+
}
1430+
/* }}} */
1431+
13501432
static zend_bool zend_try_ct_eval_class_const(zval *zv, zend_string *class_name, zend_string *name) /* {{{ */
13511433
{
13521434
uint32_t fetch_type = zend_get_class_fetch_type(class_name);
@@ -1627,41 +1709,6 @@ ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify
16271709
}
16281710
/* }}} */
16291711

1630-
uint32_t zend_get_class_fetch_type(zend_string *name) /* {{{ */
1631-
{
1632-
if (zend_string_equals_literal_ci(name, "self")) {
1633-
return ZEND_FETCH_CLASS_SELF;
1634-
} else if (zend_string_equals_literal_ci(name, "parent")) {
1635-
return ZEND_FETCH_CLASS_PARENT;
1636-
} else if (zend_string_equals_literal_ci(name, "static")) {
1637-
return ZEND_FETCH_CLASS_STATIC;
1638-
} else {
1639-
return ZEND_FETCH_CLASS_DEFAULT;
1640-
}
1641-
}
1642-
/* }}} */
1643-
1644-
static uint32_t zend_get_class_fetch_type_ast(zend_ast *name_ast) /* {{{ */
1645-
{
1646-
/* Fully qualified names are always default refs */
1647-
if (name_ast->attr == ZEND_NAME_FQ) {
1648-
return ZEND_FETCH_CLASS_DEFAULT;
1649-
}
1650-
1651-
return zend_get_class_fetch_type(zend_ast_get_str(name_ast));
1652-
}
1653-
/* }}} */
1654-
1655-
static void zend_ensure_valid_class_fetch_type(uint32_t fetch_type) /* {{{ */
1656-
{
1657-
if (fetch_type != ZEND_FETCH_CLASS_DEFAULT && !CG(active_class_entry) && zend_is_scope_known()) {
1658-
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use \"%s\" when no class scope is active",
1659-
fetch_type == ZEND_FETCH_CLASS_SELF ? "self" :
1660-
fetch_type == ZEND_FETCH_CLASS_PARENT ? "parent" : "static");
1661-
}
1662-
}
1663-
/* }}} */
1664-
16651712
ZEND_API zend_string *zend_get_compiled_variable_name(const zend_op_array *op_array, uint32_t var) /* {{{ */
16661713
{
16671714
return op_array->vars[EX_VAR_TO_NUM(var)];
@@ -4749,6 +4796,11 @@ void zend_compile_class_const_decl(zend_ast *ast) /* {{{ */
47494796
zend_string *name = zend_ast_get_str(name_ast);
47504797
zval value_zv;
47514798

4799+
if (zend_string_equals_literal_ci(name, "class")) {
4800+
zend_error(E_COMPILE_ERROR,
4801+
"A class constant must not be called 'class'; it is reserved for class name fetching");
4802+
}
4803+
47524804
zend_const_expr_to_zval(&value_zv, value_ast);
47534805

47544806
name = zend_new_interned_string_safe(name);
@@ -6315,6 +6367,16 @@ void zend_compile_class_const(znode *result, zend_ast *ast) /* {{{ */
63156367
zend_op *opline;
63166368
zend_string *resolved_name;
63176369

6370+
if (zend_try_compile_const_expr_resolve_class_name(&result->u.constant, class_ast, const_ast, 0)) {
6371+
if (Z_TYPE(result->u.constant) == IS_NULL) {
6372+
zend_op *opline = zend_emit_op_tmp(result, ZEND_FETCH_CLASS_NAME, NULL, NULL);
6373+
opline->extended_value = zend_get_class_fetch_type(zend_ast_get_str(class_ast));
6374+
} else {
6375+
result->op_type = IS_CONST;
6376+
}
6377+
return;
6378+
}
6379+
63186380
zend_eval_const_expr(&class_ast);
63196381
zend_eval_const_expr(&const_ast);
63206382

@@ -6326,6 +6388,10 @@ void zend_compile_class_const(znode *result, zend_ast *ast) /* {{{ */
63266388
return;
63276389
}
63286390
}
6391+
if (const_ast->kind == ZEND_AST_ZVAL && zend_string_equals_literal_ci(zend_ast_get_str(const_ast), "class")) {
6392+
zend_error_noreturn(E_COMPILE_ERROR,
6393+
"Dynamic class names are not allowed in compile-time ::class fetch");
6394+
}
63296395

63306396
if (zend_is_const_default_class_ref(class_ast)) {
63316397
class_node.op_type = IS_CONST;
@@ -6538,7 +6604,7 @@ zend_bool zend_is_allowed_in_const_expr(zend_ast_kind kind) /* {{{ */
65386604
|| kind == ZEND_AST_CONDITIONAL || kind == ZEND_AST_DIM
65396605
|| kind == ZEND_AST_ARRAY || kind == ZEND_AST_ARRAY_ELEM
65406606
|| kind == ZEND_AST_CONST || kind == ZEND_AST_CLASS_CONST
6541-
|| kind == ZEND_AST_RESOLVE_CLASS_NAME || kind == ZEND_AST_MAGIC_CONST;
6607+
|| kind == ZEND_AST_MAGIC_CONST;
65426608
}
65436609
/* }}} */
65446610

@@ -6557,6 +6623,11 @@ void zend_compile_const_expr_class_const(zend_ast **ast_ptr) /* {{{ */
65576623
"Dynamic class names are not allowed in compile-time class constant references");
65586624
}
65596625

6626+
if (zend_try_compile_const_expr_resolve_class_name(&result, class_ast, const_ast, 1)) {
6627+
*ast_ptr = zend_ast_create_zval(&result);
6628+
return;
6629+
}
6630+
65606631
class_name = zend_ast_get_str(class_ast);
65616632
fetch_type = zend_get_class_fetch_type(class_name);
65626633

@@ -6612,36 +6683,6 @@ void zend_compile_const_expr_const(zend_ast **ast_ptr) /* {{{ */
66126683
}
66136684
/* }}} */
66146685

6615-
void zend_compile_const_expr_resolve_class_name(zend_ast **ast_ptr) /* {{{ */
6616-
{
6617-
zend_ast *ast = *ast_ptr;
6618-
zend_ast *name_ast = ast->child[0];
6619-
zval result;
6620-
uint32_t fetch_type = zend_get_class_fetch_type(zend_ast_get_str(name_ast));
6621-
zend_ensure_valid_class_fetch_type(fetch_type);
6622-
6623-
switch (fetch_type) {
6624-
case ZEND_FETCH_CLASS_SELF:
6625-
ZVAL_STR_COPY(&result, CG(active_class_entry)->name);
6626-
break;
6627-
case ZEND_FETCH_CLASS_STATIC:
6628-
case ZEND_FETCH_CLASS_PARENT:
6629-
zend_error_noreturn(E_COMPILE_ERROR,
6630-
"%s::class cannot be used for compile-time class name resolution",
6631-
fetch_type == ZEND_FETCH_CLASS_STATIC ? "static" : "parent"
6632-
);
6633-
break;
6634-
case ZEND_FETCH_CLASS_DEFAULT:
6635-
ZVAL_STR(&result, zend_resolve_class_name_ast(name_ast));
6636-
break;
6637-
EMPTY_SWITCH_DEFAULT_CASE()
6638-
}
6639-
6640-
zend_ast_destroy(ast);
6641-
*ast_ptr = zend_ast_create_zval(&result);
6642-
}
6643-
/* }}} */
6644-
66456686
void zend_compile_const_expr_magic_const(zend_ast **ast_ptr) /* {{{ */
66466687
{
66476688
zend_ast *ast = *ast_ptr;
@@ -6680,9 +6721,6 @@ void zend_compile_const_expr(zend_ast **ast_ptr) /* {{{ */
66806721
case ZEND_AST_CONST:
66816722
zend_compile_const_expr_const(ast_ptr);
66826723
break;
6683-
case ZEND_AST_RESOLVE_CLASS_NAME:
6684-
zend_compile_const_expr_resolve_class_name(ast_ptr);
6685-
break;
66866724
case ZEND_AST_MAGIC_CONST:
66876725
zend_compile_const_expr_magic_const(ast_ptr);
66886726
break;
@@ -6957,9 +6995,6 @@ void zend_compile_expr(znode *result, zend_ast *ast) /* {{{ */
69576995
case ZEND_AST_CLASS_CONST:
69586996
zend_compile_class_const(result, ast);
69596997
return;
6960-
case ZEND_AST_RESOLVE_CLASS_NAME:
6961-
zend_compile_resolve_class_name(result, ast);
6962-
return;
69636998
case ZEND_AST_ENCAPS_LIST:
69646999
zend_compile_encaps_list(result, ast);
69657000
return;
@@ -7129,9 +7164,18 @@ void zend_eval_const_expr(zend_ast **ast_ptr) /* {{{ */
71297164
zend_ast *name_ast = ast->child[1];
71307165
zend_string *resolved_name;
71317166

7167+
if (zend_try_compile_const_expr_resolve_class_name(&result, class_ast, name_ast, 1)) {
7168+
break;
7169+
}
7170+
71327171
zend_eval_const_expr(&class_ast);
71337172
zend_eval_const_expr(&name_ast);
71347173

7174+
if (name_ast->kind == ZEND_AST_ZVAL && zend_string_equals_literal_ci(zend_ast_get_str(name_ast), "class")) {
7175+
zend_error_noreturn(E_COMPILE_ERROR,
7176+
"Dynamic class names are not allowed in compile-time ::class fetch");
7177+
}
7178+
71357179
if (class_ast->kind != ZEND_AST_ZVAL || name_ast->kind != ZEND_AST_ZVAL) {
71367180
return;
71377181
}

Zend/zend_language_parser.y

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,6 @@
2121

2222
/* $Id$ */
2323

24-
/*
25-
* LALR shift/reduce conflicts and how they are resolved:
26-
*
27-
* - 2 shift/reduce conflicts due to the dangling elseif/else ambiguity. Solved by shift.
28-
*
29-
*/
30-
31-
3224
#include "zend_compile.h"
3325
#include "zend.h"
3426
#include "zend_list.h"
@@ -246,7 +238,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
246238
%type <ast> new_expr anonymous_class class_name class_name_reference simple_variable
247239
%type <ast> internal_functions_in_yacc
248240
%type <ast> exit_expr scalar backticks_expr lexical_var function_call member_name property_name
249-
%type <ast> variable_class_name dereferencable_scalar class_name_scalar constant dereferencable
241+
%type <ast> variable_class_name dereferencable_scalar constant dereferencable
250242
%type <ast> callable_expr callable_variable static_member new_variable
251243
%type <ast> assignment_list_element array_pair encaps_var encaps_var_offset isset_variables
252244
%type <ast> top_statement_list use_declarations const_list inner_statement_list if_stmt
@@ -279,7 +271,7 @@ reserved_non_modifiers:
279271
| T_THROW | T_USE | T_INSTEADOF | T_GLOBAL | T_VAR | T_UNSET | T_ISSET | T_EMPTY | T_CONTINUE | T_GOTO
280272
| T_FUNCTION | T_CONST | T_RETURN | T_PRINT | T_YIELD | T_LIST | T_SWITCH | T_ENDSWITCH | T_CASE | T_DEFAULT | T_BREAK
281273
| T_ARRAY | T_CALLABLE | T_EXTENDS | T_IMPLEMENTS | T_NAMESPACE | T_TRAIT | T_INTERFACE
282-
// | T_CLASS
274+
| T_CLASS
283275
;
284276

285277
semi_reserved:
@@ -1058,7 +1050,6 @@ scalar:
10581050
| '"' encaps_list '"' { $$ = $2; }
10591051
| T_START_HEREDOC encaps_list T_END_HEREDOC { $$ = $2; }
10601052
| dereferencable_scalar { $$ = $1; }
1061-
| class_name_scalar { $$ = $1; }
10621053
| constant { $$ = $1; }
10631054
;
10641055

@@ -1262,11 +1253,6 @@ isset_variable:
12621253
expr { $$ = zend_ast_create(ZEND_AST_ISSET, $1); }
12631254
;
12641255

1265-
class_name_scalar:
1266-
class_name T_PAAMAYIM_NEKUDOTAYIM T_CLASS
1267-
{ $$ = zend_ast_create(ZEND_AST_RESOLVE_CLASS_NAME, $1); }
1268-
;
1269-
12701256
%%
12711257

12721258
/* Copy to YYRES the contents of YYSTR after stripping away unnecessary

0 commit comments

Comments
 (0)