From 60972343c1c729a767fba39c4552034b448bd8ae Mon Sep 17 00:00:00 2001 From: Guilherme Blanco Date: Sat, 22 Nov 2014 04:57:55 +0000 Subject: [PATCH 1/4] Removed ZEND_ACC_FINAL_CLASS which is unnecessary. This also fixed some currently defined classes as final which were just not being considered as such before. --- Zend/zend_closures.c | 2 +- Zend/zend_compile.h | 1 - Zend/zend_generators.c | 2 +- Zend/zend_inheritance.c | 2 +- Zend/zend_language_parser.y | 2 +- ext/mysqli/mysqli.c | 4 ++-- ext/pdo/pdo_stmt.c | 2 +- ext/phar/phar_object.c | 4 ++-- ext/reflection/php_reflection.c | 10 +++++----- .../tests/ReflectionClass_getModifiers_basic.phpt | 2 +- .../tests/ReflectionClass_modifiers_001.phpt | 2 +- ext/reflection/tests/ReflectionClass_toString_001.phpt | 2 +- ext/tidy/tidy.c | 2 +- 13 files changed, 18 insertions(+), 19 deletions(-) diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c index bf0ba0ace4050..b9d097c424d86 100644 --- a/Zend/zend_closures.c +++ b/Zend/zend_closures.c @@ -445,7 +445,7 @@ void zend_register_closure_ce(TSRMLS_D) /* {{{ */ INIT_CLASS_ENTRY(ce, "Closure", closure_functions); zend_ce_closure = zend_register_internal_class(&ce TSRMLS_CC); - zend_ce_closure->ce_flags |= ZEND_ACC_FINAL_CLASS; + zend_ce_closure->ce_flags |= ZEND_ACC_FINAL; zend_ce_closure->create_object = zend_closure_new; zend_ce_closure->serialize = zend_class_serialize_deny; zend_ce_closure->unserialize = zend_class_unserialize_deny; diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 63d67660c68e1..48a3527324ce8 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -161,7 +161,6 @@ typedef struct _zend_try_catch_element { /* ZEND_ACC_EXPLICIT_ABSTRACT_CLASS denotes that a class was explicitly defined as abstract by using the keyword. */ #define ZEND_ACC_IMPLICIT_ABSTRACT_CLASS 0x10 #define ZEND_ACC_EXPLICIT_ABSTRACT_CLASS 0x20 -#define ZEND_ACC_FINAL_CLASS 0x40 #define ZEND_ACC_INTERFACE 0x80 #define ZEND_ACC_TRAIT 0x120 diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index 2d1810ef78d08..c3827c5c51144 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -671,7 +671,7 @@ void zend_register_generator_ce(TSRMLS_D) /* {{{ */ INIT_CLASS_ENTRY(ce, "Generator", generator_functions); zend_ce_generator = zend_register_internal_class(&ce TSRMLS_CC); - zend_ce_generator->ce_flags |= ZEND_ACC_FINAL_CLASS; + zend_ce_generator->ce_flags |= ZEND_ACC_FINAL; zend_ce_generator->create_object = zend_generator_create; zend_ce_generator->serialize = zend_class_serialize_deny; zend_ce_generator->unserialize = zend_class_unserialize_deny; diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index 407acade0ef68..bf98cabbf6696 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -727,7 +727,7 @@ ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent && !(parent_ce->ce_flags & ZEND_ACC_INTERFACE)) { zend_error_noreturn(E_COMPILE_ERROR, "Interface %s may not inherit from class (%s)", ce->name->val, parent_ce->name->val); } - if (parent_ce->ce_flags & ZEND_ACC_FINAL_CLASS) { + if (parent_ce->ce_flags & ZEND_ACC_FINAL) { zend_error_noreturn(E_COMPILE_ERROR, "Class %s may not inherit from final class (%s)", ce->name->val, parent_ce->name->val); } diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 88286203da953..b293ca80039f1 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -435,7 +435,7 @@ class_declaration_statement: class_type: T_CLASS { $$ = 0; } | T_ABSTRACT T_CLASS { $$ = ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; } - | T_FINAL T_CLASS { $$ = ZEND_ACC_FINAL_CLASS; } + | T_FINAL T_CLASS { $$ = ZEND_ACC_FINAL; } | T_TRAIT { $$ = ZEND_ACC_TRAIT; } ; diff --git a/ext/mysqli/mysqli.c b/ext/mysqli/mysqli.c index 878c8fb94677f..6d7210fe592c2 100644 --- a/ext/mysqli/mysqli.c +++ b/ext/mysqli/mysqli.c @@ -625,7 +625,7 @@ PHP_MINIT_FUNCTION(mysqli) zend_declare_property_null(ce, "embedded", sizeof("embedded") - 1, ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_null(ce, "reconnect", sizeof("reconnect") - 1, ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_null(ce, "report_mode", sizeof("report_mode") - 1, ZEND_ACC_PUBLIC TSRMLS_CC); - ce->ce_flags |= ZEND_ACC_FINAL_CLASS; + ce->ce_flags |= ZEND_ACC_FINAL; zend_hash_add_ptr(&classes, ce->name, &mysqli_driver_properties); REGISTER_MYSQLI_CLASS_ENTRY("mysqli", mysqli_link_class_entry, mysqli_link_methods); @@ -655,7 +655,7 @@ PHP_MINIT_FUNCTION(mysqli) REGISTER_MYSQLI_CLASS_ENTRY("mysqli_warning", mysqli_warning_class_entry, mysqli_warning_methods); ce = mysqli_warning_class_entry; - ce->ce_flags |= ZEND_ACC_FINAL_CLASS | ZEND_ACC_PROTECTED; + ce->ce_flags |= ZEND_ACC_FINAL; zend_hash_init(&mysqli_warning_properties, 0, NULL, free_prop_handler, 1); MYSQLI_ADD_PROPERTIES(&mysqli_warning_properties, mysqli_warning_property_entries); zend_declare_property_null(ce, "message", sizeof("message") - 1, ZEND_ACC_PUBLIC TSRMLS_CC); diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c index 27cc157ed7240..1491c80cfdddc 100644 --- a/ext/pdo/pdo_stmt.c +++ b/ext/pdo/pdo_stmt.c @@ -2292,7 +2292,7 @@ void pdo_stmt_init(TSRMLS_D) INIT_CLASS_ENTRY(ce, "PDORow", pdo_row_functions); pdo_row_ce = zend_register_internal_class(&ce TSRMLS_CC); - pdo_row_ce->ce_flags |= ZEND_ACC_FINAL_CLASS; /* when removing this a lot of handlers need to be redone */ + pdo_row_ce->ce_flags |= ZEND_ACC_FINAL; /* when removing this a lot of handlers need to be redone */ pdo_row_ce->create_object = pdo_row_new; pdo_row_ce->serialize = pdo_row_serialize; } diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index f82b82563144f..d23c7cd6c6f09 100755 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -5308,11 +5308,11 @@ void phar_object_init(TSRMLS_D) /* {{{ */ #else INIT_CLASS_ENTRY(ce, "Phar", php_archive_methods); phar_ce_archive = zend_register_internal_class(&ce TSRMLS_CC); - phar_ce_archive->ce_flags |= ZEND_ACC_FINAL_CLASS; + phar_ce_archive->ce_flags |= ZEND_ACC_FINAL; INIT_CLASS_ENTRY(ce, "PharData", php_archive_methods); phar_ce_data = zend_register_internal_class(&ce TSRMLS_CC); - phar_ce_data->ce_flags |= ZEND_ACC_FINAL_CLASS; + phar_ce_data->ce_flags |= ZEND_ACC_FINAL; #endif REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "BZ2", PHAR_ENT_COMPRESSED_BZ2) diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 7d8f2b43ea301..5de5406cf36e7 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -395,7 +395,7 @@ static void _class_string(string *str, zend_class_entry *ce, zval *obj, char *in if (ce->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) { string_printf(str, "abstract "); } - if (ce->ce_flags & ZEND_ACC_FINAL_CLASS) { + if (ce->ce_flags & ZEND_ACC_FINAL) { string_printf(str, "final "); } string_printf(str, "class "); @@ -1557,7 +1557,7 @@ ZEND_METHOD(reflection, getModifierNames) if (modifiers & (ZEND_ACC_ABSTRACT | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) { add_next_index_stringl(return_value, "abstract", sizeof("abstract")-1); } - if (modifiers & (ZEND_ACC_FINAL | ZEND_ACC_FINAL_CLASS)) { + if (modifiers & ZEND_ACC_FINAL) { add_next_index_stringl(return_value, "final", sizeof("final")-1); } if (modifiers & ZEND_ACC_IMPLICIT_PUBLIC) { @@ -4162,7 +4162,7 @@ ZEND_METHOD(reflection_class, isTrait) Returns whether this class is final */ ZEND_METHOD(reflection_class, isFinal) { - _class_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_FINAL_CLASS); + _class_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_FINAL); } /* }}} */ @@ -4290,7 +4290,7 @@ ZEND_METHOD(reflection_class, newInstanceWithoutConstructor) METHOD_NOTSTATIC(reflection_class_ptr); GET_REFLECTION_OBJECT_PTR(ce); - if (ce->create_object != NULL && ce->ce_flags & ZEND_ACC_FINAL_CLASS) { + if (ce->create_object != NULL && ce->ce_flags & ZEND_ACC_FINAL) { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Class %s is an internal class marked as final that cannot be instantiated without invoking its constructor", ce->name->val); } @@ -6187,7 +6187,7 @@ PHP_MINIT_FUNCTION(reflection) /* {{{ */ REGISTER_REFLECTION_CLASS_CONST_LONG(class, "IS_IMPLICIT_ABSTRACT", ZEND_ACC_IMPLICIT_ABSTRACT_CLASS); REGISTER_REFLECTION_CLASS_CONST_LONG(class, "IS_EXPLICIT_ABSTRACT", ZEND_ACC_EXPLICIT_ABSTRACT_CLASS); - REGISTER_REFLECTION_CLASS_CONST_LONG(class, "IS_FINAL", ZEND_ACC_FINAL_CLASS); + REGISTER_REFLECTION_CLASS_CONST_LONG(class, "IS_FINAL", ZEND_ACC_FINAL); INIT_CLASS_ENTRY(_reflection_entry, "ReflectionObject", reflection_object_functions); _reflection_entry.create_object = reflection_objects_new; diff --git a/ext/reflection/tests/ReflectionClass_getModifiers_basic.phpt b/ext/reflection/tests/ReflectionClass_getModifiers_basic.phpt index 65f23c935f91e..8d2bd47d12da1 100644 --- a/ext/reflection/tests/ReflectionClass_getModifiers_basic.phpt +++ b/ext/reflection/tests/ReflectionClass_getModifiers_basic.phpt @@ -30,7 +30,7 @@ dump_modifiers('g'); --EXPECT-- int(0) int(32) -int(64) +int(4) int(128) int(524288) int(524416) diff --git a/ext/reflection/tests/ReflectionClass_modifiers_001.phpt b/ext/reflection/tests/ReflectionClass_modifiers_001.phpt index 941bfe5f2b9f9..1e0a97dfe088d 100644 --- a/ext/reflection/tests/ReflectionClass_modifiers_001.phpt +++ b/ext/reflection/tests/ReflectionClass_modifiers_001.phpt @@ -37,7 +37,7 @@ int(0) bool(true) bool(false) bool(false) -int(64) +int(4) bool(false) bool(true) bool(false) diff --git a/ext/reflection/tests/ReflectionClass_toString_001.phpt b/ext/reflection/tests/ReflectionClass_toString_001.phpt index 8dd571c3a9cc2..c47aba8b8d622 100644 --- a/ext/reflection/tests/ReflectionClass_toString_001.phpt +++ b/ext/reflection/tests/ReflectionClass_toString_001.phpt @@ -14,7 +14,7 @@ Class [ class ReflectionClass implements Reflector ] { - Constants [3] { Constant [ integer IS_IMPLICIT_ABSTRACT ] { 16 } Constant [ integer IS_EXPLICIT_ABSTRACT ] { 32 } - Constant [ integer IS_FINAL ] { 64 } + Constant [ integer IS_FINAL ] { 4 } } - Static properties [0] { diff --git a/ext/tidy/tidy.c b/ext/tidy/tidy.c index 8ca27d7b9a454..23531e9ae3e9c 100644 --- a/ext/tidy/tidy.c +++ b/ext/tidy/tidy.c @@ -1037,7 +1037,7 @@ static PHP_MINIT_FUNCTION(tidy) REGISTER_INI_ENTRIES(); REGISTER_TIDY_CLASS(tidy, doc, NULL, 0); - REGISTER_TIDY_CLASS(tidyNode, node, NULL, ZEND_ACC_FINAL_CLASS); + REGISTER_TIDY_CLASS(tidyNode, node, NULL, ZEND_ACC_FINAL); tidy_object_handlers_doc.cast_object = tidy_doc_cast_handler; tidy_object_handlers_node.cast_object = tidy_node_cast_handler; From db522c4d721c0911f88ce85665d515c34398b04f Mon Sep 17 00:00:00 2001 From: Guilherme Blanco Date: Fri, 5 Dec 2014 04:15:23 +0000 Subject: [PATCH 2/4] Updated NEWS and UPGRADING.INTERNALS. --- NEWS | 2 ++ UPGRADING.INTERNALS | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/NEWS b/NEWS index d2e68d0b6c6ec..96eb43fb21974 100644 --- a/NEWS +++ b/NEWS @@ -22,6 +22,8 @@ PHP NEWS classes (https://wiki.php.net/rfc/secure_unserialize). (Stas) . Fixed bug #68185 ("Inconsistent insteadof definition."- incorrectly triggered). (Julien) . Fixed bug #65419 (Inside trait, self::class != __CLASS__). (Julien) + . Removed ZEND_ACC_FINAL_CLASS, promoting ZEND_ACC_FINAL as final class + modifier. (Guilherme Blanco) - DBA: . Fixed bug #62490 (dba_delete returns true on missing item (inifile)). (Mike) diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index 0c4dc8a34254f..3b80f295e2351 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -13,6 +13,7 @@ PHP 7.0 INTERNALS UPGRADE NOTES l. get_class_name object handler info m. Other portable macros info n. ZEND_ENGINE_2 removal + o. Updated final class modifier 2. Build system changes a. Unix build system changes @@ -123,6 +124,9 @@ PHP 7.0 INTERNALS UPGRADE NOTES ZEND_NORETURN is defined as __declspec(noreturn) on VS n. The ZEND_ENGINE_2 macro has been removed. A ZEND_ENGINE_3 macro has been added. + + o. Removed ZEND_ACC_FINAL_CLASS in favour of ZEND_ACC_FINAL, turning final class + modifier now a different class entry flag. Update your extensions. ======================== 2. Build system changes From cf249f4fdaee15d5ce7797fd96fac7acbeb4e19c Mon Sep 17 00:00:00 2001 From: Guilherme Blanco Date: Mon, 1 Dec 2014 18:44:07 +0000 Subject: [PATCH 3/4] Decoupled class declaration statement into more granular pieces. --- Zend/tests/access_modifiers_003.phpt | 2 +- Zend/tests/access_modifiers_013.phpt | 12 ++++++ Zend/zend_compile.c | 16 ++++++++ Zend/zend_compile.h | 1 + Zend/zend_language_parser.y | 60 ++++++++++++++++++---------- 5 files changed, 70 insertions(+), 21 deletions(-) create mode 100644 Zend/tests/access_modifiers_013.phpt diff --git a/Zend/tests/access_modifiers_003.phpt b/Zend/tests/access_modifiers_003.phpt index dc21278025f4c..2b3a88242f723 100644 --- a/Zend/tests/access_modifiers_003.phpt +++ b/Zend/tests/access_modifiers_003.phpt @@ -10,4 +10,4 @@ final final class test { echo "Done\n"; ?> --EXPECTF-- -Parse error: %s error,%sexpecting %s in %s on line %d +Fatal error: Multiple final modifiers are not allowed in %s on line %d diff --git a/Zend/tests/access_modifiers_013.phpt b/Zend/tests/access_modifiers_013.phpt new file mode 100644 index 0000000000000..f9b72c1f52aa8 --- /dev/null +++ b/Zend/tests/access_modifiers_013.phpt @@ -0,0 +1,12 @@ +--TEST-- +Prevent abstract and final in the same class declaration +--FILE-- + +--EXPECTF-- +Fatal error: Cannot use the final modifier on an abstract class in %s on line %d diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 086c7d0db165e..ce2108e95da51 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -551,6 +551,22 @@ void zend_do_free(znode *op1 TSRMLS_DC) /* {{{ */ } /* }}} */ +uint32_t zend_add_class_modifier(uint32_t flags, uint32_t new_flag) /* {{{ */ +{ + uint32_t new_flags = flags | new_flag; + if ((flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) && (new_flag & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) { + zend_error_noreturn(E_COMPILE_ERROR, "Multiple abstract modifiers are not allowed"); + } + if ((flags & ZEND_ACC_FINAL) && (new_flag & ZEND_ACC_FINAL)) { + zend_error_noreturn(E_COMPILE_ERROR, "Multiple final modifiers are not allowed"); + } + if ((new_flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) && (new_flags & ZEND_ACC_FINAL)) { + zend_error_noreturn(E_COMPILE_ERROR, "Cannot use the final modifier on an abstract class"); + } + return new_flags; +} +/* }}} */ + uint32_t zend_add_member_modifier(uint32_t flags, uint32_t new_flag) /* {{{ */ { uint32_t new_flags = flags | new_flag; diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 48a3527324ce8..723aff0366e57 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -475,6 +475,7 @@ ZEND_API binary_op_type get_binary_op(int opcode); void zend_stop_lexing(TSRMLS_D); void zend_emit_final_return(zval *zv TSRMLS_DC); zend_ast *zend_ast_append_str(zend_ast *left, zend_ast *right); +uint32_t zend_add_class_modifier(uint32_t flags, uint32_t new_flag); uint32_t zend_add_member_modifier(uint32_t flags, uint32_t new_flag); zend_ast *zend_ast_append_doc_comment(zend_ast *list TSRMLS_DC); void zend_handle_encoding_declaration(zend_ast *ast TSRMLS_DC); diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index b293ca80039f1..1a8df0a0efbad 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -232,7 +232,9 @@ static YYSIZE_T zend_yytnamerr(char*, const char*); %token T_POW_EQUAL "**= (T_POW_EQUAL)" %type top_statement namespace_name name statement function_declaration_statement -%type class_declaration_statement use_declaration const_decl inner_statement +%type class_declaration_statement trait_declaration_statement +%type interface_declaration_statement interface_extends_list +%type use_declaration const_decl inner_statement %type expr optional_expr while_statement for_statement foreach_variable %type foreach_statement declare_statement finally_statement unset_variable variable %type extends_from parameter optional_type argument expr_without_variable global_var @@ -247,15 +249,16 @@ static YYSIZE_T zend_yytnamerr(char*, const char*); %type top_statement_list use_declarations const_list inner_statement_list if_stmt %type alt_if_stmt for_exprs switch_case_list global_var_list static_var_list %type echo_expr_list unset_variables catch_list parameter_list class_statement_list -%type implements_list interface_extends_list case_list if_stmt_without_else +%type implements_list case_list if_stmt_without_else %type non_empty_parameter_list argument_list non_empty_argument_list property_list %type class_const_list name_list trait_adaptations method_body non_empty_for_exprs %type ctor_arguments alt_if_stmt_without_else trait_adaptation_list lexical_vars %type lexical_var_list encaps_list array_pair_list non_empty_array_pair_list %type assignment_list -%type returns_ref function is_reference is_variadic class_type variable_modifiers +%type returns_ref function is_reference is_variadic variable_modifiers %type method_modifiers trait_modifiers non_empty_member_modifiers member_modifier +%type class_modifiers class_modifier %type backup_doc_comment @@ -282,9 +285,11 @@ name: ; top_statement: - statement { $$ = $1; } - | function_declaration_statement { $$ = $1; } - | class_declaration_statement { $$ = $1; } + statement { $$ = $1; } + | function_declaration_statement { $$ = $1; } + | class_declaration_statement { $$ = $1; } + | trait_declaration_statement { $$ = $1; } + | interface_declaration_statement { $$ = $1; } | T_HALT_COMPILER '(' ')' ';' { $$ = zend_ast_create(ZEND_AST_HALT_COMPILER, zend_ast_create_zval_from_long(zend_get_scanned_file_offset(TSRMLS_C))); @@ -337,8 +342,10 @@ inner_statement_list: inner_statement: statement { $$ = $1; } - | function_declaration_statement { $$ = $1; } - | class_declaration_statement { $$ = $1; } + | function_declaration_statement { $$ = $1; } + | class_declaration_statement { $$ = $1; } + | trait_declaration_statement { $$ = $1; } + | interface_declaration_statement { $$ = $1; } | T_HALT_COMPILER '(' ')' ';' { $$ = NULL; zend_error_noreturn(E_COMPILE_ERROR, "__HALT_COMPILER() can only be used from the outermost scope"); } @@ -422,21 +429,34 @@ is_variadic: ; class_declaration_statement: - class_type { $$ = CG(zend_lineno); } + class_modifiers T_CLASS { $$ = CG(zend_lineno); } T_STRING extends_from implements_list backup_doc_comment '{' class_statement_list '}' - { $$ = zend_ast_create_decl(ZEND_AST_CLASS, $1, $2, $6, - zend_ast_get_str($3), $4, $5, $8); } - | T_INTERFACE { $$ = CG(zend_lineno); } - T_STRING interface_extends_list backup_doc_comment '{' class_statement_list '}' - { $$ = zend_ast_create_decl(ZEND_AST_CLASS, ZEND_ACC_INTERFACE, $2, $5, - zend_ast_get_str($3), NULL, $4, $7); } + { $$ = zend_ast_create_decl(ZEND_AST_CLASS, $1, $3, $7, zend_ast_get_str($4), $5, $6, $9); } + | T_CLASS { $$ = CG(zend_lineno); } + T_STRING extends_from implements_list backup_doc_comment '{' class_statement_list '}' + { $$ = zend_ast_create_decl(ZEND_AST_CLASS, 0, $2, $6, zend_ast_get_str($3), $4, $5, $8); } +; + +class_modifiers: + class_modifier { $$ = $1; } + | class_modifiers class_modifier { $$ = zend_add_class_modifier($1, $2); } +; + +class_modifier: + T_ABSTRACT { $$ = ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; } + | T_FINAL { $$ = ZEND_ACC_FINAL; } ; -class_type: - T_CLASS { $$ = 0; } - | T_ABSTRACT T_CLASS { $$ = ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; } - | T_FINAL T_CLASS { $$ = ZEND_ACC_FINAL; } - | T_TRAIT { $$ = ZEND_ACC_TRAIT; } +trait_declaration_statement: + T_TRAIT { $$ = CG(zend_lineno); } + T_STRING extends_from implements_list backup_doc_comment '{' class_statement_list '}' + { $$ = zend_ast_create_decl(ZEND_AST_CLASS, ZEND_ACC_TRAIT, $2, $6, zend_ast_get_str($3), $4, $5, $8); } +; + +interface_declaration_statement: + T_INTERFACE { $$ = CG(zend_lineno); } + T_STRING interface_extends_list backup_doc_comment '{' class_statement_list '}' + { $$ = zend_ast_create_decl(ZEND_AST_CLASS, ZEND_ACC_INTERFACE, $2, $5, zend_ast_get_str($3), NULL, $4, $7); } ; extends_from: From 872a97c8dbc1c8823985d9a0305938c508865a0d Mon Sep 17 00:00:00 2001 From: Guilherme Blanco Date: Fri, 5 Dec 2014 17:09:49 +0000 Subject: [PATCH 4/4] Removed parsing support traits to have extends and implements. --- Zend/tests/traits/bug55524.phpt | 2 +- Zend/tests/traits/bugs/interfaces.phpt | 2 +- Zend/zend_compile.c | 12 ------------ Zend/zend_language_parser.y | 4 ++-- 4 files changed, 4 insertions(+), 16 deletions(-) diff --git a/Zend/tests/traits/bug55524.phpt b/Zend/tests/traits/bug55524.phpt index 137975980dd70..9fe36d7a80d0c 100644 --- a/Zend/tests/traits/bug55524.phpt +++ b/Zend/tests/traits/bug55524.phpt @@ -12,4 +12,4 @@ trait Foo extends Base { echo 'DONE'; ?> --EXPECTF-- -Fatal error: A trait (Foo) cannot extend a class. Traits can only be composed from other traits with the 'use' keyword. Error in %s on line %d +Parse error: syntax error, unexpected 'extends' (T_EXTENDS), expecting '{' in %s on line %d diff --git a/Zend/tests/traits/bugs/interfaces.phpt b/Zend/tests/traits/bugs/interfaces.phpt index 486bda7efb38f..b632b73be29df 100644 --- a/Zend/tests/traits/bugs/interfaces.phpt +++ b/Zend/tests/traits/bugs/interfaces.phpt @@ -16,4 +16,4 @@ trait THello implements MyInterface { ?> --EXPECTF-- -Fatal error: Cannot use 'MyInterface' as interface on 'THello' since it is a Trait in %s on line %d \ No newline at end of file +Parse error: syntax error, unexpected 'implements' (T_IMPLEMENTS), expecting '{' in %s on line %d diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index ce2108e95da51..fdaaf5dd6bda3 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -4458,12 +4458,6 @@ void zend_compile_implements(znode *class_node, zend_ast *ast TSRMLS_DC) /* {{{ zend_op *opline; - /* Traits can not implement interfaces */ - if (ZEND_CE_IS_TRAIT(CG(active_class_entry))) { - zend_error_noreturn(E_COMPILE_ERROR, "Cannot use '%s' as interface on '%s' " - "since it is a Trait", name->val, CG(active_class_entry)->name->val); - } - if (!zend_is_const_default_class_ref(class_ast)) { zend_error_noreturn(E_COMPILE_ERROR, "Cannot use '%s' as interface name as it is reserved", name->val); @@ -4539,12 +4533,6 @@ void zend_compile_class_decl(zend_ast *ast TSRMLS_DC) /* {{{ */ } if (extends_ast) { - if (ZEND_CE_IS_TRAIT(ce)) { - zend_error_noreturn(E_COMPILE_ERROR, "A trait (%s) cannot extend a class. " - "Traits can only be composed from other traits with the 'use' keyword. Error", - name->val); - } - if (!zend_is_const_default_class_ref(extends_ast)) { zend_string *extends_name = zend_ast_get_str(extends_ast); zend_error_noreturn(E_COMPILE_ERROR, diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 1a8df0a0efbad..24897ef7a914e 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -449,8 +449,8 @@ class_modifier: trait_declaration_statement: T_TRAIT { $$ = CG(zend_lineno); } - T_STRING extends_from implements_list backup_doc_comment '{' class_statement_list '}' - { $$ = zend_ast_create_decl(ZEND_AST_CLASS, ZEND_ACC_TRAIT, $2, $6, zend_ast_get_str($3), $4, $5, $8); } + T_STRING backup_doc_comment '{' class_statement_list '}' + { $$ = zend_ast_create_decl(ZEND_AST_CLASS, ZEND_ACC_TRAIT, $2, $4, zend_ast_get_str($3), NULL, NULL, $6); } ; interface_declaration_statement: