@@ -5501,89 +5501,178 @@ static void zend_compile_foreach(zend_ast *ast) /* {{{ */
55015501 zend_ast * value_ast = ast -> child [1 ];
55025502 zend_ast * key_ast = ast -> child [2 ];
55035503 zend_ast * stmt_ast = ast -> child [3 ];
5504- bool by_ref = value_ast -> kind == ZEND_AST_REF ;
5505- bool is_variable = zend_is_variable (expr_ast ) && zend_can_write_to_variable (expr_ast );
55065504
5507- znode expr_node , reset_node , value_node , key_node ;
5508- zend_op * opline ;
5509- uint32_t opnum_reset , opnum_fetch ;
5505+ if (! value_ast && ! key_ast ) {
5506+ bool by_ref = value_ast && value_ast -> kind == ZEND_AST_REF ;
5507+ bool is_variable = zend_is_variable ( expr_ast ) && zend_can_write_to_variable ( expr_ast ) ;
55105508
5511- if (key_ast ) {
5512- if (key_ast -> kind == ZEND_AST_REF ) {
5513- zend_error_noreturn (E_COMPILE_ERROR , "Key element cannot be a reference" );
5509+ znode expr_node , reset_node , value_node , key_node ;
5510+ zend_op * opline ;
5511+ uint32_t opnum_reset , opnum_fetch ;
5512+
5513+ if (key_ast ) {
5514+ if (key_ast -> kind == ZEND_AST_REF ) {
5515+ zend_error_noreturn (E_COMPILE_ERROR , "Key element cannot be a reference" );
5516+ }
5517+ if (key_ast -> kind == ZEND_AST_ARRAY ) {
5518+ zend_error_noreturn (E_COMPILE_ERROR , "Cannot use list as key element" );
5519+ }
55145520 }
5515- if (key_ast -> kind == ZEND_AST_ARRAY ) {
5516- zend_error_noreturn (E_COMPILE_ERROR , "Cannot use list as key element" );
5521+
5522+ if (by_ref ) {
5523+ value_ast = value_ast -> child [0 ];
55175524 }
5518- }
55195525
5520- if (by_ref ) {
5521- value_ast = value_ast -> child [ 0 ] ;
5522- }
5526+ if (value_ast && value_ast -> kind == ZEND_AST_ARRAY && zend_propagate_list_refs ( value_ast ) ) {
5527+ by_ref = 1 ;
5528+ }
55235529
5524- if (value_ast -> kind == ZEND_AST_ARRAY && zend_propagate_list_refs (value_ast )) {
5525- by_ref = 1 ;
5526- }
5530+ if (by_ref && is_variable ) {
5531+ zend_compile_var (& expr_node , expr_ast , BP_VAR_W , 1 );
5532+ } else {
5533+ zend_compile_expr (& expr_node , expr_ast );
5534+ }
55275535
5528- if (by_ref && is_variable ) {
5529- zend_compile_var (& expr_node , expr_ast , BP_VAR_W , 1 );
5530- } else {
5531- zend_compile_expr (& expr_node , expr_ast );
5532- }
5536+ if (by_ref ) {
5537+ zend_separate_if_call_and_write (& expr_node , expr_ast , BP_VAR_W );
5538+ }
55335539
5534- if (by_ref ) {
5535- zend_separate_if_call_and_write (& expr_node , expr_ast , BP_VAR_W );
5536- }
5540+ opnum_reset = get_next_op_number ();
5541+ opline = zend_emit_op (& reset_node , by_ref ? ZEND_FE_RESET_RW : ZEND_FE_RESET_R , & expr_node , NULL );
55375542
5538- opnum_reset = get_next_op_number ();
5539- opline = zend_emit_op (& reset_node , by_ref ? ZEND_FE_RESET_RW : ZEND_FE_RESET_R , & expr_node , NULL );
5543+ zend_begin_loop (ZEND_FE_FREE , & reset_node , 0 );
55405544
5541- zend_begin_loop (ZEND_FE_FREE , & reset_node , 0 );
5545+ opnum_fetch = get_next_op_number ();
5546+ opline = zend_emit_op (NULL , by_ref ? ZEND_FE_FETCH_RW : ZEND_FE_FETCH_R , & reset_node , NULL );
55425547
5543- opnum_fetch = get_next_op_number ();
5544- opline = zend_emit_op (NULL , by_ref ? ZEND_FE_FETCH_RW : ZEND_FE_FETCH_R , & reset_node , NULL );
5548+ if (value_ast && is_this_fetch (value_ast )) {
5549+ zend_error_noreturn (E_COMPILE_ERROR , "Cannot re-assign $this" );
5550+ } else if (value_ast && value_ast -> kind == ZEND_AST_VAR && zend_try_compile_cv (& value_node , value_ast ) == SUCCESS ) {
5551+ SET_NODE (opline -> op2 , & value_node );
5552+ } else {
5553+ opline -> op2_type = IS_VAR ;
5554+ opline -> op2 .var = get_temporary_variable ();
5555+ GET_NODE (& value_node , opline -> op2 );
5556+ if (value_ast -> kind == ZEND_AST_ARRAY ) {
5557+ zend_compile_list_assign (NULL , value_ast , & value_node , value_ast -> attr );
5558+ } else if (by_ref ) {
5559+ zend_emit_assign_ref_znode (value_ast , & value_node );
5560+ } else {
5561+ zend_emit_assign_znode (value_ast , & value_node );
5562+ }
5563+ }
55455564
5546- if (is_this_fetch (value_ast )) {
5547- zend_error_noreturn (E_COMPILE_ERROR , "Cannot re-assign $this" );
5548- } else if (value_ast -> kind == ZEND_AST_VAR &&
5549- zend_try_compile_cv (& value_node , value_ast ) == SUCCESS ) {
5550- SET_NODE (opline -> op2 , & value_node );
5565+ if (key_ast ) {
5566+ opline = & CG (active_op_array )-> opcodes [opnum_fetch ];
5567+ zend_make_tmp_result (& key_node , opline );
5568+ zend_emit_assign_znode (key_ast , & key_node );
5569+ }
5570+
5571+ zend_compile_stmt (stmt_ast );
5572+
5573+ /* Place JMP and FE_FREE on the line where foreach starts. It would be
5574+ * better to use the end line, but this information is not available
5575+ * currently. */
5576+ CG (zend_lineno ) = ast -> lineno ;
5577+ zend_emit_jump (opnum_fetch );
5578+
5579+ opline = & CG (active_op_array )-> opcodes [opnum_reset ];
5580+ opline -> op2 .opline_num = get_next_op_number ();
5581+
5582+ opline = & CG (active_op_array )-> opcodes [opnum_fetch ];
5583+ opline -> extended_value = get_next_op_number ();
5584+
5585+ zend_end_loop (opnum_fetch , & reset_node );
5586+
5587+ opline = zend_emit_op (NULL , ZEND_FE_FREE , & reset_node , NULL );
55515588 } else {
5552- opline -> op2_type = IS_VAR ;
5553- opline -> op2 .var = get_temporary_variable ();
5554- GET_NODE (& value_node , opline -> op2 );
5555- if (value_ast -> kind == ZEND_AST_ARRAY ) {
5556- zend_compile_list_assign (NULL , value_ast , & value_node , value_ast -> attr );
5557- } else if (by_ref ) {
5558- zend_emit_assign_ref_znode (value_ast , & value_node );
5589+ bool by_ref = value_ast && value_ast -> kind == ZEND_AST_REF ;
5590+ bool is_variable = zend_is_variable (expr_ast ) && zend_can_write_to_variable (expr_ast );
5591+
5592+ znode expr_node , reset_node , value_node , key_node ;
5593+ zend_op * opline ;
5594+ uint32_t opnum_reset , opnum_fetch ;
5595+
5596+ if (key_ast ) {
5597+ if (key_ast -> kind == ZEND_AST_REF ) {
5598+ zend_error_noreturn (E_COMPILE_ERROR , "Key element cannot be a reference" );
5599+ }
5600+ if (key_ast -> kind == ZEND_AST_ARRAY ) {
5601+ zend_error_noreturn (E_COMPILE_ERROR , "Cannot use list as key element" );
5602+ }
5603+ }
5604+
5605+ if (by_ref ) {
5606+ value_ast = value_ast -> child [0 ];
5607+ }
5608+
5609+ if (value_ast && value_ast -> kind == ZEND_AST_ARRAY && zend_propagate_list_refs (value_ast )) {
5610+ by_ref = 1 ;
5611+ }
5612+
5613+ if (by_ref && is_variable ) {
5614+ zend_compile_var (& expr_node , expr_ast , BP_VAR_W , 1 );
55595615 } else {
5560- zend_emit_assign_znode ( value_ast , & value_node );
5616+ zend_compile_expr ( & expr_node , expr_ast );
55615617 }
5562- }
55635618
5564- if (key_ast ) {
5565- opline = & CG (active_op_array )-> opcodes [opnum_fetch ];
5566- zend_make_tmp_result (& key_node , opline );
5567- zend_emit_assign_znode (key_ast , & key_node );
5568- }
5619+ if (by_ref ) {
5620+ zend_separate_if_call_and_write (& expr_node , expr_ast , BP_VAR_W );
5621+ }
55695622
5570- zend_compile_stmt (stmt_ast );
5623+ opnum_reset = get_next_op_number ();
5624+ opline = zend_emit_op (& reset_node , ZEND_FE_RESET_R , & expr_node , NULL );
55715625
5572- /* Place JMP and FE_FREE on the line where foreach starts. It would be
5573- * better to use the end line, but this information is not available
5574- * currently. */
5575- CG (zend_lineno ) = ast -> lineno ;
5576- zend_emit_jump (opnum_fetch );
5626+ zend_begin_loop (ZEND_FE_FREE , & reset_node , 0 );
55775627
5578- opline = & CG (active_op_array )-> opcodes [opnum_reset ];
5579- opline -> op2 .opline_num = get_next_op_number ();
5628+ opnum_fetch = get_next_op_number ();
5629+ opline = zend_emit_op (NULL , ZEND_FE_FETCH_R , & reset_node , NULL );
5630+ if (value_ast ) {
5631+ if (is_this_fetch (value_ast )) {
5632+ zend_error_noreturn (E_COMPILE_ERROR , "Cannot re-assign $this" );
5633+ } else
5634+ if (value_ast -> kind == ZEND_AST_VAR && zend_try_compile_cv (& value_node , value_ast ) == SUCCESS ) {
5635+ SET_NODE (opline -> op2 , & value_node );
5636+ }
5637+ else {
5638+ opline -> op2_type = IS_VAR ;
5639+ opline -> op2 .var = get_temporary_variable ();
5640+ GET_NODE (& value_node , opline -> op2 );
5641+ if (value_ast -> kind == ZEND_AST_ARRAY ) {
5642+ zend_compile_list_assign (NULL , value_ast , & value_node , value_ast -> attr );
5643+ } else
5644+ if (by_ref ) {
5645+ zend_emit_assign_ref_znode (value_ast , & value_node );
5646+ } else {
5647+ zend_emit_assign_znode (value_ast , & value_node );
5648+ }
5649+ }
5650+ }
55805651
5581- opline = & CG (active_op_array )-> opcodes [opnum_fetch ];
5582- opline -> extended_value = get_next_op_number ();
5652+ if (key_ast ) {
5653+ opline = & CG (active_op_array )-> opcodes [opnum_fetch ];
5654+ zend_make_tmp_result (& key_node , opline );
5655+ zend_emit_assign_znode (key_ast , & key_node );
5656+ }
55835657
5584- zend_end_loop (opnum_fetch , & reset_node );
5658+ zend_compile_stmt (stmt_ast );
5659+
5660+ /* Place JMP and FE_FREE on the line where foreach starts. It would be
5661+ * better to use the end line, but this information is not available
5662+ * currently. */
5663+ CG (zend_lineno ) = ast -> lineno ;
5664+ zend_emit_jump (opnum_fetch );
5665+
5666+ opline = & CG (active_op_array )-> opcodes [opnum_reset ];
5667+ opline -> op2 .opline_num = get_next_op_number ();
55855668
5586- opline = zend_emit_op (NULL , ZEND_FE_FREE , & reset_node , NULL );
5669+ opline = & CG (active_op_array )-> opcodes [opnum_fetch ];
5670+ opline -> extended_value = get_next_op_number ();
5671+
5672+ zend_end_loop (opnum_fetch , & reset_node );
5673+
5674+ opline = zend_emit_op (NULL , ZEND_FE_FREE , & reset_node , NULL );
5675+ }
55875676}
55885677/* }}} */
55895678
0 commit comments