diff --git a/Zend/tests/lsb_006.phpt b/Zend/tests/lsb_006.phpt index e6296a9674042..39bff7fa92690 100644 --- a/Zend/tests/lsb_006.phpt +++ b/Zend/tests/lsb_006.phpt @@ -9,4 +9,4 @@ class Foo extends static { ?> ==DONE== --EXPECTF-- -Parse error: syntax error, unexpected T_STATIC, expecting T_STRING or T_PAAMAYIM_NEKUDOTAYIM in %s on line %d +Parse error: syntax error, unexpected T_STATIC, expecting T_STRING or T_PAAMAYIM_NEKUDOTAYIM or T_NAMESPACE in %s on line %d diff --git a/Zend/tests/lsb_007.phpt b/Zend/tests/lsb_007.phpt index 6366f09b0f662..68c2fc2757b29 100644 --- a/Zend/tests/lsb_007.phpt +++ b/Zend/tests/lsb_007.phpt @@ -9,4 +9,4 @@ class Foo implements static { ?> ==DONE== --EXPECTF-- -Parse error: syntax error, unexpected T_STATIC, expecting T_STRING or T_PAAMAYIM_NEKUDOTAYIM in %s on line %d +Parse error: syntax error, unexpected T_STATIC, expecting T_STRING or T_PAAMAYIM_NEKUDOTAYIM or T_NAMESPACE in %s on line %d diff --git a/Zend/tests/ns_057.phpt b/Zend/tests/ns_057.phpt new file mode 100755 index 0000000000000..249634335c6b5 --- /dev/null +++ b/Zend/tests/ns_057.phpt @@ -0,0 +1,56 @@ +--TEST-- +057: Usage of 'namespace' in compound names (inside namespase) +--FILE-- + +--EXPECTF-- +const ok +func ok +const ok +const ok +var ok +method ok +const ok +const ok +class ok +ok diff --git a/Zend/tests/ns_058.phpt b/Zend/tests/ns_058.phpt new file mode 100755 index 0000000000000..6c86f10f9d7e3 --- /dev/null +++ b/Zend/tests/ns_058.phpt @@ -0,0 +1,54 @@ +--TEST-- +058: Usage of 'namespace' in compound names (out of namespase) +--FILE-- + +--EXPECT-- +const ok +func ok +const ok +const ok +var ok +method ok +const ok +const ok +class ok +ok diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 36c9fa6be2d3c..31373c71c2b89 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1303,6 +1303,14 @@ void zend_do_receive_arg(zend_uchar op, znode *var, znode *offset, znode *initia zend_op *opline; zend_arg_info *cur_arg_info; + if (class_type->op_type == IS_CONST && + Z_STRLEN(class_type->u.constant) == 0) { + /* Usage of namespace as class name not in namespace */ + zval_dtor(&class_type->u.constant); + zend_error(E_COMPILE_ERROR, "Cannot use 'namespace' as a class name"); + return; + } + if (CG(active_op_array)->scope && ((CG(active_op_array)->fn_flags & ZEND_ACC_STATIC) == 0) && (Z_TYPE(varname->u.constant) == IS_STRING) && @@ -1568,6 +1576,14 @@ void zend_do_fetch_class(znode *result, znode *class_name TSRMLS_DC) long fetch_class_op_number; zend_op *opline; + if (class_name->op_type == IS_CONST && + Z_STRLEN(class_name->u.constant) == 0) { + /* Usage of namespace as class name not in namespace */ + zval_dtor(&class_name->u.constant); + zend_error(E_COMPILE_ERROR, "Cannot use 'namespace' as a class name"); + return; + } + fetch_class_op_number = get_next_op_number(CG(active_op_array)); opline = get_next_op(CG(active_op_array) TSRMLS_CC); @@ -1620,13 +1636,20 @@ void zend_do_fetch_class_name(znode *result, znode *class_name_entry, znode *cla result->u.constant.value.str.len = length; } -void zend_do_begin_class_member_function_call(znode *class_name, znode *method_name TSRMLS_DC) +int zend_do_begin_class_member_function_call(znode *class_name, znode *method_name TSRMLS_DC) { znode class_node; unsigned char *ptr = NULL; zend_op *opline; ulong fetch_type = 0; + if (class_name->op_type == IS_CONST && + Z_STRLEN(class_name->u.constant) == 0) { + /* namespace::func() not in namespace */ + zval_dtor(&class_name->u.constant); + return zend_do_begin_function_call(method_name, 0 TSRMLS_CC); + } + if (method_name->op_type == IS_CONST) { char *lcname = zend_str_tolower_dup(Z_STRVAL(method_name->u.constant), Z_STRLEN(method_name->u.constant)); if ((sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1) == Z_STRLEN(method_name->u.constant) && @@ -1689,6 +1712,7 @@ void zend_do_begin_class_member_function_call(znode *class_name, znode *method_n zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *)); zend_do_extended_fcall_begin(TSRMLS_C); + return 1; /* Dynamic */ } @@ -3524,6 +3548,15 @@ void zend_do_fetch_constant(znode *result, znode *constant_container, znode *con } break; case ZEND_RT: + if (constant_container && + constant_container->op_type == IS_CONST && + Z_STRLEN(constant_container->u.constant) == 0) { + /* Usage of namespace as class name not in namespace */ + zval_dtor(&constant_container->u.constant); + constant_container = NULL; + check_namespace = 0; + } + if (constant_container || !zend_constant_ct_subst(result, &constant_name->u.constant TSRMLS_CC)) { zend_op *opline; diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 022ac85aa713f..b2ab1ae5abcb2 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -404,7 +404,7 @@ void zend_do_clone(znode *result, znode *expr TSRMLS_DC); void zend_do_begin_dynamic_function_call(znode *function_name, int prefix_len TSRMLS_DC); void zend_do_fetch_class(znode *result, znode *class_name TSRMLS_DC); void zend_do_fetch_class_name(znode *result, znode *class_entry, znode *class_name TSRMLS_DC); -void zend_do_begin_class_member_function_call(znode *class_name, znode *method_name TSRMLS_DC); +int zend_do_begin_class_member_function_call(znode *class_name, znode *method_name TSRMLS_DC); void zend_do_end_function_call(znode *function_name, znode *result, znode *argument_list, int is_method, int is_dynamic_fcall TSRMLS_DC); void zend_do_return(znode *expr, int do_end_vparse TSRMLS_DC); void zend_do_handle_exception(TSRMLS_D); diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 517b93a612766..a96c2a6f0f10c 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -634,9 +634,9 @@ function_call: | T_PAAMAYIM_NEKUDOTAYIM T_STRING '(' { $3.u.opline_num = zend_do_begin_function_call(&$2, 0 TSRMLS_CC); } function_call_parameter_list ')' { zend_do_end_function_call(&$2, &$$, &$5, 0, $3.u.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} - | class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING '(' { zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); } + | class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING '(' { $4.u.opline_num = zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); } function_call_parameter_list - ')' { zend_do_end_function_call(NULL, &$$, &$6, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} + ')' { zend_do_end_function_call($4.u.opline_num?NULL:&$3, &$$, &$6, $4.u.opline_num, $4.u.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} | class_name T_PAAMAYIM_NEKUDOTAYIM variable_without_objects '(' { zend_do_end_variable_parse(BP_VAR_R, 0 TSRMLS_CC); zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); } function_call_parameter_list ')' { zend_do_end_function_call(NULL, &$$, &$6, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} @@ -654,12 +654,14 @@ function_call: class_name: T_STRING { $$ = $1; } | T_STATIC { $$.op_type = IS_CONST; ZVAL_STRINGL(&$$.u.constant, "static", sizeof("static")-1, 1);} + | T_NAMESPACE {if (CG(current_namespace)) { $1.op_type = IS_CONST; $1.u.constant = *CG(current_namespace); zval_copy_ctor(&$1.u.constant); zend_do_build_namespace_name(&$$, NULL, &$1 TSRMLS_CC); } else { $$.op_type = IS_CONST; ZVAL_EMPTY_STRING(&$$.u.constant); } } | T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_build_namespace_name(&$$, NULL, &$2 TSRMLS_CC); } | class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_build_namespace_name(&$$, &$1, &$3 TSRMLS_CC); } ; fully_qualified_class_name: T_STRING { $$ = $1; } + | T_NAMESPACE {if (CG(current_namespace)) { $1.op_type = IS_CONST; $1.u.constant = *CG(current_namespace); zval_copy_ctor(&$1.u.constant); zend_do_build_namespace_name(&$$, NULL, &$1 TSRMLS_CC); } else { $$.op_type = IS_CONST; ZVAL_EMPTY_STRING(&$$.u.constant); } } | T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_build_namespace_name(&$$, NULL, &$2 TSRMLS_CC); } | fully_qualified_class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_build_namespace_name(&$$, &$1, &$3 TSRMLS_CC); } ;