diff options
-rw-r--r-- | Zend/tests/access_modifiers_003.phpt | 2 | ||||
-rw-r--r-- | Zend/tests/access_modifiers_013.phpt | 12 | ||||
-rw-r--r-- | Zend/zend_compile.c | 16 | ||||
-rw-r--r-- | Zend/zend_compile.h | 1 | ||||
-rw-r--r-- | Zend/zend_language_parser.y | 60 |
5 files changed, 70 insertions, 21 deletions
diff --git a/Zend/tests/access_modifiers_003.phpt b/Zend/tests/access_modifiers_003.phpt index dc21278025..2b3a88242f 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 0000000000..f9b72c1f52 --- /dev/null +++ b/Zend/tests/access_modifiers_013.phpt @@ -0,0 +1,12 @@ +--TEST-- +Prevent abstract and final in the same class declaration +--FILE-- +<?php + +final abstract class C { + private function priv() { } +} + +?> +--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 c06ebc4595..0164515b20 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -540,6 +540,22 @@ void zend_do_free(znode *op1) /* {{{ */ } /* }}} */ +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 7909e9800a..966347fd3c 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -632,6 +632,7 @@ ZEND_API binary_op_type get_binary_op(int opcode); void zend_stop_lexing(void); void zend_emit_final_return(zval *zv); 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); void zend_handle_encoding_declaration(zend_ast *ast); diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index da94e0e773..1d18ae9d7e 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -228,7 +228,9 @@ static YYSIZE_T zend_yytnamerr(char*, const char*); %token T_POW_EQUAL "**= (T_POW_EQUAL)" %type <ast> top_statement namespace_name name statement function_declaration_statement -%type <ast> class_declaration_statement use_declaration const_decl inner_statement +%type <ast> class_declaration_statement trait_declaration_statement +%type <ast> interface_declaration_statement interface_extends_list +%type <ast> use_declaration const_decl inner_statement %type <ast> expr optional_expr while_statement for_statement foreach_variable %type <ast> foreach_statement declare_statement finally_statement unset_variable variable %type <ast> extends_from parameter optional_type argument expr_without_variable global_var @@ -243,15 +245,16 @@ static YYSIZE_T zend_yytnamerr(char*, const char*); %type <ast> top_statement_list use_declarations const_list inner_statement_list if_stmt %type <ast> alt_if_stmt for_exprs switch_case_list global_var_list static_var_list %type <ast> echo_expr_list unset_variables catch_list parameter_list class_statement_list -%type <ast> implements_list interface_extends_list case_list if_stmt_without_else +%type <ast> implements_list case_list if_stmt_without_else %type <ast> non_empty_parameter_list argument_list non_empty_argument_list property_list %type <ast> class_const_list name_list trait_adaptations method_body non_empty_for_exprs %type <ast> ctor_arguments alt_if_stmt_without_else trait_adaptation_list lexical_vars %type <ast> lexical_var_list encaps_list array_pair_list non_empty_array_pair_list %type <ast> assignment_list -%type <num> returns_ref function is_reference is_variadic class_type variable_modifiers +%type <num> returns_ref function is_reference is_variadic variable_modifiers %type <num> method_modifiers trait_modifiers non_empty_member_modifiers member_modifier +%type <num> class_modifiers class_modifier %type <str> backup_doc_comment @@ -278,9 +281,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())); @@ -333,8 +338,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"); } @@ -418,21 +425,34 @@ is_variadic: ; class_declaration_statement: - class_type { $<num>$ = CG(zend_lineno); } + class_modifiers T_CLASS { $<num>$ = CG(zend_lineno); } T_STRING extends_from implements_list backup_doc_comment '{' class_statement_list '}' - { $$ = zend_ast_create_decl(ZEND_AST_CLASS, $1, $<num>2, $6, - zend_ast_get_str($3), $4, $5, $8); } - | T_INTERFACE { $<num>$ = CG(zend_lineno); } - T_STRING interface_extends_list backup_doc_comment '{' class_statement_list '}' - { $$ = zend_ast_create_decl(ZEND_AST_CLASS, ZEND_ACC_INTERFACE, $<num>2, $5, - zend_ast_get_str($3), NULL, $4, $7); } + { $$ = zend_ast_create_decl(ZEND_AST_CLASS, $1, $<num>3, $7, zend_ast_get_str($4), $5, $6, $9); } + | T_CLASS { $<num>$ = CG(zend_lineno); } + T_STRING extends_from implements_list backup_doc_comment '{' class_statement_list '}' + { $$ = zend_ast_create_decl(ZEND_AST_CLASS, 0, $<num>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 { $<num>$ = 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, $<num>2, $6, zend_ast_get_str($3), $4, $5, $8); } +; + +interface_declaration_statement: + T_INTERFACE { $<num>$ = CG(zend_lineno); } + T_STRING interface_extends_list backup_doc_comment '{' class_statement_list '}' + { $$ = zend_ast_create_decl(ZEND_AST_CLASS, ZEND_ACC_INTERFACE, $<num>2, $5, zend_ast_get_str($3), NULL, $4, $7); } ; extends_from: |