]> granicus.if.org Git - php/commitdiff
Decoupled class declaration statement into more granular pieces.
authorGuilherme Blanco <guilhermeblanco@hotmail.com>
Mon, 1 Dec 2014 18:44:07 +0000 (18:44 +0000)
committerJulien Pauli <jpauli@php.net>
Fri, 9 Jan 2015 14:45:01 +0000 (15:45 +0100)
Zend/tests/access_modifiers_003.phpt
Zend/tests/access_modifiers_013.phpt [new file with mode: 0644]
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_language_parser.y

index dc21278025f4c5419bda55d289b15c06b4871629..2b3a88242f723bedb2ce8bba4970fa58a981dec4 100644 (file)
@@ -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 (file)
index 0000000..f9b72c1
--- /dev/null
@@ -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
index c06ebc4595e74904ccb5befa8f41ed469f9671f5..0164515b20a6c03b741dd71e0b3d6bfbb66b63fd 100644 (file)
@@ -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;
index 7909e9800ac8805a8f159847fe93078c533524bd..966347fd3cfa1c93b07e93873b967dddaf91f733 100644 (file)
@@ -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);
index da94e0e7737720bf801ce92cb1a3ce5b2c5904d3..1d18ae9d7e748d724c58fde9cc0bd0048587ab19 100644 (file)
@@ -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: