Index: Zend/zend_compile.c =================================================================== --- Zend/zend_compile.c (revision 286822) +++ Zend/zend_compile.c (working copy) @@ -677,6 +677,8 @@ } n++; } + } else { + zend_check_writable_variable(variable); } opline->opcode = ZEND_ASSIGN; @@ -962,6 +964,9 @@ if (type == ZEND_PARSED_FUNCTION_CALL) { zend_error(E_COMPILE_ERROR, "Can't use function return value in write context"); } + if (variable->op_type == IS_CONST || variable->op_type == IS_TMP_VAR) { + zend_error(E_COMPILE_ERROR, "Can't use constant value in write context"); + } } /* }}} */ @@ -2088,47 +2093,52 @@ zend_stack_top(&CG(function_call_stack), (void **) &function_ptr_ptr); function_ptr = *function_ptr_ptr; - if (original_op == ZEND_SEND_REF && !CG(allow_call_time_pass_reference)) { - if (function_ptr && - function_ptr->common.function_name && - function_ptr->common.type == ZEND_USER_FUNCTION && - !ARG_SHOULD_BE_SENT_BY_REF(function_ptr, (zend_uint) offset)) { - zend_error(E_DEPRECATED, - "Call-time pass-by-reference has been deprecated; " - "If you would like to pass it by reference, modify the declaration of %s(). " - "If you would like to enable call-time pass-by-reference, you can set " - "allow_call_time_pass_reference to true in your INI file", function_ptr->common.function_name); - } else { - zend_error(E_DEPRECATED, "Call-time pass-by-reference has been deprecated"); + if (param->op_type & (IS_CONST | IS_TMP_VAR)) { + op = ZEND_SEND_VAL; + send_by_reference = 0; + } else { + if (original_op == ZEND_SEND_REF && !CG(allow_call_time_pass_reference)) { + if (function_ptr && + function_ptr->common.function_name && + function_ptr->common.type == ZEND_USER_FUNCTION && + !ARG_SHOULD_BE_SENT_BY_REF(function_ptr, (zend_uint) offset)) { + zend_error(E_DEPRECATED, + "Call-time pass-by-reference has been deprecated; " + "If you would like to pass it by reference, modify the declaration of %s(). " + "If you would like to enable call-time pass-by-reference, you can set " + "allow_call_time_pass_reference to true in your INI file", function_ptr->common.function_name); + } else { + zend_error(E_DEPRECATED, "Call-time pass-by-reference has been deprecated"); + } } - } - if (function_ptr) { - if (ARG_MAY_BE_SENT_BY_REF(function_ptr, (zend_uint) offset)) { - if (param->op_type & (IS_VAR|IS_CV)) { - send_by_reference = 1; - if (op == ZEND_SEND_VAR && zend_is_function_or_method_call(param)) { - /* Method call */ - op = ZEND_SEND_VAR_NO_REF; - send_function = ZEND_ARG_SEND_FUNCTION | ZEND_ARG_SEND_SILENT; + if (function_ptr) { + if (ARG_MAY_BE_SENT_BY_REF(function_ptr, (zend_uint) offset)) { + if (param->op_type & (IS_VAR|IS_CV)) { + send_by_reference = 1; + if (op == ZEND_SEND_VAR && zend_is_function_or_method_call(param)) { + /* Method call */ + op = ZEND_SEND_VAR_NO_REF; + send_function = ZEND_ARG_SEND_FUNCTION | ZEND_ARG_SEND_SILENT; + } + } else { + op = ZEND_SEND_VAL; + send_by_reference = 0; } } else { - op = ZEND_SEND_VAL; - send_by_reference = 0; + send_by_reference = ARG_SHOULD_BE_SENT_BY_REF(function_ptr, (zend_uint) offset) ? ZEND_ARG_SEND_BY_REF : 0; } } else { - send_by_reference = ARG_SHOULD_BE_SENT_BY_REF(function_ptr, (zend_uint) offset) ? ZEND_ARG_SEND_BY_REF : 0; + send_by_reference = 0; } - } else { - send_by_reference = 0; - } - if (op == ZEND_SEND_VAR && zend_is_function_or_method_call(param)) { - /* Method call */ - op = ZEND_SEND_VAR_NO_REF; - send_function = ZEND_ARG_SEND_FUNCTION; - } else if (op == ZEND_SEND_VAL && (param->op_type & (IS_VAR|IS_CV))) { - op = ZEND_SEND_VAR_NO_REF; + if (op == ZEND_SEND_VAR && zend_is_function_or_method_call(param)) { + /* Method call */ + op = ZEND_SEND_VAR_NO_REF; + send_function = ZEND_ARG_SEND_FUNCTION; + } else if (op == ZEND_SEND_VAL && (param->op_type & (IS_VAR|IS_CV))) { + op = ZEND_SEND_VAR_NO_REF; + } } if (op!=ZEND_SEND_VAR_NO_REF && send_by_reference==ZEND_ARG_SEND_BY_REF) { @@ -2146,6 +2156,7 @@ if (original_op == ZEND_SEND_VAR) { switch (op) { + case ZEND_SEND_VAL: case ZEND_SEND_VAR_NO_REF: zend_do_end_variable_parse(param, BP_VAR_R, 0 TSRMLS_CC); break; Index: Zend/zend_language_parser.y =================================================================== --- Zend/zend_language_parser.y (revision 286822) +++ Zend/zend_language_parser.y (working copy) @@ -47,7 +47,7 @@ %} %pure_parser -%expect 2 +%expect 20 %left T_INCLUDE T_INCLUDE_ONCE T_EVAL T_REQUIRE T_REQUIRE_ONCE %left ',' @@ -236,7 +236,7 @@ | T_CONTINUE ';' { zend_do_brk_cont(ZEND_CONT, NULL TSRMLS_CC); } | T_CONTINUE expr ';' { zend_do_brk_cont(ZEND_CONT, &$2 TSRMLS_CC); } | T_RETURN ';' { zend_do_return(NULL, 0 TSRMLS_CC); } - | T_RETURN expr_without_variable ';' { zend_do_return(&$2, 0 TSRMLS_CC); } + | T_RETURN expr_without_variable_and_intrinsics ';' { zend_do_return(&$2, 0 TSRMLS_CC); } | T_RETURN variable ';' { zend_do_return(&$2, 1 TSRMLS_CC); } | T_GLOBAL global_var_list ';' | T_STATIC static_var_list ';' @@ -248,7 +248,7 @@ { zend_do_foreach_begin(&$1, &$2, &$3, &$4, 1 TSRMLS_CC); } foreach_variable foreach_optional_arg ')' { zend_do_foreach_cont(&$1, &$2, &$4, &$6, &$7 TSRMLS_CC); } foreach_statement { zend_do_foreach_end(&$1, &$4 TSRMLS_CC); } - | T_FOREACH '(' expr_without_variable T_AS + | T_FOREACH '(' expr_without_variable_and_intrinsics T_AS { zend_do_foreach_begin(&$1, &$2, &$3, &$4, 0 TSRMLS_CC); } variable foreach_optional_arg ')' { zend_check_writable_variable(&$6); zend_do_foreach_cont(&$1, &$2, &$4, &$6, &$7 TSRMLS_CC); } foreach_statement { zend_do_foreach_end(&$1, &$4 TSRMLS_CC); } @@ -475,10 +475,10 @@ non_empty_function_call_parameter_list: - expr_without_variable { Z_LVAL($$.u.constant) = 1; zend_do_pass_param(&$1, ZEND_SEND_VAL, Z_LVAL($$.u.constant) TSRMLS_CC); } + expr_without_variable_and_intrinsics { Z_LVAL($$.u.constant) = 1; zend_do_pass_param(&$1, ZEND_SEND_VAL, Z_LVAL($$.u.constant) TSRMLS_CC); } | variable { Z_LVAL($$.u.constant) = 1; zend_do_pass_param(&$1, ZEND_SEND_VAR, Z_LVAL($$.u.constant) TSRMLS_CC); } | '&' w_variable { Z_LVAL($$.u.constant) = 1; zend_do_pass_param(&$2, ZEND_SEND_REF, Z_LVAL($$.u.constant) TSRMLS_CC); } - | non_empty_function_call_parameter_list ',' expr_without_variable { Z_LVAL($$.u.constant)=Z_LVAL($1.u.constant)+1; zend_do_pass_param(&$3, ZEND_SEND_VAL, Z_LVAL($$.u.constant) TSRMLS_CC); } + | non_empty_function_call_parameter_list ',' expr_without_variable_and_intrinsics { Z_LVAL($$.u.constant)=Z_LVAL($1.u.constant)+1; zend_do_pass_param(&$3, ZEND_SEND_VAL, Z_LVAL($$.u.constant) TSRMLS_CC); } | non_empty_function_call_parameter_list ',' variable { Z_LVAL($$.u.constant)=Z_LVAL($1.u.constant)+1; zend_do_pass_param(&$3, ZEND_SEND_VAR, Z_LVAL($$.u.constant) TSRMLS_CC); } | non_empty_function_call_parameter_list ',' '&' w_variable { Z_LVAL($$.u.constant)=Z_LVAL($1.u.constant)+1; zend_do_pass_param(&$4, ZEND_SEND_REF, Z_LVAL($$.u.constant) TSRMLS_CC); } ; @@ -491,7 +491,7 @@ global_var: T_VARIABLE { $$ = $1; } - | '$' r_variable { $$ = $2; } + | '$' variable { zend_do_end_variable_parse(&$2, BP_VAR_R, 0 TSRMLS_CC); $$ = $2; } | '$' '{' expr '}' { $$ = $3; } ; @@ -576,13 +576,10 @@ | expr { $$ = $1; } ; -expr_without_variable: +expr_without_variable_and_intrinsics: T_LIST '(' { zend_do_list_init(TSRMLS_C); } assignment_list ')' '=' expr { zend_do_list_end(&$$, &$7 TSRMLS_CC); } | variable '=' expr { zend_check_writable_variable(&$1); zend_do_assign(&$$, &$1, &$3 TSRMLS_CC); } | variable '=' '&' variable { zend_check_writable_variable(&$1); zend_do_end_variable_parse(&$4, BP_VAR_W, 1 TSRMLS_CC); zend_do_end_variable_parse(&$1, BP_VAR_W, 0 TSRMLS_CC); zend_do_assign_ref(&$$, &$1, &$4 TSRMLS_CC); } - | variable '=' '&' T_NEW class_name_reference { zend_error(E_DEPRECATED, "Assigning the return value of new by reference is deprecated"); zend_check_writable_variable(&$1); zend_do_extended_fcall_begin(TSRMLS_C); zend_do_begin_new_object(&$4, &$5 TSRMLS_CC); } ctor_arguments { zend_do_end_new_object(&$3, &$4, &$7 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); zend_do_end_variable_parse(&$1, BP_VAR_W, 0 TSRMLS_CC); $3.u.EA.type = ZEND_PARSED_NEW; zend_do_assign_ref(&$$, &$1, &$3 TSRMLS_CC); } - | T_NEW class_name_reference { zend_do_extended_fcall_begin(TSRMLS_C); zend_do_begin_new_object(&$1, &$2 TSRMLS_CC); } ctor_arguments { zend_do_end_new_object(&$$, &$1, &$4 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} - | T_CLONE expr { zend_do_clone(&$$, &$2 TSRMLS_CC); } | variable T_PLUS_EQUAL expr { zend_check_writable_variable(&$1); zend_do_end_variable_parse(&$1, BP_VAR_RW, 0 TSRMLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_ADD, &$$, &$1, &$3 TSRMLS_CC); } | variable T_MINUS_EQUAL expr { zend_check_writable_variable(&$1); zend_do_end_variable_parse(&$1, BP_VAR_RW, 0 TSRMLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_SUB, &$$, &$1, &$3 TSRMLS_CC); } | variable T_MUL_EQUAL expr { zend_check_writable_variable(&$1); zend_do_end_variable_parse(&$1, BP_VAR_RW, 0 TSRMLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_MUL, &$$, &$1, &$3 TSRMLS_CC); } @@ -594,10 +591,10 @@ | variable T_XOR_EQUAL expr { zend_check_writable_variable(&$1); zend_do_end_variable_parse(&$1, BP_VAR_RW, 0 TSRMLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_BW_XOR, &$$, &$1, &$3 TSRMLS_CC); } | variable T_SL_EQUAL expr { zend_check_writable_variable(&$1); zend_do_end_variable_parse(&$1, BP_VAR_RW, 0 TSRMLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_SL, &$$, &$1, &$3 TSRMLS_CC); } | variable T_SR_EQUAL expr { zend_check_writable_variable(&$1); zend_do_end_variable_parse(&$1, BP_VAR_RW, 0 TSRMLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_SR, &$$, &$1, &$3 TSRMLS_CC); } - | rw_variable T_INC { zend_do_post_incdec(&$$, &$1, ZEND_POST_INC TSRMLS_CC); } - | T_INC rw_variable { zend_do_pre_incdec(&$$, &$2, ZEND_PRE_INC TSRMLS_CC); } - | rw_variable T_DEC { zend_do_post_incdec(&$$, &$1, ZEND_POST_DEC TSRMLS_CC); } - | T_DEC rw_variable { zend_do_pre_incdec(&$$, &$2, ZEND_PRE_DEC TSRMLS_CC); } + | variable T_INC { zend_do_end_variable_parse(&$1, BP_VAR_RW, 0 TSRMLS_CC); zend_check_writable_variable(&$1); zend_do_post_incdec(&$$, &$1, ZEND_POST_INC TSRMLS_CC); } + | T_INC variable { zend_do_end_variable_parse(&$2, BP_VAR_RW, 0 TSRMLS_CC); zend_check_writable_variable(&$2); zend_do_pre_incdec(&$$, &$2, ZEND_PRE_INC TSRMLS_CC); } + | variable T_DEC { zend_do_end_variable_parse(&$1, BP_VAR_RW, 0 TSRMLS_CC); zend_check_writable_variable(&$1); zend_do_post_incdec(&$$, &$1, ZEND_POST_DEC TSRMLS_CC); } + | T_DEC variable { zend_do_end_variable_parse(&$2, BP_VAR_RW, 0 TSRMLS_CC); zend_check_writable_variable(&$2); zend_do_pre_incdec(&$$, &$2, ZEND_PRE_DEC TSRMLS_CC); } | expr T_BOOLEAN_OR { zend_do_boolean_or_begin(&$1, &$2 TSRMLS_CC); } expr { zend_do_boolean_or_end(&$$, &$1, &$4, &$2 TSRMLS_CC); } | expr T_BOOLEAN_AND { zend_do_boolean_and_begin(&$1, &$2 TSRMLS_CC); } expr { zend_do_boolean_and_end(&$$, &$1, &$4, &$2 TSRMLS_CC); } | expr T_LOGICAL_OR { zend_do_boolean_or_begin(&$1, &$2 TSRMLS_CC); } expr { zend_do_boolean_or_end(&$$, &$1, &$4, &$2 TSRMLS_CC); } @@ -627,7 +624,6 @@ | expr '>' expr { zend_do_binary_op(ZEND_IS_SMALLER, &$$, &$3, &$1 TSRMLS_CC); } | expr T_IS_GREATER_OR_EQUAL expr { zend_do_binary_op(ZEND_IS_SMALLER_OR_EQUAL, &$$, &$3, &$1 TSRMLS_CC); } | expr T_INSTANCEOF class_name_reference { zend_do_instanceof(&$$, &$1, &$3, 0 TSRMLS_CC); } - | '(' expr ')' { $$ = $2; } | expr '?' { zend_do_begin_qm_op(&$1, &$2 TSRMLS_CC); } expr ':' { zend_do_qm_true(&$4, &$2, &$5 TSRMLS_CC); } expr { zend_do_qm_false(&$$, &$7, &$2, &$5 TSRMLS_CC); } @@ -642,14 +638,20 @@ | T_BOOL_CAST expr { zend_do_cast(&$$, &$2, IS_BOOL TSRMLS_CC); } | T_UNSET_CAST expr { zend_do_cast(&$$, &$2, IS_NULL TSRMLS_CC); } | T_EXIT exit_expr { zend_do_exit(&$$, &$2 TSRMLS_CC); } + | T_PRINT expr { zend_do_print(&$$, &$2 TSRMLS_CC); } +; + +intrinsics: + '(' expr ')' { $$ = $2; } | '@' { zend_do_begin_silence(&$1 TSRMLS_CC); } expr { zend_do_end_silence(&$1 TSRMLS_CC); $$ = $3; } | scalar { $$ = $1; } | T_ARRAY '(' array_pair_list ')' { $$ = $3; } | '`' backticks_expr '`' { zend_do_shell_exec(&$$, &$2 TSRMLS_CC); } - | T_PRINT expr { zend_do_print(&$$, &$2 TSRMLS_CC); } | function is_reference '(' { zend_do_begin_lambda_function_declaration(&$$, &$1, $2.op_type TSRMLS_CC); } parameter_list ')' lexical_vars '{' inner_statement_list '}' { zend_do_end_function_declaration(&$1 TSRMLS_CC); $$ = $4; } -; + | T_NEW class_name_reference { zend_do_extended_fcall_begin(TSRMLS_C); zend_do_begin_new_object(&$1, &$2 TSRMLS_CC); } ctor_arguments { zend_do_end_new_object(&$$, &$1, &$4 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); $$.u.EA.type = ZEND_PARSED_NEW; } + | T_CLONE expr { zend_do_clone(&$$, &$2 TSRMLS_CC); } + ; function: T_FUNCTION { $$.u.opline_num = CG(zend_lineno); } @@ -813,26 +815,15 @@ ; expr: - r_variable { $$ = $1; } - | expr_without_variable { $$ = $1; } + variable { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); $$ = $1; } + | expr_without_variable_and_intrinsics { $$ = $1; } ; - -r_variable: - variable { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); $$ = $1; } -; - - w_variable: variable { zend_do_end_variable_parse(&$1, BP_VAR_W, 0 TSRMLS_CC); $$ = $1; zend_check_writable_variable(&$1); } ; -rw_variable: - variable { zend_do_end_variable_parse(&$1, BP_VAR_RW, 0 TSRMLS_CC); $$ = $1; - zend_check_writable_variable(&$1); } -; - variable: base_variable_with_function_calls T_OBJECT_OPERATOR { zend_do_push_object(&$1 TSRMLS_CC); } object_property { zend_do_push_object(&$4 TSRMLS_CC); } method_or_not variable_properties @@ -876,6 +867,7 @@ base_variable_with_function_calls: base_variable { $$ = $1; } | function_call { zend_do_begin_variable_parse(TSRMLS_C); $$ = $1; $$.u.EA.type = ZEND_PARSED_FUNCTION_CALL; } + | intrinsics { zend_do_begin_variable_parse(TSRMLS_C); $$ = $1; } ; Index: Zend/zend_vm_def.h =================================================================== --- Zend/zend_vm_def.h (revision 286822) +++ Zend/zend_vm_def.h (working copy) @@ -1915,7 +1915,7 @@ } } -ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV) +ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, ANY, CONST|TMP|VAR|CV) { zend_op *opline = EX(opline); zval *function_name;