Skip to content

Commit

Permalink
Add (void) cast
Browse files Browse the repository at this point in the history
  • Loading branch information
TimWolla committed Jan 28, 2025
1 parent 7cc44af commit d78b74c
Show file tree
Hide file tree
Showing 11 changed files with 66 additions and 15 deletions.
4 changes: 3 additions & 1 deletion Zend/Optimizer/block_pass.c
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,9 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array
* If it's not local, then the other blocks successors must also eventually either FREE or consume the temporary,
* hence removing the temporary is not safe in the general case, especially when other consumers are not FREE.
* A FREE may not be removed without also removing the source's result, because otherwise that would cause a memory leak. */
if (opline->op1_type == IS_TMP_VAR) {
if (opline->extended_value == ZEND_FREE_VOID_CAST) {
/* Keep the ZEND_FREE opcode alive. */
} else if (opline->op1_type == IS_TMP_VAR) {
src = VAR_SOURCE(opline->op1);
if (src) {
switch (src->opcode) {
Expand Down
3 changes: 2 additions & 1 deletion Zend/Optimizer/dce.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ static inline bool may_have_side_effects(
case ZEND_IS_IDENTICAL:
case ZEND_IS_NOT_IDENTICAL:
case ZEND_QM_ASSIGN:
case ZEND_FREE:
case ZEND_FE_FREE:
case ZEND_TYPE_CHECK:
case ZEND_DEFINED:
Expand Down Expand Up @@ -127,6 +126,8 @@ static inline bool may_have_side_effects(
case ZEND_ARRAY_KEY_EXISTS:
/* No side effects */
return 0;
case ZEND_FREE:
return opline->extended_value == ZEND_FREE_VOID_CAST;
case ZEND_ADD_ARRAY_ELEMENT:
/* TODO: We can't free two vars. Keep instruction alive. <?php [0, "$a" => "$b"]; */
if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && (opline->op2_type & (IS_VAR|IS_TMP_VAR))) {
Expand Down
24 changes: 12 additions & 12 deletions Zend/tests/attributes/nodiscard/suppress_cast.phpt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
--TEST--
#[\NoDiscard]: Casting to (bool) suppresses.
#[\NoDiscard]: Casting to (void) suppresses.
--FILE--
<?php

Expand Down Expand Up @@ -43,22 +43,22 @@ $closure2 = #[\NoDiscard] function(): int {
return 0;
};

(bool)test();
(bool)test2();
(bool)test3(1, 2, named: 3);
(bool)call_user_func("test");
(void)test();
(void)test2();
(void)test3(1, 2, named: 3);
(void)call_user_func("test");
$fcc = test(...);
(bool)$fcc();
(void)$fcc();

$cls = new Clazz();
(bool)$cls->test();
(bool)$cls->test2();
(bool)call_user_func([$cls, "test"]);
(bool)Clazz::test3();
(void)$cls->test();
(void)$cls->test2();
(void)call_user_func([$cls, "test"]);
(void)Clazz::test3();

(bool)$closure();
(void)$closure();

(bool)$closure2();
(void)$closure2();

?>
DONE
Expand Down
31 changes: 31 additions & 0 deletions Zend/tests/attributes/nodiscard/suppress_cast_destructor.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
--TEST--
#[\NoDiscard]: Casting to (void) destroys the value.
--FILE--
<?php

class WithDestructor {
public function __destruct() {
echo __METHOD__, PHP_EOL;
}
}

#[\NoDiscard]
function test(): WithDestructor {
return new WithDestructor();
}

function do_it(): void {
echo "Before", PHP_EOL;

(void)test();

echo "After", PHP_EOL;
}

do_it();

?>
--EXPECT--
Before
WithDestructor::__destruct
After
3 changes: 3 additions & 0 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -10247,6 +10247,9 @@ static void zend_compile_cast(znode *result, zend_ast *ast) /* {{{ */
opline = zend_emit_op_tmp(result, ZEND_BOOL, &expr_node, NULL);
} else if (ast->attr == IS_NULL) {
zend_error(E_COMPILE_ERROR, "The (unset) cast is no longer supported");
} else if (ast->attr == IS_UNDEF) {
opline = zend_emit_op_tmp(NULL, ZEND_FREE, &expr_node, NULL);
opline->extended_value = ZEND_FREE_VOID_CAST;
} else {
opline = zend_emit_op_tmp(result, ZEND_CAST, &expr_node, NULL);
opline->extended_value = ast->attr;
Expand Down
1 change: 1 addition & 0 deletions Zend/zend_compile.h
Original file line number Diff line number Diff line change
Expand Up @@ -1095,6 +1095,7 @@ ZEND_API zend_string *zend_type_to_string(zend_type type);

#define ZEND_FREE_ON_RETURN (1<<0)
#define ZEND_FREE_SWITCH (1<<1)
#define ZEND_FREE_VOID_CAST (1<<2)

#define ZEND_SEND_BY_VAL 0u
#define ZEND_SEND_BY_REF 1u
Expand Down
2 changes: 2 additions & 0 deletions Zend/zend_language_parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
%token T_OBJECT_CAST "'(object)'"
%token T_BOOL_CAST "'(bool)'"
%token T_UNSET_CAST "'(unset)'"
%token T_VOID_CAST "'(void)'"
%token T_OBJECT_OPERATOR "'->'"
%token T_NULLSAFE_OBJECT_OPERATOR "'?->'"
%token T_DOUBLE_ARROW "'=>'"
Expand Down Expand Up @@ -534,6 +535,7 @@ statement:
{ $$ = zend_ast_create(ZEND_AST_TRY, $3, $5, $6); }
| T_GOTO T_STRING ';' { $$ = zend_ast_create(ZEND_AST_GOTO, $2); }
| T_STRING ':' { $$ = zend_ast_create(ZEND_AST_LABEL, $1); }
| T_VOID_CAST expr ';' { $$ = zend_ast_create_cast(IS_UNDEF, $2); }
;

catch_list:
Expand Down
4 changes: 4 additions & 0 deletions Zend/zend_language_scanner.l
Original file line number Diff line number Diff line change
Expand Up @@ -1657,6 +1657,10 @@ OPTIONAL_WHITESPACE_OR_COMMENTS ({WHITESPACE}|{MULTI_LINE_COMMENT}|{SINGLE_LINE_
RETURN_TOKEN(T_UNSET_CAST);
}

<ST_IN_SCRIPTING>"("{TABS_AND_SPACES}("void"){TABS_AND_SPACES}")" {
RETURN_TOKEN(T_VOID_CAST);
}

<ST_IN_SCRIPTING>"eval" {
RETURN_TOKEN_WITH_IDENT(T_EVAL);
}
Expand Down
1 change: 1 addition & 0 deletions ext/tokenizer/tokenizer_data.c

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions ext/tokenizer/tokenizer_data.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,11 @@
* @cvalue T_UNSET_CAST
*/
const T_UNSET_CAST = UNKNOWN;
/**
* @var int
* @cvalue T_VOID_CAST
*/
const T_VOID_CAST = UNKNOWN;
/**
* @var int
* @cvalue T_OBJECT_OPERATOR
Expand Down
3 changes: 2 additions & 1 deletion ext/tokenizer/tokenizer_data_arginfo.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit d78b74c

Please sign in to comment.