mirror of
https://github.com/php/php-src.git
synced 2025-08-15 13:38:49 +02:00
RFC: Marking return values as important (#[\NoDiscard]) (#17599)
RFC: https://wiki.php.net/rfc/marking_return_value_as_important Co-authored-by: Volker Dusch <volker@tideways-gmbh.com>
This commit is contained in:
parent
f11c22ae30
commit
5544be7018
52 changed files with 1261 additions and 68 deletions
4
NEWS
4
NEWS
|
@ -38,8 +38,10 @@ PHP NEWS
|
|||
. Fixed bug GH-18033 (NULL-ptr dereference when using register_tick_function
|
||||
in destructor). (nielsdos)
|
||||
. Fixed bug GH-18026 (Improve "expecting token" error for ampersand). (ilutov)
|
||||
. Added the #[\NoDiscard] attribute to indicate that a function's return
|
||||
value is important and should be consumed. (timwolla, Volker Dusch)
|
||||
. Added the (void) cast to indicate that not using a value is intentional.
|
||||
(timwolla)
|
||||
(timwolla, Volker Dusch)
|
||||
. Added get_error_handler(), get_exception_handler() functions. (Arnaud)
|
||||
. Fixed bug GH-15753 and GH-16198 (Bind traits before parent class). (ilutov)
|
||||
|
||||
|
|
|
@ -114,8 +114,13 @@ PHP 8.5 UPGRADE NOTES
|
|||
. Fatal Errors (such as an exceeded maximum execution time) now include a
|
||||
backtrace.
|
||||
RFC: https://wiki.php.net/rfc/error_backtraces_v2
|
||||
. Added the (void) to indicate that not using a value is intentional. The
|
||||
(void) cast does nothing by itself.
|
||||
. Added the #[\NoDiscard] attribute to indicate that a function's return
|
||||
value is important and should be consumed.
|
||||
RFC: https://wiki.php.net/rfc/marking_return_value_as_important
|
||||
. Added the (void) cast to indicate that not using a value is intentional.
|
||||
The (void) cast has no effect on the program's execution by itself, but
|
||||
it can be used to suppress warnings emitted by #[\NoDiscard] and possibly
|
||||
also diagnostics emitted by external IDEs or static analysis tools.
|
||||
RFC: https://wiki.php.net/rfc/marking_return_value_as_important
|
||||
|
||||
- Curl:
|
||||
|
|
|
@ -78,8 +78,10 @@ static void zend_delete_call_instructions(zend_op_array *op_array, zend_op *opli
|
|||
|
||||
static void zend_try_inline_call(zend_op_array *op_array, zend_op *fcall, zend_op *opline, zend_function *func)
|
||||
{
|
||||
const uint32_t no_discard = RETURN_VALUE_USED(opline) ? 0 : ZEND_ACC_NODISCARD;
|
||||
|
||||
if (func->type == ZEND_USER_FUNCTION
|
||||
&& !(func->op_array.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_DEPRECATED))
|
||||
&& !(func->op_array.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_DEPRECATED|no_discard))
|
||||
/* TODO: function copied from trait may be inconsistent ??? */
|
||||
&& !(func->op_array.fn_flags & (ZEND_ACC_TRAIT_CLONE))
|
||||
&& fcall->extended_value >= func->op_array.required_num_args
|
||||
|
@ -202,18 +204,12 @@ void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx)
|
|||
fcall->op1.num = zend_vm_calc_used_stack(fcall->extended_value, call_stack[call].func);
|
||||
literal_dtor(&ZEND_OP2_LITERAL(fcall));
|
||||
fcall->op2.constant = fcall->op2.constant + 1;
|
||||
if (opline->opcode != ZEND_CALLABLE_CONVERT) {
|
||||
opline->opcode = zend_get_call_op(fcall, call_stack[call].func);
|
||||
}
|
||||
} else if (fcall->opcode == ZEND_INIT_NS_FCALL_BY_NAME) {
|
||||
fcall->opcode = ZEND_INIT_FCALL;
|
||||
fcall->op1.num = zend_vm_calc_used_stack(fcall->extended_value, call_stack[call].func);
|
||||
literal_dtor(&op_array->literals[fcall->op2.constant]);
|
||||
literal_dtor(&op_array->literals[fcall->op2.constant + 2]);
|
||||
fcall->op2.constant = fcall->op2.constant + 1;
|
||||
if (opline->opcode != ZEND_CALLABLE_CONVERT) {
|
||||
opline->opcode = zend_get_call_op(fcall, call_stack[call].func);
|
||||
}
|
||||
} else if (fcall->opcode == ZEND_INIT_STATIC_METHOD_CALL
|
||||
|| fcall->opcode == ZEND_INIT_METHOD_CALL
|
||||
|| fcall->opcode == ZEND_INIT_PARENT_PROPERTY_HOOK_CALL
|
||||
|
@ -223,6 +219,16 @@ void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx)
|
|||
ZEND_UNREACHABLE();
|
||||
}
|
||||
|
||||
/* If the INIT opcode changed the DO opcode can also change to
|
||||
* a more optimized one.
|
||||
*
|
||||
* At this point we also know whether or not the result of
|
||||
* the DO opcode is used, allowing to optimize calls to
|
||||
* ZEND_ACC_NODISCARD functions. */
|
||||
if (opline->opcode != ZEND_CALLABLE_CONVERT) {
|
||||
opline->opcode = zend_get_call_op(fcall, call_stack[call].func, !RESULT_UNUSED(opline));
|
||||
}
|
||||
|
||||
if ((ZEND_OPTIMIZER_PASS_16 & ctx->optimization_level)
|
||||
&& call_stack[call].try_inline
|
||||
&& opline->opcode != ZEND_CALLABLE_CONVERT) {
|
||||
|
|
86
Zend/tests/attributes/nodiscard/001.phpt
Normal file
86
Zend/tests/attributes/nodiscard/001.phpt
Normal file
|
@ -0,0 +1,86 @@
|
|||
--TEST--
|
||||
#[\NoDiscard]: Basic test.
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
#[\NoDiscard]
|
||||
function test(): int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#[\NoDiscard("this is important")]
|
||||
function test2(): int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#[\NoDiscard]
|
||||
function test3(...$args): int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
class Clazz {
|
||||
#[\NoDiscard]
|
||||
function test(): int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#[\NoDiscard("this is important")]
|
||||
function test2(): int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#[\NoDiscard]
|
||||
static function test3(): int {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
$closure = #[\NoDiscard] function(): int {
|
||||
return 0;
|
||||
};
|
||||
|
||||
$closure2 = #[\NoDiscard] function(): int {
|
||||
return 0;
|
||||
};
|
||||
|
||||
test();
|
||||
test2();
|
||||
test3(1, 2, named: 3);
|
||||
call_user_func("test");
|
||||
$fcc = test(...);
|
||||
$fcc();
|
||||
|
||||
$cls = new Clazz();
|
||||
$cls->test();
|
||||
$cls->test2();
|
||||
Clazz::test3();
|
||||
|
||||
call_user_func([$cls, "test"]);
|
||||
|
||||
$closure();
|
||||
|
||||
$closure2();
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Warning: The return value of function test() should either be used or intentionally ignored by casting it as (void) in %s on line %d
|
||||
|
||||
Warning: The return value of function test2() should either be used or intentionally ignored by casting it as (void), this is important in %s on line %d
|
||||
|
||||
Warning: The return value of function test3() should either be used or intentionally ignored by casting it as (void) in %s on line %d
|
||||
|
||||
Warning: The return value of function test() should either be used or intentionally ignored by casting it as (void) in %s on line %d
|
||||
|
||||
Warning: The return value of function test() should either be used or intentionally ignored by casting it as (void) in %s on line %d
|
||||
|
||||
Warning: The return value of method Clazz::test() should either be used or intentionally ignored by casting it as (void) in %s on line %d
|
||||
|
||||
Warning: The return value of method Clazz::test2() should either be used or intentionally ignored by casting it as (void), this is important in %s on line %d
|
||||
|
||||
Warning: The return value of method Clazz::test3() should either be used or intentionally ignored by casting it as (void) in %s on line %d
|
||||
|
||||
Warning: The return value of method Clazz::test() should either be used or intentionally ignored by casting it as (void) in %s on line %d
|
||||
|
||||
Warning: The return value of function {closure:%s:%d}() should either be used or intentionally ignored by casting it as (void) in %s on line %d
|
||||
|
||||
Warning: The return value of function {closure:%s:%d}() should either be used or intentionally ignored by casting it as (void) in %s on line %d
|
44
Zend/tests/attributes/nodiscard/002.phpt
Normal file
44
Zend/tests/attributes/nodiscard/002.phpt
Normal file
|
@ -0,0 +1,44 @@
|
|||
--TEST--
|
||||
#[\NoDiscard]: __call(), __callStatic(), and __invoke().
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class Clazz {
|
||||
#[\NoDiscard]
|
||||
public function __call(string $name, array $args): int {
|
||||
echo "__call({$name})", PHP_EOL;
|
||||
|
||||
return strlen($name);
|
||||
}
|
||||
|
||||
#[\NoDiscard]
|
||||
public static function __callStatic(string $name, array $args): int {
|
||||
echo "__callStatic({$name})", PHP_EOL;
|
||||
|
||||
return strlen($name);
|
||||
}
|
||||
|
||||
#[\NoDiscard]
|
||||
public function __invoke(string $param): int {
|
||||
echo "__invoke({$param})", PHP_EOL;
|
||||
|
||||
return strlen($param);
|
||||
}
|
||||
}
|
||||
|
||||
$cls = new Clazz();
|
||||
$cls->test();
|
||||
Clazz::test();
|
||||
$cls('foo');
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Warning: The return value of method Clazz::test() should either be used or intentionally ignored by casting it as (void) in %s on line %d
|
||||
__call(test)
|
||||
|
||||
Warning: The return value of method Clazz::test() should either be used or intentionally ignored by casting it as (void) in %s on line %d
|
||||
__callStatic(test)
|
||||
|
||||
Warning: The return value of method Clazz::__invoke() should either be used or intentionally ignored by casting it as (void) in %s on line %d
|
||||
__invoke(foo)
|
||||
|
22
Zend/tests/attributes/nodiscard/003.phpt
Normal file
22
Zend/tests/attributes/nodiscard/003.phpt
Normal file
|
@ -0,0 +1,22 @@
|
|||
--TEST--
|
||||
#[\NoDiscard]: Taken from trait.
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
trait T {
|
||||
#[\NoDiscard]
|
||||
function test(): int {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
class Clazz {
|
||||
use T;
|
||||
}
|
||||
|
||||
$cls = new Clazz();
|
||||
$cls->test();
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Warning: The return value of method Clazz::test() should either be used or intentionally ignored by casting it as (void) in %s on line %d
|
17
Zend/tests/attributes/nodiscard/005.phpt
Normal file
17
Zend/tests/attributes/nodiscard/005.phpt
Normal file
|
@ -0,0 +1,17 @@
|
|||
--TEST--
|
||||
#[\NoDiscard]: Native function and method.
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$f = tmpfile();
|
||||
flock($f, LOCK_SH | LOCK_NB);
|
||||
fclose($f);
|
||||
|
||||
$date = new DateTimeImmutable('now');
|
||||
$date->setTimestamp(0);
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Warning: The return value of function flock() should either be used or intentionally ignored by casting it as (void), as locking the stream might have failed in %s on line %d
|
||||
|
||||
Warning: The return value of method DateTimeImmutable::setTimestamp() should either be used or intentionally ignored by casting it as (void), as DateTimeImmutable::setTimestamp() does not modify the object itself in %s on line %d
|
20
Zend/tests/attributes/nodiscard/006.phpt
Normal file
20
Zend/tests/attributes/nodiscard/006.phpt
Normal file
|
@ -0,0 +1,20 @@
|
|||
--TEST--
|
||||
#[\NoDiscard]: execute_ex overwritten
|
||||
--EXTENSIONS--
|
||||
zend_test
|
||||
--INI--
|
||||
zend_test.replace_zend_execute_ex=1
|
||||
opcache.jit=disable
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
#[\NoDiscard]
|
||||
function test(): int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
test();
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Warning: The return value of function test() should either be used or intentionally ignored by casting it as (void) in %s on line %d
|
21
Zend/tests/attributes/nodiscard/007.phpt
Normal file
21
Zend/tests/attributes/nodiscard/007.phpt
Normal file
|
@ -0,0 +1,21 @@
|
|||
--TEST--
|
||||
#[\NoDiscard]: execute_internal overwritten
|
||||
--EXTENSIONS--
|
||||
zend_test
|
||||
--INI--
|
||||
zend_test.observer.execute_internal=1
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$f = tmpfile();
|
||||
flock($f, LOCK_SH | LOCK_NB);
|
||||
fclose($f);
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
<!-- internal enter tmpfile() -->
|
||||
<!-- internal enter NoDiscard::__construct() -->
|
||||
|
||||
Warning: The return value of function flock() should either be used or intentionally ignored by casting it as (void), as locking the stream might have failed in %s on line %d
|
||||
<!-- internal enter flock() -->
|
||||
<!-- internal enter fclose() -->
|
18
Zend/tests/attributes/nodiscard/008.phpt
Normal file
18
Zend/tests/attributes/nodiscard/008.phpt
Normal file
|
@ -0,0 +1,18 @@
|
|||
--TEST--
|
||||
#[\NoDiscard]: Combining with #[\Deprecated].
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
#[\NoDiscard]
|
||||
#[\Deprecated]
|
||||
function test(): int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
test();
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Deprecated: Function test() is deprecated in %s on line %d
|
||||
|
||||
Warning: The return value of function test() should either be used or intentionally ignored by casting it as (void) in %s on line %d
|
14
Zend/tests/attributes/nodiscard/009.phpt
Normal file
14
Zend/tests/attributes/nodiscard/009.phpt
Normal file
|
@ -0,0 +1,14 @@
|
|||
--TEST--
|
||||
#[\NoDiscard]: Combining with #[\Deprecated] (Internal).
|
||||
--EXTENSIONS--
|
||||
zend_test
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
zend_test_deprecated_nodiscard();
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Deprecated: Function zend_test_deprecated_nodiscard() is deprecated, custom message in %s on line %d
|
||||
|
||||
Warning: The return value of function zend_test_deprecated_nodiscard() should either be used or intentionally ignored by casting it as (void), custom message 2 in %s on line %d
|
76
Zend/tests/attributes/nodiscard/010.phpt
Normal file
76
Zend/tests/attributes/nodiscard/010.phpt
Normal file
|
@ -0,0 +1,76 @@
|
|||
--TEST--
|
||||
#[\NoDiscard]: Functions with known-used result use DO_[IU]CALL opcodes
|
||||
--INI--
|
||||
opcache.enable=1
|
||||
opcache.enable_cli=1
|
||||
opcache.optimization_level=-1
|
||||
opcache.opt_debug_level=0x20000
|
||||
--EXTENSIONS--
|
||||
opcache
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$f = tmpfile();
|
||||
flock($f, LOCK_SH | LOCK_NB);
|
||||
(void)flock($f, LOCK_SH | LOCK_NB);
|
||||
$success = flock($f, LOCK_SH | LOCK_NB);
|
||||
fclose($f);
|
||||
|
||||
#[\NoDiscard]
|
||||
function test() {
|
||||
return new stdClass();
|
||||
}
|
||||
|
||||
test();
|
||||
(void)test();
|
||||
$obj = test();
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
$_main:
|
||||
; (lines=29, args=0, vars=3, tmps=1)
|
||||
; (after optimizer)
|
||||
; %s
|
||||
0000 INIT_FCALL 0 %d string("tmpfile")
|
||||
0001 V3 = DO_ICALL
|
||||
0002 ASSIGN CV0($f) V3
|
||||
0003 INIT_FCALL 2 %d string("flock")
|
||||
0004 SEND_VAR CV0($f) 1
|
||||
0005 SEND_VAL int(5) 2
|
||||
0006 DO_FCALL_BY_NAME
|
||||
0007 INIT_FCALL 2 %d string("flock")
|
||||
0008 SEND_VAR CV0($f) 1
|
||||
0009 SEND_VAL int(5) 2
|
||||
0010 V3 = DO_ICALL
|
||||
0011 FREE V3
|
||||
0012 INIT_FCALL 2 %d string("flock")
|
||||
0013 SEND_VAR CV0($f) 1
|
||||
0014 SEND_VAL int(5) 2
|
||||
0015 V3 = DO_ICALL
|
||||
0016 ASSIGN CV1($success) V3
|
||||
0017 INIT_FCALL 1 %d string("fclose")
|
||||
0018 SEND_VAR CV0($f) 1
|
||||
0019 DO_ICALL
|
||||
0020 INIT_FCALL 0 %d string("test")
|
||||
0021 DO_FCALL_BY_NAME
|
||||
0022 INIT_FCALL 0 %d string("test")
|
||||
0023 V3 = DO_UCALL
|
||||
0024 FREE V3
|
||||
0025 INIT_FCALL 0 %d string("test")
|
||||
0026 V3 = DO_UCALL
|
||||
0027 ASSIGN CV2($obj) V3
|
||||
0028 RETURN int(1)
|
||||
|
||||
test:
|
||||
; (lines=3, args=0, vars=0, tmps=1)
|
||||
; (after optimizer)
|
||||
; %s
|
||||
0000 V0 = NEW 0 string("stdClass")
|
||||
0001 DO_FCALL
|
||||
0002 RETURN V0
|
||||
LIVE RANGES:
|
||||
0: 0001 - 0002 (new)
|
||||
|
||||
Warning: The return value of function flock() should either be used or intentionally ignored by casting it as (void), as locking the stream might have failed in %s on line %d
|
||||
|
||||
Warning: The return value of function test() should either be used or intentionally ignored by casting it as (void) in %s on line %d
|
21
Zend/tests/attributes/nodiscard/error_code_001.phpt
Normal file
21
Zend/tests/attributes/nodiscard/error_code_001.phpt
Normal file
|
@ -0,0 +1,21 @@
|
|||
--TEST--
|
||||
#[\NoDiscard]: Code is E_USER_WARNING.
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
set_error_handler(function (int $errno, string $errstr, ?string $errfile = null, ?int $errline = null) {
|
||||
var_dump($errno, E_USER_WARNING, $errno === E_USER_WARNING);
|
||||
});
|
||||
|
||||
#[\NoDiscard]
|
||||
function test(): int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
test();
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
int(512)
|
||||
int(512)
|
||||
bool(true)
|
14
Zend/tests/attributes/nodiscard/property_readonly_001.phpt
Normal file
14
Zend/tests/attributes/nodiscard/property_readonly_001.phpt
Normal file
|
@ -0,0 +1,14 @@
|
|||
--TEST--
|
||||
#[\NoDiscard]: NoDiscard::$message is readonly.
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$d = new \NoDiscard("foo");
|
||||
$d->message = 'bar';
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Uncaught Error: Cannot modify readonly property NoDiscard::$message in %s:%d
|
||||
Stack trace:
|
||||
#0 {main}
|
||||
thrown in %s on line %d
|
15
Zend/tests/attributes/nodiscard/property_readonly_002.phpt
Normal file
15
Zend/tests/attributes/nodiscard/property_readonly_002.phpt
Normal file
|
@ -0,0 +1,15 @@
|
|||
--TEST--
|
||||
#[\NoDiscard]: __construct() respects that properties are readonly.
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$d = new \NoDiscard("foo");
|
||||
$d->__construct("bar");
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Uncaught Error: Cannot modify readonly property NoDiscard::$message in %s:%d
|
||||
Stack trace:
|
||||
#0 %s(%d): NoDiscard->__construct('bar')
|
||||
#1 {main}
|
||||
thrown in %s on line %d
|
66
Zend/tests/attributes/nodiscard/suppress_assign.phpt
Normal file
66
Zend/tests/attributes/nodiscard/suppress_assign.phpt
Normal file
|
@ -0,0 +1,66 @@
|
|||
--TEST--
|
||||
#[\NoDiscard]: Assigning to variable suppresses.
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
#[\NoDiscard]
|
||||
function test(): int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#[\NoDiscard("this is important")]
|
||||
function test2(): int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#[\NoDiscard]
|
||||
function test3(...$args): int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
class Clazz {
|
||||
#[\NoDiscard]
|
||||
function test(): int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#[\NoDiscard("this is important")]
|
||||
function test2(): int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#[\NoDiscard]
|
||||
static function test3(): int {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
$closure = #[\NoDiscard] function(): int {
|
||||
return 0;
|
||||
};
|
||||
|
||||
$closure2 = #[\NoDiscard] function(): int {
|
||||
return 0;
|
||||
};
|
||||
|
||||
$_ = test();
|
||||
$_ = test2();
|
||||
$_ = test3(1, 2, named: 3);
|
||||
$_ = call_user_func("test");
|
||||
$fcc = test(...);
|
||||
$_ = $fcc();
|
||||
|
||||
$cls = new Clazz();
|
||||
$_ = $cls->test();
|
||||
$_ = $cls->test2();
|
||||
$_ = call_user_func([$cls, "test"]);
|
||||
$_ = Clazz::test3();
|
||||
|
||||
$_ = $closure();
|
||||
|
||||
$_ = $closure2();
|
||||
|
||||
?>
|
||||
DONE
|
||||
--EXPECT--
|
||||
DONE
|
66
Zend/tests/attributes/nodiscard/suppress_cast.phpt
Normal file
66
Zend/tests/attributes/nodiscard/suppress_cast.phpt
Normal file
|
@ -0,0 +1,66 @@
|
|||
--TEST--
|
||||
#[\NoDiscard]: Casting to (void) suppresses.
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
#[\NoDiscard]
|
||||
function test(): int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#[\NoDiscard("this is important")]
|
||||
function test2(): int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#[\NoDiscard]
|
||||
function test3(...$args): int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
class Clazz {
|
||||
#[\NoDiscard]
|
||||
function test(): int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#[\NoDiscard("this is important")]
|
||||
function test2(): int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#[\NoDiscard]
|
||||
static function test3(): int {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
$closure = #[\NoDiscard] function(): int {
|
||||
return 0;
|
||||
};
|
||||
|
||||
$closure2 = #[\NoDiscard] function(): int {
|
||||
return 0;
|
||||
};
|
||||
|
||||
(void)test();
|
||||
(void)test2();
|
||||
(void)test3(1, 2, named: 3);
|
||||
(void)call_user_func("test");
|
||||
$fcc = test(...);
|
||||
(void)$fcc();
|
||||
|
||||
$cls = new Clazz();
|
||||
(void)$cls->test();
|
||||
(void)$cls->test2();
|
||||
(void)call_user_func([$cls, "test"]);
|
||||
(void)Clazz::test3();
|
||||
|
||||
(void)$closure();
|
||||
|
||||
(void)$closure2();
|
||||
|
||||
?>
|
||||
DONE
|
||||
--EXPECT--
|
||||
DONE
|
|
@ -0,0 +1,35 @@
|
|||
--TEST--
|
||||
#[\NoDiscard]: Throwing error handler.
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
set_error_handler(function (int $errno, string $errstr, ?string $errfile = null, ?int $errline = null) {
|
||||
throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
|
||||
});
|
||||
|
||||
#[\NoDiscard]
|
||||
function test(): int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
try {
|
||||
test();
|
||||
} catch (ErrorException $e) {
|
||||
echo "Caught: ", $e->getMessage(), PHP_EOL;
|
||||
}
|
||||
|
||||
#[\NoDiscard]
|
||||
function test2(): stdClass {
|
||||
return new stdClass();
|
||||
}
|
||||
|
||||
try {
|
||||
test2();
|
||||
} catch (ErrorException $e) {
|
||||
echo "Caught: ", $e->getMessage(), PHP_EOL;
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Caught: The return value of function test() should either be used or intentionally ignored by casting it as (void)
|
||||
Caught: The return value of function test2() should either be used or intentionally ignored by casting it as (void)
|
15
Zend/tests/attributes/nodiscard/type_validation_001.phpt
Normal file
15
Zend/tests/attributes/nodiscard/type_validation_001.phpt
Normal file
|
@ -0,0 +1,15 @@
|
|||
--TEST--
|
||||
#[\NoDiscard]: Type validation of $message parameter with int.
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
#[\NoDiscard(1234)]
|
||||
function test(): int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
test();
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Warning: The return value of function test() should either be used or intentionally ignored by casting it as (void), 1234 in %s on line %d
|
20
Zend/tests/attributes/nodiscard/type_validation_002.phpt
Normal file
20
Zend/tests/attributes/nodiscard/type_validation_002.phpt
Normal file
|
@ -0,0 +1,20 @@
|
|||
--TEST--
|
||||
#[\NoDiscard]: Type validation of $message parameter with int and strict types.
|
||||
--FILE--
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
#[\NoDiscard(1234)]
|
||||
function test(): int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
test();
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Uncaught TypeError: NoDiscard::__construct(): Argument #1 ($message) must be of type ?string, int given in %s:%d
|
||||
Stack trace:
|
||||
#0 %s(%d): NoDiscard->__construct(1234)
|
||||
#1 {main}
|
||||
thrown in %s on line %d
|
18
Zend/tests/attributes/nodiscard/type_validation_003.phpt
Normal file
18
Zend/tests/attributes/nodiscard/type_validation_003.phpt
Normal file
|
@ -0,0 +1,18 @@
|
|||
--TEST--
|
||||
#[\NoDiscard]: Type validation of $message parameter with array.
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
#[\NoDiscard([])]
|
||||
function test(): int {
|
||||
return 0;
|
||||
}
|
||||
test();
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Uncaught TypeError: NoDiscard::__construct(): Argument #1 ($message) must be of type ?string, array given in %s:%d
|
||||
Stack trace:
|
||||
#0 %s(%d): NoDiscard->__construct(Array)
|
||||
#1 {main}
|
||||
thrown in %s on line %d
|
18
Zend/tests/attributes/nodiscard/type_validation_004.phpt
Normal file
18
Zend/tests/attributes/nodiscard/type_validation_004.phpt
Normal file
|
@ -0,0 +1,18 @@
|
|||
--TEST--
|
||||
#[\NoDiscard]: Type validation of $message parameter with native enum case.
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
#[\NoDiscard(\Random\IntervalBoundary::ClosedOpen)]
|
||||
function test(): int {
|
||||
return 0;
|
||||
}
|
||||
test();
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Uncaught TypeError: NoDiscard::__construct(): Argument #1 ($message) must be of type ?string, Random\IntervalBoundary given in %s:%d
|
||||
Stack trace:
|
||||
#0 %s(%d): NoDiscard->__construct(Random\IntervalBoundary::ClosedOpen)
|
||||
#1 {main}
|
||||
thrown in %s on line %d
|
16
Zend/tests/attributes/nodiscard/unsupported_clone.phpt
Normal file
16
Zend/tests/attributes/nodiscard/unsupported_clone.phpt
Normal file
|
@ -0,0 +1,16 @@
|
|||
--TEST--
|
||||
#[\NoDiscard]: Not allowed on '__clone'.
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class Clazz {
|
||||
#[\NoDiscard]
|
||||
public function __clone() {
|
||||
}
|
||||
}
|
||||
|
||||
$cls = new Clazz();
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Method Clazz::__clone cannot be #[\NoDiscard] in %s on line %d
|
16
Zend/tests/attributes/nodiscard/unsupported_constructor.phpt
Normal file
16
Zend/tests/attributes/nodiscard/unsupported_constructor.phpt
Normal file
|
@ -0,0 +1,16 @@
|
|||
--TEST--
|
||||
#[\NoDiscard]: Not allowed on '__construct'.
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class Clazz {
|
||||
#[\NoDiscard]
|
||||
public function __construct() {
|
||||
}
|
||||
}
|
||||
|
||||
$cls = new Clazz();
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Method Clazz::__construct cannot be #[\NoDiscard] in %s on line %d
|
|
@ -0,0 +1,15 @@
|
|||
--TEST--
|
||||
#[\NoDiscard]: Not allowed on never function.
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
#[\NoDiscard]
|
||||
function test(): never {
|
||||
throw new \Exception('Error!');
|
||||
}
|
||||
|
||||
test();
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: A never returning function does not return a value, but #[\NoDiscard] requires a return value in %s on line %d
|
|
@ -0,0 +1,20 @@
|
|||
--TEST--
|
||||
#[\NoDiscard]: Not allowed on 'get' property hook.
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class Clazz {
|
||||
public string $test {
|
||||
#[\NoDiscard]
|
||||
get {
|
||||
return 'asd';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$cls = new Clazz();
|
||||
$cls->test;
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: #[\NoDiscard] is not supported for property hooks in %s on line %d
|
|
@ -0,0 +1,20 @@
|
|||
--TEST--
|
||||
#[\NoDiscard]: Not allowed on 'set' property hook.
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class Clazz {
|
||||
public string $test {
|
||||
#[\NoDiscard]
|
||||
set(string $value) {
|
||||
$this->test = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$cls = new Foo();
|
||||
$cls->test = 'foo';
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: #[\NoDiscard] is not supported for property hooks in %s on line %d
|
|
@ -0,0 +1,15 @@
|
|||
--TEST--
|
||||
#[\NoDiscard]: Not allowed on void function.
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
#[\NoDiscard]
|
||||
function test(): void {
|
||||
return;
|
||||
}
|
||||
|
||||
test();
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: A void function does not return a value, but #[\NoDiscard] requires a return value in %s on line %d
|
|
@ -2698,6 +2698,12 @@ static void zend_check_magic_method_arg_type(uint32_t arg_num, const zend_class_
|
|||
|
||||
static void zend_check_magic_method_return_type(const zend_class_entry *ce, const zend_function *fptr, int error_type, int return_type)
|
||||
{
|
||||
if (return_type == MAY_BE_VOID) {
|
||||
if (fptr->common.fn_flags & ZEND_ACC_NODISCARD) {
|
||||
zend_error_noreturn(error_type, "Method %s::%s cannot be #[\\NoDiscard]", ZSTR_VAL(ce->name), ZSTR_VAL(fptr->common.function_name));
|
||||
}
|
||||
}
|
||||
|
||||
if (!(fptr->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) {
|
||||
/* For backwards compatibility reasons, do not enforce the return type if it is not set. */
|
||||
return;
|
||||
|
@ -2757,6 +2763,10 @@ static void zend_check_magic_method_no_return_type(
|
|||
zend_error_noreturn(error_type, "Method %s::%s() cannot declare a return type",
|
||||
ZSTR_VAL(ce->name), ZSTR_VAL(fptr->common.function_name));
|
||||
}
|
||||
|
||||
if (fptr->common.fn_flags & ZEND_ACC_NODISCARD) {
|
||||
zend_error_noreturn(error_type, "Method %s::%s cannot be #[\\NoDiscard]", ZSTR_VAL(ce->name), ZSTR_VAL(fptr->common.function_name));
|
||||
}
|
||||
}
|
||||
|
||||
ZEND_API void zend_check_magic_method_implementation(const zend_class_entry *ce, const zend_function *fptr, zend_string *lcname, int error_type) /* {{{ */
|
||||
|
|
|
@ -31,6 +31,7 @@ ZEND_API zend_class_entry *zend_ce_sensitive_parameter;
|
|||
ZEND_API zend_class_entry *zend_ce_sensitive_parameter_value;
|
||||
ZEND_API zend_class_entry *zend_ce_override;
|
||||
ZEND_API zend_class_entry *zend_ce_deprecated;
|
||||
ZEND_API zend_class_entry *zend_ce_nodiscard;
|
||||
|
||||
static zend_object_handlers attributes_object_handlers_sensitive_parameter_value;
|
||||
|
||||
|
@ -193,6 +194,29 @@ ZEND_METHOD(Deprecated, __construct)
|
|||
}
|
||||
}
|
||||
|
||||
ZEND_METHOD(NoDiscard, __construct)
|
||||
{
|
||||
zend_string *message = NULL;
|
||||
zval value;
|
||||
|
||||
ZEND_PARSE_PARAMETERS_START(0, 1)
|
||||
Z_PARAM_OPTIONAL
|
||||
Z_PARAM_STR_OR_NULL(message)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
|
||||
if (message) {
|
||||
ZVAL_STR(&value, message);
|
||||
} else {
|
||||
ZVAL_NULL(&value);
|
||||
}
|
||||
zend_update_property_ex(zend_ce_nodiscard, Z_OBJ_P(ZEND_THIS), ZSTR_KNOWN(ZEND_STR_MESSAGE), &value);
|
||||
|
||||
/* The assignment might fail due to 'readonly'. */
|
||||
if (UNEXPECTED(EG(exception))) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
}
|
||||
|
||||
static zend_attribute *get_attribute(HashTable *attributes, zend_string *lcname, uint32_t offset)
|
||||
{
|
||||
if (attributes) {
|
||||
|
@ -520,6 +544,9 @@ void zend_register_attribute_ce(void)
|
|||
|
||||
zend_ce_deprecated = register_class_Deprecated();
|
||||
attr = zend_mark_internal_attribute(zend_ce_deprecated);
|
||||
|
||||
zend_ce_nodiscard = register_class_NoDiscard();
|
||||
attr = zend_mark_internal_attribute(zend_ce_nodiscard);
|
||||
}
|
||||
|
||||
void zend_attributes_shutdown(void)
|
||||
|
|
|
@ -47,6 +47,7 @@ extern ZEND_API zend_class_entry *zend_ce_sensitive_parameter;
|
|||
extern ZEND_API zend_class_entry *zend_ce_sensitive_parameter_value;
|
||||
extern ZEND_API zend_class_entry *zend_ce_override;
|
||||
extern ZEND_API zend_class_entry *zend_ce_deprecated;
|
||||
extern ZEND_API zend_class_entry *zend_ce_nodiscard;
|
||||
|
||||
typedef struct {
|
||||
zend_string *name;
|
||||
|
|
|
@ -84,3 +84,14 @@ final class Deprecated
|
|||
|
||||
public function __construct(?string $message = null, ?string $since = null) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* @strict-properties
|
||||
*/
|
||||
#[Attribute(Attribute::TARGET_METHOD|Attribute::TARGET_FUNCTION)]
|
||||
final class NoDiscard
|
||||
{
|
||||
public readonly ?string $message;
|
||||
|
||||
public function __construct(?string $message = null) {}
|
||||
}
|
||||
|
|
33
Zend/zend_attributes_arginfo.h
generated
33
Zend/zend_attributes_arginfo.h
generated
|
@ -1,5 +1,5 @@
|
|||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: 2358a0d820edd06a1702c84104bfd545af08311c */
|
||||
* Stub hash: 6b54bc195be211caabb395b621380681953c1f5a */
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Attribute___construct, 0, 0, 0)
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "Attribute::TARGET_ALL")
|
||||
|
@ -29,6 +29,10 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Deprecated___construct, 0, 0, 0)
|
|||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, since, IS_STRING, 1, "null")
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_NoDiscard___construct, 0, 0, 0)
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, message, IS_STRING, 1, "null")
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_METHOD(Attribute, __construct);
|
||||
ZEND_METHOD(ReturnTypeWillChange, __construct);
|
||||
ZEND_METHOD(AllowDynamicProperties, __construct);
|
||||
|
@ -38,6 +42,7 @@ ZEND_METHOD(SensitiveParameterValue, getValue);
|
|||
ZEND_METHOD(SensitiveParameterValue, __debugInfo);
|
||||
ZEND_METHOD(Override, __construct);
|
||||
ZEND_METHOD(Deprecated, __construct);
|
||||
ZEND_METHOD(NoDiscard, __construct);
|
||||
|
||||
static const zend_function_entry class_Attribute_methods[] = {
|
||||
ZEND_ME(Attribute, __construct, arginfo_class_Attribute___construct, ZEND_ACC_PUBLIC)
|
||||
|
@ -76,6 +81,11 @@ static const zend_function_entry class_Deprecated_methods[] = {
|
|||
ZEND_FE_END
|
||||
};
|
||||
|
||||
static const zend_function_entry class_NoDiscard_methods[] = {
|
||||
ZEND_ME(NoDiscard, __construct, arginfo_class_NoDiscard___construct, ZEND_ACC_PUBLIC)
|
||||
ZEND_FE_END
|
||||
};
|
||||
|
||||
static zend_class_entry *register_class_Attribute(void)
|
||||
{
|
||||
zend_class_entry ce, *class_entry;
|
||||
|
@ -253,3 +263,24 @@ static zend_class_entry *register_class_Deprecated(void)
|
|||
|
||||
return class_entry;
|
||||
}
|
||||
|
||||
static zend_class_entry *register_class_NoDiscard(void)
|
||||
{
|
||||
zend_class_entry ce, *class_entry;
|
||||
|
||||
INIT_CLASS_ENTRY(ce, "NoDiscard", class_NoDiscard_methods);
|
||||
class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES);
|
||||
|
||||
zval property_message_default_value;
|
||||
ZVAL_UNDEF(&property_message_default_value);
|
||||
zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_MESSAGE), &property_message_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL));
|
||||
|
||||
zend_string *attribute_name_Attribute_class_NoDiscard_0 = zend_string_init_interned("Attribute", sizeof("Attribute") - 1, 1);
|
||||
zend_attribute *attribute_Attribute_class_NoDiscard_0 = zend_add_class_attribute(class_entry, attribute_name_Attribute_class_NoDiscard_0, 1);
|
||||
zend_string_release(attribute_name_Attribute_class_NoDiscard_0);
|
||||
zval attribute_Attribute_class_NoDiscard_0_arg0;
|
||||
ZVAL_LONG(&attribute_Attribute_class_NoDiscard_0_arg0, ZEND_ATTRIBUTE_TARGET_METHOD | ZEND_ATTRIBUTE_TARGET_FUNCTION);
|
||||
ZVAL_COPY_VALUE(&attribute_Attribute_class_NoDiscard_0->args[0].value, &attribute_Attribute_class_NoDiscard_0_arg0);
|
||||
|
||||
return class_entry;
|
||||
}
|
||||
|
|
|
@ -3927,13 +3927,15 @@ static uint32_t zend_compile_args(
|
|||
}
|
||||
/* }}} */
|
||||
|
||||
ZEND_API uint8_t zend_get_call_op(const zend_op *init_op, zend_function *fbc) /* {{{ */
|
||||
ZEND_API uint8_t zend_get_call_op(const zend_op *init_op, zend_function *fbc, bool result_used) /* {{{ */
|
||||
{
|
||||
if (fbc) {
|
||||
uint32_t no_discard = result_used ? 0 : ZEND_ACC_NODISCARD;
|
||||
|
||||
if (fbc && init_op->opcode != ZEND_NEW) {
|
||||
ZEND_ASSERT(!(fbc->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE));
|
||||
if (fbc->type == ZEND_INTERNAL_FUNCTION && !(CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS)) {
|
||||
if (init_op->opcode == ZEND_INIT_FCALL && !zend_execute_internal) {
|
||||
if (!(fbc->common.fn_flags & ZEND_ACC_DEPRECATED)) {
|
||||
if (!(fbc->common.fn_flags & (ZEND_ACC_DEPRECATED|no_discard))) {
|
||||
return ZEND_DO_ICALL;
|
||||
} else {
|
||||
return ZEND_DO_FCALL_BY_NAME;
|
||||
|
@ -3941,7 +3943,7 @@ ZEND_API uint8_t zend_get_call_op(const zend_op *init_op, zend_function *fbc) /*
|
|||
}
|
||||
} else if (!(CG(compiler_options) & ZEND_COMPILE_IGNORE_USER_FUNCTIONS)){
|
||||
if (zend_execute_ex == execute_ex) {
|
||||
if (!(fbc->common.fn_flags & ZEND_ACC_DEPRECATED)) {
|
||||
if (!(fbc->common.fn_flags & (ZEND_ACC_DEPRECATED|no_discard))) {
|
||||
return ZEND_DO_UCALL;
|
||||
} else {
|
||||
return ZEND_DO_FCALL_BY_NAME;
|
||||
|
@ -3991,7 +3993,16 @@ static bool zend_compile_call_common(znode *result, zend_ast *args_ast, zend_fun
|
|||
opline->op1.num = zend_vm_calc_used_stack(arg_count, fbc);
|
||||
}
|
||||
|
||||
opline = zend_emit_op(result, zend_get_call_op(opline, fbc), NULL, NULL);
|
||||
uint8_t call_op = zend_get_call_op(
|
||||
opline,
|
||||
fbc,
|
||||
/* result_used: At this point we do not yet reliably
|
||||
* know if the result is used. Deoptimize #[\NoDiscard]
|
||||
* calls to be sure. The optimizer will fix this up.
|
||||
*/
|
||||
false
|
||||
);
|
||||
opline = zend_emit_op(result, call_op, NULL, NULL);
|
||||
if (may_have_extra_named_args) {
|
||||
opline->extended_value = ZEND_FCALL_MAY_HAVE_EXTRA_NAMED_PARAMS;
|
||||
}
|
||||
|
@ -8353,6 +8364,16 @@ static zend_op_array *zend_compile_func_decl_ex(
|
|||
if (deprecated_attribute) {
|
||||
op_array->fn_flags |= ZEND_ACC_DEPRECATED;
|
||||
}
|
||||
|
||||
zend_attribute *nodiscard_attribute = zend_get_attribute_str(
|
||||
op_array->attributes,
|
||||
"nodiscard",
|
||||
sizeof("nodiscard")-1
|
||||
);
|
||||
|
||||
if (nodiscard_attribute) {
|
||||
op_array->fn_flags |= ZEND_ACC_NODISCARD;
|
||||
}
|
||||
}
|
||||
|
||||
/* Do not leak the class scope into free standing functions, even if they are dynamically
|
||||
|
@ -8403,6 +8424,27 @@ static zend_op_array *zend_compile_func_decl_ex(
|
|||
}
|
||||
}
|
||||
|
||||
if (op_array->fn_flags & ZEND_ACC_NODISCARD) {
|
||||
if (is_hook) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "#[\\NoDiscard] is not supported for property hooks");
|
||||
}
|
||||
|
||||
if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
|
||||
zend_arg_info *return_info = CG(active_op_array)->arg_info - 1;
|
||||
if (ZEND_TYPE_CONTAINS_CODE(return_info->type, IS_VOID)) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR,
|
||||
"A void %s does not return a value, but #[\\NoDiscard] requires a return value",
|
||||
CG(active_class_entry) != NULL ? "method" : "function");
|
||||
}
|
||||
|
||||
if (ZEND_TYPE_CONTAINS_CODE(return_info->type, IS_NEVER)) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR,
|
||||
"A never returning %s does not return a value, but #[\\NoDiscard] requires a return value",
|
||||
CG(active_class_entry) != NULL ? "method" : "function");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
zend_compile_stmt(stmt_ast);
|
||||
|
||||
if (is_method) {
|
||||
|
|
|
@ -333,7 +333,7 @@ typedef struct _zend_oparray_context {
|
|||
/* Class cannot be serialized or unserialized | | | */
|
||||
#define ZEND_ACC_NOT_SERIALIZABLE (1 << 29) /* X | | | */
|
||||
/* | | | */
|
||||
/* Function Flags (unused: 29-30) | | | */
|
||||
/* Function Flags (unused: 30) | | | */
|
||||
/* ============== | | | */
|
||||
/* | | | */
|
||||
/* deprecation flag | | | */
|
||||
|
@ -395,6 +395,9 @@ typedef struct _zend_oparray_context {
|
|||
/* has #[\Override] attribute | | | */
|
||||
#define ZEND_ACC_OVERRIDE (1 << 28) /* | X | | */
|
||||
/* | | | */
|
||||
/* has #[\NoDiscard] attribute | | | */
|
||||
#define ZEND_ACC_NODISCARD (1 << 29) /* | X | | */
|
||||
/* | | | */
|
||||
/* op_array uses strict mode types | | | */
|
||||
#define ZEND_ACC_STRICT_TYPES (1U << 31) /* | X | | */
|
||||
|
||||
|
@ -981,7 +984,7 @@ ZEND_API bool zend_is_compiling(void);
|
|||
ZEND_API char *zend_make_compiled_string_description(const char *name);
|
||||
ZEND_API void zend_initialize_class_data(zend_class_entry *ce, bool nullify_handlers);
|
||||
uint32_t zend_get_class_fetch_type(const zend_string *name);
|
||||
ZEND_API uint8_t zend_get_call_op(const zend_op *init_op, zend_function *fbc);
|
||||
ZEND_API uint8_t zend_get_call_op(const zend_op *init_op, zend_function *fbc, bool result_used);
|
||||
ZEND_API bool zend_is_smart_branch(const zend_op *opline);
|
||||
|
||||
typedef bool (*zend_auto_global_callback)(zend_string *name);
|
||||
|
|
|
@ -1907,6 +1907,87 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_deprecated_function(const zend_functi
|
|||
zend_string_release(message_suffix);
|
||||
}
|
||||
|
||||
ZEND_COLD static zend_result ZEND_FASTCALL get_nodiscard_suffix_from_attribute(HashTable *attributes, zend_class_entry* scope, zend_string **message_suffix)
|
||||
{
|
||||
*message_suffix = ZSTR_EMPTY_ALLOC();
|
||||
|
||||
if (!attributes) {
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
zend_attribute *nodiscard = zend_get_attribute_str(attributes, "nodiscard", sizeof("nodiscard")-1);
|
||||
|
||||
if (!nodiscard) {
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
if (nodiscard->argc == 0) {
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
zend_result result = FAILURE;
|
||||
|
||||
zend_string *message = ZSTR_EMPTY_ALLOC();
|
||||
|
||||
zval obj;
|
||||
ZVAL_UNDEF(&obj);
|
||||
zval *z;
|
||||
|
||||
/* Construct the NoDiscard object to correctly handle parameter processing. */
|
||||
if (FAILURE == zend_get_attribute_object(&obj, zend_ce_nodiscard, nodiscard, scope, NULL)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Extract the $message property. */
|
||||
z = zend_read_property_ex(zend_ce_nodiscard, Z_OBJ_P(&obj), ZSTR_KNOWN(ZEND_STR_MESSAGE), false, NULL);
|
||||
ZEND_ASSERT(z != &EG(uninitialized_zval));
|
||||
if (Z_TYPE_P(z) == IS_STRING) {
|
||||
message = Z_STR_P(z);
|
||||
}
|
||||
|
||||
/* Construct the suffix. */
|
||||
*message_suffix = zend_strpprintf_unchecked(
|
||||
0,
|
||||
"%s%S",
|
||||
ZSTR_LEN(message) > 0 ? ", " : "",
|
||||
message
|
||||
);
|
||||
|
||||
result = SUCCESS;
|
||||
|
||||
out:
|
||||
|
||||
zval_ptr_dtor(&obj);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_nodiscard_function(const zend_function *fbc)
|
||||
{
|
||||
zend_string *message_suffix = ZSTR_EMPTY_ALLOC();
|
||||
|
||||
if (get_nodiscard_suffix_from_attribute(fbc->common.attributes, fbc->common.scope, &message_suffix) == FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
int code = fbc->type == ZEND_INTERNAL_FUNCTION ? E_WARNING : E_USER_WARNING;
|
||||
|
||||
if (fbc->common.scope) {
|
||||
zend_error_unchecked(code, "The return value of method %s::%s() should either be used or intentionally ignored by casting it as (void)%S",
|
||||
ZSTR_VAL(fbc->common.scope->name),
|
||||
ZSTR_VAL(fbc->common.function_name),
|
||||
message_suffix
|
||||
);
|
||||
} else {
|
||||
zend_error_unchecked(code, "The return value of function %s() should either be used or intentionally ignored by casting it as (void)%S",
|
||||
ZSTR_VAL(fbc->common.function_name),
|
||||
message_suffix
|
||||
);
|
||||
}
|
||||
|
||||
zend_string_release(message_suffix);
|
||||
}
|
||||
|
||||
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_deprecated_class_constant(const zend_class_constant *c, const zend_string *constant_name)
|
||||
{
|
||||
zend_string *message_suffix = ZSTR_EMPTY_ALLOC();
|
||||
|
|
|
@ -62,6 +62,7 @@ extern ZEND_API const zend_internal_function zend_pass_function;
|
|||
|
||||
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_missing_arg_error(zend_execute_data *execute_data);
|
||||
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_deprecated_function(const zend_function *fbc);
|
||||
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_nodiscard_function(const zend_function *fbc);
|
||||
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_deprecated_class_constant(const zend_class_constant *c, const zend_string *constant_name);
|
||||
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_false_to_array_deprecated(void);
|
||||
ZEND_COLD void ZEND_FASTCALL zend_param_must_be_ref(const zend_function *func, uint32_t arg_num);
|
||||
|
|
|
@ -1679,7 +1679,7 @@ ZEND_API zend_function *zend_get_call_trampoline_func(const zend_class_entry *ce
|
|||
func->fn_flags = ZEND_ACC_CALL_VIA_TRAMPOLINE
|
||||
| ZEND_ACC_PUBLIC
|
||||
| ZEND_ACC_VARIADIC
|
||||
| (fbc->common.fn_flags & (ZEND_ACC_RETURN_REFERENCE|ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED));
|
||||
| (fbc->common.fn_flags & (ZEND_ACC_RETURN_REFERENCE|ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED|ZEND_ACC_NODISCARD));
|
||||
/* Attributes outlive the trampoline because they are created by the compiler. */
|
||||
func->attributes = fbc->common.attributes;
|
||||
if (is_static) {
|
||||
|
|
|
@ -4156,8 +4156,15 @@ ZEND_VM_HOT_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY, SPEC(RETVAL,OBSERVER))
|
|||
SAVE_OPLINE();
|
||||
EX(call) = call->prev_execute_data;
|
||||
|
||||
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
|
||||
zend_deprecated_function(fbc);
|
||||
const uint32_t no_discard = RETURN_VALUE_USED(opline) ? 0 : ZEND_ACC_NODISCARD;
|
||||
|
||||
if (UNEXPECTED(fbc->common.fn_flags & (ZEND_ACC_DEPRECATED|no_discard))) {
|
||||
if (fbc->common.fn_flags & ZEND_ACC_DEPRECATED) {
|
||||
zend_deprecated_function(fbc);
|
||||
}
|
||||
if ((fbc->common.fn_flags & no_discard) && EG(exception) == NULL) {
|
||||
zend_nodiscard_function(fbc);
|
||||
}
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
UNDEF_RESULT();
|
||||
if (!RETURN_VALUE_USED(opline)) {
|
||||
|
@ -4260,8 +4267,15 @@ ZEND_VM_HOT_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL,OBSERVER))
|
|||
SAVE_OPLINE();
|
||||
EX(call) = call->prev_execute_data;
|
||||
|
||||
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
|
||||
zend_deprecated_function(fbc);
|
||||
const uint32_t no_discard = RETURN_VALUE_USED(opline) ? 0 : ZEND_ACC_NODISCARD;
|
||||
|
||||
if (UNEXPECTED(fbc->common.fn_flags & (ZEND_ACC_DEPRECATED|no_discard))) {
|
||||
if (fbc->common.fn_flags & ZEND_ACC_DEPRECATED) {
|
||||
zend_deprecated_function(fbc);
|
||||
}
|
||||
if ((fbc->common.fn_flags & no_discard) && EG(exception) == NULL) {
|
||||
zend_nodiscard_function(fbc);
|
||||
}
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE)) {
|
||||
OBJ_RELEASE(ZEND_CLOSURE_OBJECT(call->func));
|
||||
|
|
66
Zend/zend_vm_execute.h
generated
66
Zend/zend_vm_execute.h
generated
|
@ -1552,8 +1552,15 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_S
|
|||
SAVE_OPLINE();
|
||||
EX(call) = call->prev_execute_data;
|
||||
|
||||
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
|
||||
zend_deprecated_function(fbc);
|
||||
const uint32_t no_discard = 0 ? 0 : ZEND_ACC_NODISCARD;
|
||||
|
||||
if (UNEXPECTED(fbc->common.fn_flags & (ZEND_ACC_DEPRECATED|no_discard))) {
|
||||
if (fbc->common.fn_flags & ZEND_ACC_DEPRECATED) {
|
||||
zend_deprecated_function(fbc);
|
||||
}
|
||||
if ((fbc->common.fn_flags & no_discard) && EG(exception) == NULL) {
|
||||
zend_nodiscard_function(fbc);
|
||||
}
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
UNDEF_RESULT();
|
||||
if (!0) {
|
||||
|
@ -1654,8 +1661,15 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_S
|
|||
SAVE_OPLINE();
|
||||
EX(call) = call->prev_execute_data;
|
||||
|
||||
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
|
||||
zend_deprecated_function(fbc);
|
||||
const uint32_t no_discard = 1 ? 0 : ZEND_ACC_NODISCARD;
|
||||
|
||||
if (UNEXPECTED(fbc->common.fn_flags & (ZEND_ACC_DEPRECATED|no_discard))) {
|
||||
if (fbc->common.fn_flags & ZEND_ACC_DEPRECATED) {
|
||||
zend_deprecated_function(fbc);
|
||||
}
|
||||
if ((fbc->common.fn_flags & no_discard) && EG(exception) == NULL) {
|
||||
zend_nodiscard_function(fbc);
|
||||
}
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
UNDEF_RESULT();
|
||||
if (!1) {
|
||||
|
@ -1756,8 +1770,15 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_
|
|||
SAVE_OPLINE();
|
||||
EX(call) = call->prev_execute_data;
|
||||
|
||||
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
|
||||
zend_deprecated_function(fbc);
|
||||
const uint32_t no_discard = RETURN_VALUE_USED(opline) ? 0 : ZEND_ACC_NODISCARD;
|
||||
|
||||
if (UNEXPECTED(fbc->common.fn_flags & (ZEND_ACC_DEPRECATED|no_discard))) {
|
||||
if (fbc->common.fn_flags & ZEND_ACC_DEPRECATED) {
|
||||
zend_deprecated_function(fbc);
|
||||
}
|
||||
if ((fbc->common.fn_flags & no_discard) && EG(exception) == NULL) {
|
||||
zend_nodiscard_function(fbc);
|
||||
}
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
UNDEF_RESULT();
|
||||
if (!RETURN_VALUE_USED(opline)) {
|
||||
|
@ -1860,8 +1881,15 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV
|
|||
SAVE_OPLINE();
|
||||
EX(call) = call->prev_execute_data;
|
||||
|
||||
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
|
||||
zend_deprecated_function(fbc);
|
||||
const uint32_t no_discard = 0 ? 0 : ZEND_ACC_NODISCARD;
|
||||
|
||||
if (UNEXPECTED(fbc->common.fn_flags & (ZEND_ACC_DEPRECATED|no_discard))) {
|
||||
if (fbc->common.fn_flags & ZEND_ACC_DEPRECATED) {
|
||||
zend_deprecated_function(fbc);
|
||||
}
|
||||
if ((fbc->common.fn_flags & no_discard) && EG(exception) == NULL) {
|
||||
zend_nodiscard_function(fbc);
|
||||
}
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE)) {
|
||||
OBJ_RELEASE(ZEND_CLOSURE_OBJECT(call->func));
|
||||
|
@ -1978,8 +2006,15 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV
|
|||
SAVE_OPLINE();
|
||||
EX(call) = call->prev_execute_data;
|
||||
|
||||
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
|
||||
zend_deprecated_function(fbc);
|
||||
const uint32_t no_discard = 1 ? 0 : ZEND_ACC_NODISCARD;
|
||||
|
||||
if (UNEXPECTED(fbc->common.fn_flags & (ZEND_ACC_DEPRECATED|no_discard))) {
|
||||
if (fbc->common.fn_flags & ZEND_ACC_DEPRECATED) {
|
||||
zend_deprecated_function(fbc);
|
||||
}
|
||||
if ((fbc->common.fn_flags & no_discard) && EG(exception) == NULL) {
|
||||
zend_nodiscard_function(fbc);
|
||||
}
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE)) {
|
||||
OBJ_RELEASE(ZEND_CLOSURE_OBJECT(call->func));
|
||||
|
@ -2096,8 +2131,15 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_OBS
|
|||
SAVE_OPLINE();
|
||||
EX(call) = call->prev_execute_data;
|
||||
|
||||
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
|
||||
zend_deprecated_function(fbc);
|
||||
const uint32_t no_discard = RETURN_VALUE_USED(opline) ? 0 : ZEND_ACC_NODISCARD;
|
||||
|
||||
if (UNEXPECTED(fbc->common.fn_flags & (ZEND_ACC_DEPRECATED|no_discard))) {
|
||||
if (fbc->common.fn_flags & ZEND_ACC_DEPRECATED) {
|
||||
zend_deprecated_function(fbc);
|
||||
}
|
||||
if ((fbc->common.fn_flags & no_discard) && EG(exception) == NULL) {
|
||||
zend_nodiscard_function(fbc);
|
||||
}
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE)) {
|
||||
OBJ_RELEASE(ZEND_CLOSURE_OBJECT(call->func));
|
||||
|
|
|
@ -1519,9 +1519,13 @@ class FuncInfo {
|
|||
}
|
||||
|
||||
foreach ($this->attributes as $attr) {
|
||||
if ($attr->class === "Deprecated") {
|
||||
$flags[] = "ZEND_ACC_DEPRECATED";
|
||||
break;
|
||||
switch ($attr->class) {
|
||||
case "Deprecated":
|
||||
$flags[] = "ZEND_ACC_DEPRECATED";
|
||||
break;
|
||||
case "NoDiscard":
|
||||
$flags[] = "ZEND_ACC_NODISCARD";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -524,29 +524,38 @@ class DateTimeImmutable implements DateTimeInterface
|
|||
public function diff(DateTimeInterface $targetObject, bool $absolute = false): DateInterval {}
|
||||
|
||||
/** @tentative-return-type */
|
||||
#[\NoDiscard(message: "as DateTimeImmutable::modify() does not modify the object itself")]
|
||||
public function modify(string $modifier): DateTimeImmutable {}
|
||||
|
||||
/** @tentative-return-type */
|
||||
#[\NoDiscard(message: "as DateTimeImmutable::add() does not modify the object itself")]
|
||||
public function add(DateInterval $interval): DateTimeImmutable {}
|
||||
|
||||
/** @tentative-return-type */
|
||||
#[\NoDiscard(message: "as DateTimeImmutable::sub() does not modify the object itself")]
|
||||
public function sub(DateInterval $interval): DateTimeImmutable {}
|
||||
|
||||
/** @tentative-return-type */
|
||||
#[\NoDiscard(message: "as DateTimeImmutable::setTimezone() does not modify the object itself")]
|
||||
public function setTimezone(DateTimeZone $timezone): DateTimeImmutable {}
|
||||
|
||||
/** @tentative-return-type */
|
||||
#[\NoDiscard(message: "as DateTimeImmutable::setTime() does not modify the object itself")]
|
||||
public function setTime(int $hour, int $minute, int $second = 0, int $microsecond = 0): DateTimeImmutable {}
|
||||
|
||||
/** @tentative-return-type */
|
||||
#[\NoDiscard(message: "as DateTimeImmutable::setDate() does not modify the object itself")]
|
||||
public function setDate(int $year, int $month, int $day): DateTimeImmutable {}
|
||||
|
||||
/** @tentative-return-type */
|
||||
#[\NoDiscard(message: "as DateTimeImmutable::setISODate() does not modify the object itself")]
|
||||
public function setISODate(int $year, int $week, int $dayOfWeek = 1): DateTimeImmutable {}
|
||||
|
||||
/** @tentative-return-type */
|
||||
#[\NoDiscard(message: "as DateTimeImmutable::setTimestamp() does not modify the object itself")]
|
||||
public function setTimestamp(int $timestamp): DateTimeImmutable {}
|
||||
|
||||
#[\NoDiscard(message: "as DateTimeImmutable::setMicrosecond() does not modify the object itself")]
|
||||
public function setMicrosecond(int $microsecond): static {}
|
||||
|
||||
/** @tentative-return-type */
|
||||
|
|
102
ext/date/php_date_arginfo.h
generated
102
ext/date/php_date_arginfo.h
generated
|
@ -1,5 +1,5 @@
|
|||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: d7a318f6fd85e23c6352323e03c323035a511738 */
|
||||
* Stub hash: 093743b4fe7a698d1262cc1a81b60a85064fdccb */
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_strtotime, 0, 1, MAY_BE_LONG|MAY_BE_FALSE)
|
||||
ZEND_ARG_TYPE_INFO(0, datetime, IS_STRING, 0)
|
||||
|
@ -725,15 +725,15 @@ static const zend_function_entry class_DateTimeImmutable_methods[] = {
|
|||
ZEND_RAW_FENTRY("getTimestamp", zif_date_timestamp_get, arginfo_class_DateTimeImmutable_getTimestamp, ZEND_ACC_PUBLIC, NULL, NULL)
|
||||
ZEND_RAW_FENTRY("getMicrosecond", zim_DateTime_getMicrosecond, arginfo_class_DateTimeImmutable_getMicrosecond, ZEND_ACC_PUBLIC, NULL, NULL)
|
||||
ZEND_RAW_FENTRY("diff", zif_date_diff, arginfo_class_DateTimeImmutable_diff, ZEND_ACC_PUBLIC, NULL, NULL)
|
||||
ZEND_ME(DateTimeImmutable, modify, arginfo_class_DateTimeImmutable_modify, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(DateTimeImmutable, add, arginfo_class_DateTimeImmutable_add, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(DateTimeImmutable, sub, arginfo_class_DateTimeImmutable_sub, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(DateTimeImmutable, setTimezone, arginfo_class_DateTimeImmutable_setTimezone, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(DateTimeImmutable, setTime, arginfo_class_DateTimeImmutable_setTime, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(DateTimeImmutable, setDate, arginfo_class_DateTimeImmutable_setDate, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(DateTimeImmutable, setISODate, arginfo_class_DateTimeImmutable_setISODate, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(DateTimeImmutable, setTimestamp, arginfo_class_DateTimeImmutable_setTimestamp, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(DateTimeImmutable, setMicrosecond, arginfo_class_DateTimeImmutable_setMicrosecond, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(DateTimeImmutable, modify, arginfo_class_DateTimeImmutable_modify, ZEND_ACC_PUBLIC|ZEND_ACC_NODISCARD)
|
||||
ZEND_ME(DateTimeImmutable, add, arginfo_class_DateTimeImmutable_add, ZEND_ACC_PUBLIC|ZEND_ACC_NODISCARD)
|
||||
ZEND_ME(DateTimeImmutable, sub, arginfo_class_DateTimeImmutable_sub, ZEND_ACC_PUBLIC|ZEND_ACC_NODISCARD)
|
||||
ZEND_ME(DateTimeImmutable, setTimezone, arginfo_class_DateTimeImmutable_setTimezone, ZEND_ACC_PUBLIC|ZEND_ACC_NODISCARD)
|
||||
ZEND_ME(DateTimeImmutable, setTime, arginfo_class_DateTimeImmutable_setTime, ZEND_ACC_PUBLIC|ZEND_ACC_NODISCARD)
|
||||
ZEND_ME(DateTimeImmutable, setDate, arginfo_class_DateTimeImmutable_setDate, ZEND_ACC_PUBLIC|ZEND_ACC_NODISCARD)
|
||||
ZEND_ME(DateTimeImmutable, setISODate, arginfo_class_DateTimeImmutable_setISODate, ZEND_ACC_PUBLIC|ZEND_ACC_NODISCARD)
|
||||
ZEND_ME(DateTimeImmutable, setTimestamp, arginfo_class_DateTimeImmutable_setTimestamp, ZEND_ACC_PUBLIC|ZEND_ACC_NODISCARD)
|
||||
ZEND_ME(DateTimeImmutable, setMicrosecond, arginfo_class_DateTimeImmutable_setMicrosecond, ZEND_ACC_PUBLIC|ZEND_ACC_NODISCARD)
|
||||
ZEND_ME(DateTimeImmutable, createFromMutable, arginfo_class_DateTimeImmutable_createFromMutable, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
|
||||
ZEND_ME(DateTimeImmutable, createFromInterface, arginfo_class_DateTimeImmutable_createFromInterface, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
|
||||
ZEND_FE_END
|
||||
|
@ -989,6 +989,88 @@ static zend_class_entry *register_class_DateTimeImmutable(zend_class_entry *clas
|
|||
class_entry = zend_register_internal_class_with_flags(&ce, NULL, 0);
|
||||
zend_class_implements(class_entry, 1, class_entry_DateTimeInterface);
|
||||
|
||||
|
||||
zend_string *attribute_name_NoDiscard_func_modify_0 = zend_string_init_interned("NoDiscard", sizeof("NoDiscard") - 1, 1);
|
||||
zend_attribute *attribute_NoDiscard_func_modify_0 = zend_add_function_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "modify", sizeof("modify") - 1), attribute_name_NoDiscard_func_modify_0, 1);
|
||||
zend_string_release(attribute_name_NoDiscard_func_modify_0);
|
||||
zval attribute_NoDiscard_func_modify_0_arg0;
|
||||
zend_string *attribute_NoDiscard_func_modify_0_arg0_str = zend_string_init("as DateTimeImmutable::modify() does not modify the object itself", strlen("as DateTimeImmutable::modify() does not modify the object itself"), 1);
|
||||
ZVAL_STR(&attribute_NoDiscard_func_modify_0_arg0, attribute_NoDiscard_func_modify_0_arg0_str);
|
||||
ZVAL_COPY_VALUE(&attribute_NoDiscard_func_modify_0->args[0].value, &attribute_NoDiscard_func_modify_0_arg0);
|
||||
attribute_NoDiscard_func_modify_0->args[0].name = ZSTR_KNOWN(ZEND_STR_MESSAGE);
|
||||
|
||||
zend_string *attribute_name_NoDiscard_func_add_0 = zend_string_init_interned("NoDiscard", sizeof("NoDiscard") - 1, 1);
|
||||
zend_attribute *attribute_NoDiscard_func_add_0 = zend_add_function_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "add", sizeof("add") - 1), attribute_name_NoDiscard_func_add_0, 1);
|
||||
zend_string_release(attribute_name_NoDiscard_func_add_0);
|
||||
zval attribute_NoDiscard_func_add_0_arg0;
|
||||
zend_string *attribute_NoDiscard_func_add_0_arg0_str = zend_string_init("as DateTimeImmutable::add() does not modify the object itself", strlen("as DateTimeImmutable::add() does not modify the object itself"), 1);
|
||||
ZVAL_STR(&attribute_NoDiscard_func_add_0_arg0, attribute_NoDiscard_func_add_0_arg0_str);
|
||||
ZVAL_COPY_VALUE(&attribute_NoDiscard_func_add_0->args[0].value, &attribute_NoDiscard_func_add_0_arg0);
|
||||
attribute_NoDiscard_func_add_0->args[0].name = ZSTR_KNOWN(ZEND_STR_MESSAGE);
|
||||
|
||||
zend_string *attribute_name_NoDiscard_func_sub_0 = zend_string_init_interned("NoDiscard", sizeof("NoDiscard") - 1, 1);
|
||||
zend_attribute *attribute_NoDiscard_func_sub_0 = zend_add_function_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "sub", sizeof("sub") - 1), attribute_name_NoDiscard_func_sub_0, 1);
|
||||
zend_string_release(attribute_name_NoDiscard_func_sub_0);
|
||||
zval attribute_NoDiscard_func_sub_0_arg0;
|
||||
zend_string *attribute_NoDiscard_func_sub_0_arg0_str = zend_string_init("as DateTimeImmutable::sub() does not modify the object itself", strlen("as DateTimeImmutable::sub() does not modify the object itself"), 1);
|
||||
ZVAL_STR(&attribute_NoDiscard_func_sub_0_arg0, attribute_NoDiscard_func_sub_0_arg0_str);
|
||||
ZVAL_COPY_VALUE(&attribute_NoDiscard_func_sub_0->args[0].value, &attribute_NoDiscard_func_sub_0_arg0);
|
||||
attribute_NoDiscard_func_sub_0->args[0].name = ZSTR_KNOWN(ZEND_STR_MESSAGE);
|
||||
|
||||
zend_string *attribute_name_NoDiscard_func_settimezone_0 = zend_string_init_interned("NoDiscard", sizeof("NoDiscard") - 1, 1);
|
||||
zend_attribute *attribute_NoDiscard_func_settimezone_0 = zend_add_function_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "settimezone", sizeof("settimezone") - 1), attribute_name_NoDiscard_func_settimezone_0, 1);
|
||||
zend_string_release(attribute_name_NoDiscard_func_settimezone_0);
|
||||
zval attribute_NoDiscard_func_settimezone_0_arg0;
|
||||
zend_string *attribute_NoDiscard_func_settimezone_0_arg0_str = zend_string_init("as DateTimeImmutable::setTimezone() does not modify the object itself", strlen("as DateTimeImmutable::setTimezone() does not modify the object itself"), 1);
|
||||
ZVAL_STR(&attribute_NoDiscard_func_settimezone_0_arg0, attribute_NoDiscard_func_settimezone_0_arg0_str);
|
||||
ZVAL_COPY_VALUE(&attribute_NoDiscard_func_settimezone_0->args[0].value, &attribute_NoDiscard_func_settimezone_0_arg0);
|
||||
attribute_NoDiscard_func_settimezone_0->args[0].name = ZSTR_KNOWN(ZEND_STR_MESSAGE);
|
||||
|
||||
zend_string *attribute_name_NoDiscard_func_settime_0 = zend_string_init_interned("NoDiscard", sizeof("NoDiscard") - 1, 1);
|
||||
zend_attribute *attribute_NoDiscard_func_settime_0 = zend_add_function_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "settime", sizeof("settime") - 1), attribute_name_NoDiscard_func_settime_0, 1);
|
||||
zend_string_release(attribute_name_NoDiscard_func_settime_0);
|
||||
zval attribute_NoDiscard_func_settime_0_arg0;
|
||||
zend_string *attribute_NoDiscard_func_settime_0_arg0_str = zend_string_init("as DateTimeImmutable::setTime() does not modify the object itself", strlen("as DateTimeImmutable::setTime() does not modify the object itself"), 1);
|
||||
ZVAL_STR(&attribute_NoDiscard_func_settime_0_arg0, attribute_NoDiscard_func_settime_0_arg0_str);
|
||||
ZVAL_COPY_VALUE(&attribute_NoDiscard_func_settime_0->args[0].value, &attribute_NoDiscard_func_settime_0_arg0);
|
||||
attribute_NoDiscard_func_settime_0->args[0].name = ZSTR_KNOWN(ZEND_STR_MESSAGE);
|
||||
|
||||
zend_string *attribute_name_NoDiscard_func_setdate_0 = zend_string_init_interned("NoDiscard", sizeof("NoDiscard") - 1, 1);
|
||||
zend_attribute *attribute_NoDiscard_func_setdate_0 = zend_add_function_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "setdate", sizeof("setdate") - 1), attribute_name_NoDiscard_func_setdate_0, 1);
|
||||
zend_string_release(attribute_name_NoDiscard_func_setdate_0);
|
||||
zval attribute_NoDiscard_func_setdate_0_arg0;
|
||||
zend_string *attribute_NoDiscard_func_setdate_0_arg0_str = zend_string_init("as DateTimeImmutable::setDate() does not modify the object itself", strlen("as DateTimeImmutable::setDate() does not modify the object itself"), 1);
|
||||
ZVAL_STR(&attribute_NoDiscard_func_setdate_0_arg0, attribute_NoDiscard_func_setdate_0_arg0_str);
|
||||
ZVAL_COPY_VALUE(&attribute_NoDiscard_func_setdate_0->args[0].value, &attribute_NoDiscard_func_setdate_0_arg0);
|
||||
attribute_NoDiscard_func_setdate_0->args[0].name = ZSTR_KNOWN(ZEND_STR_MESSAGE);
|
||||
|
||||
zend_string *attribute_name_NoDiscard_func_setisodate_0 = zend_string_init_interned("NoDiscard", sizeof("NoDiscard") - 1, 1);
|
||||
zend_attribute *attribute_NoDiscard_func_setisodate_0 = zend_add_function_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "setisodate", sizeof("setisodate") - 1), attribute_name_NoDiscard_func_setisodate_0, 1);
|
||||
zend_string_release(attribute_name_NoDiscard_func_setisodate_0);
|
||||
zval attribute_NoDiscard_func_setisodate_0_arg0;
|
||||
zend_string *attribute_NoDiscard_func_setisodate_0_arg0_str = zend_string_init("as DateTimeImmutable::setISODate() does not modify the object itself", strlen("as DateTimeImmutable::setISODate() does not modify the object itself"), 1);
|
||||
ZVAL_STR(&attribute_NoDiscard_func_setisodate_0_arg0, attribute_NoDiscard_func_setisodate_0_arg0_str);
|
||||
ZVAL_COPY_VALUE(&attribute_NoDiscard_func_setisodate_0->args[0].value, &attribute_NoDiscard_func_setisodate_0_arg0);
|
||||
attribute_NoDiscard_func_setisodate_0->args[0].name = ZSTR_KNOWN(ZEND_STR_MESSAGE);
|
||||
|
||||
zend_string *attribute_name_NoDiscard_func_settimestamp_0 = zend_string_init_interned("NoDiscard", sizeof("NoDiscard") - 1, 1);
|
||||
zend_attribute *attribute_NoDiscard_func_settimestamp_0 = zend_add_function_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "settimestamp", sizeof("settimestamp") - 1), attribute_name_NoDiscard_func_settimestamp_0, 1);
|
||||
zend_string_release(attribute_name_NoDiscard_func_settimestamp_0);
|
||||
zval attribute_NoDiscard_func_settimestamp_0_arg0;
|
||||
zend_string *attribute_NoDiscard_func_settimestamp_0_arg0_str = zend_string_init("as DateTimeImmutable::setTimestamp() does not modify the object itself", strlen("as DateTimeImmutable::setTimestamp() does not modify the object itself"), 1);
|
||||
ZVAL_STR(&attribute_NoDiscard_func_settimestamp_0_arg0, attribute_NoDiscard_func_settimestamp_0_arg0_str);
|
||||
ZVAL_COPY_VALUE(&attribute_NoDiscard_func_settimestamp_0->args[0].value, &attribute_NoDiscard_func_settimestamp_0_arg0);
|
||||
attribute_NoDiscard_func_settimestamp_0->args[0].name = ZSTR_KNOWN(ZEND_STR_MESSAGE);
|
||||
|
||||
zend_string *attribute_name_NoDiscard_func_setmicrosecond_0 = zend_string_init_interned("NoDiscard", sizeof("NoDiscard") - 1, 1);
|
||||
zend_attribute *attribute_NoDiscard_func_setmicrosecond_0 = zend_add_function_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "setmicrosecond", sizeof("setmicrosecond") - 1), attribute_name_NoDiscard_func_setmicrosecond_0, 1);
|
||||
zend_string_release(attribute_name_NoDiscard_func_setmicrosecond_0);
|
||||
zval attribute_NoDiscard_func_setmicrosecond_0_arg0;
|
||||
zend_string *attribute_NoDiscard_func_setmicrosecond_0_arg0_str = zend_string_init("as DateTimeImmutable::setMicrosecond() does not modify the object itself", strlen("as DateTimeImmutable::setMicrosecond() does not modify the object itself"), 1);
|
||||
ZVAL_STR(&attribute_NoDiscard_func_setmicrosecond_0_arg0, attribute_NoDiscard_func_setmicrosecond_0_arg0_str);
|
||||
ZVAL_COPY_VALUE(&attribute_NoDiscard_func_setmicrosecond_0->args[0].value, &attribute_NoDiscard_func_setmicrosecond_0_arg0);
|
||||
attribute_NoDiscard_func_setmicrosecond_0->args[0].name = ZSTR_KNOWN(ZEND_STR_MESSAGE);
|
||||
|
||||
return class_entry;
|
||||
}
|
||||
|
||||
|
|
|
@ -233,6 +233,8 @@ ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_loop_counter_helper(ZEND_OPCODE_H
|
|||
void ZEND_FASTCALL zend_jit_copy_extra_args_helper(EXECUTE_DATA_D);
|
||||
void ZEND_FASTCALL zend_jit_copy_extra_args_helper_no_skip_recv(EXECUTE_DATA_D);
|
||||
bool ZEND_FASTCALL zend_jit_deprecated_helper(OPLINE_D);
|
||||
bool ZEND_FASTCALL zend_jit_nodiscard_helper(OPLINE_D);
|
||||
bool ZEND_FASTCALL zend_jit_deprecated_nodiscard_helper(OPLINE_D);
|
||||
void ZEND_FASTCALL zend_jit_undefined_long_key(EXECUTE_DATA_D);
|
||||
void ZEND_FASTCALL zend_jit_undefined_long_key_ex(zend_long key EXECUTE_DATA_DC);
|
||||
void ZEND_FASTCALL zend_jit_undefined_string_key(EXECUTE_DATA_D);
|
||||
|
|
|
@ -10153,7 +10153,7 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
|
|||
ir_GUARD_NOT(
|
||||
ir_AND_U32(
|
||||
ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, fn_flags))),
|
||||
ir_CONST_U32(ZEND_ACC_DEPRECATED)),
|
||||
ir_CONST_U32(ZEND_ACC_DEPRECATED|ZEND_ACC_NODISCARD)),
|
||||
ir_CONST_ADDR(exit_addr));
|
||||
}
|
||||
}
|
||||
|
@ -10179,12 +10179,27 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
|
|||
if (opline->opcode == ZEND_DO_FCALL || opline->opcode == ZEND_DO_FCALL_BY_NAME) {
|
||||
if (!func) {
|
||||
if (!trace) {
|
||||
ir_ref if_deprecated, ret;
|
||||
ir_ref if_deprecated_nodiscard, ret;
|
||||
|
||||
if_deprecated = ir_IF(ir_AND_U32(
|
||||
uint32_t no_discard = RETURN_VALUE_USED(opline) ? 0 : ZEND_ACC_NODISCARD;
|
||||
|
||||
if_deprecated_nodiscard = ir_IF(ir_AND_U32(
|
||||
ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, fn_flags))),
|
||||
ir_CONST_U32(ZEND_ACC_DEPRECATED)));
|
||||
ir_IF_TRUE_cold(if_deprecated);
|
||||
ir_CONST_U32(ZEND_ACC_DEPRECATED|no_discard)));
|
||||
ir_IF_TRUE_cold(if_deprecated_nodiscard);
|
||||
|
||||
ir_ref helper = ir_CONST_FC_FUNC(no_discard ? zend_jit_deprecated_nodiscard_helper : zend_jit_deprecated_helper);
|
||||
if (GCC_GLOBAL_REGS) {
|
||||
ret = ir_CALL(IR_BOOL, helper);
|
||||
} else {
|
||||
ret = ir_CALL_1(IR_BOOL, helper, rx);
|
||||
}
|
||||
ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler));
|
||||
ir_MERGE_WITH_EMPTY_FALSE(if_deprecated_nodiscard);
|
||||
}
|
||||
} else {
|
||||
if (func->common.fn_flags & ZEND_ACC_DEPRECATED) {
|
||||
ir_ref ret;
|
||||
|
||||
if (GCC_GLOBAL_REGS) {
|
||||
ret = ir_CALL(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_deprecated_helper));
|
||||
|
@ -10192,17 +10207,18 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
|
|||
ret = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_deprecated_helper), rx);
|
||||
}
|
||||
ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler));
|
||||
ir_MERGE_WITH_EMPTY_FALSE(if_deprecated);
|
||||
}
|
||||
} else if (func->common.fn_flags & ZEND_ACC_DEPRECATED) {
|
||||
ir_ref ret;
|
||||
|
||||
if (GCC_GLOBAL_REGS) {
|
||||
ret = ir_CALL(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_deprecated_helper));
|
||||
} else {
|
||||
ret = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_deprecated_helper), rx);
|
||||
if ((func->common.fn_flags & ZEND_ACC_NODISCARD) && !RETURN_VALUE_USED(opline)) {
|
||||
ir_ref ret;
|
||||
|
||||
if (GCC_GLOBAL_REGS) {
|
||||
ret = ir_CALL(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_nodiscard_helper));
|
||||
} else {
|
||||
ret = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_nodiscard_helper), rx);
|
||||
}
|
||||
ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler));
|
||||
}
|
||||
ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -204,6 +204,54 @@ bool ZEND_FASTCALL zend_jit_deprecated_helper(OPLINE_D)
|
|||
return 1;
|
||||
}
|
||||
|
||||
bool ZEND_FASTCALL zend_jit_nodiscard_helper(OPLINE_D)
|
||||
{
|
||||
zend_execute_data *call = (zend_execute_data *) opline;
|
||||
zend_function *fbc = call->func;
|
||||
|
||||
zend_nodiscard_function(fbc);
|
||||
|
||||
if (EG(exception)) {
|
||||
#ifndef HAVE_GCC_GLOBAL_REGS
|
||||
zend_execute_data *execute_data = EG(current_execute_data);
|
||||
#endif
|
||||
const zend_op *opline = EG(opline_before_exception);
|
||||
if (opline && RETURN_VALUE_USED(opline)) {
|
||||
ZVAL_UNDEF(EX_VAR(opline->result.var));
|
||||
}
|
||||
|
||||
zend_vm_stack_free_args(call);
|
||||
|
||||
if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS)) {
|
||||
OBJ_RELEASE(Z_OBJ(call->This));
|
||||
}
|
||||
|
||||
zend_vm_stack_free_call_frame(call);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool ZEND_FASTCALL zend_jit_deprecated_nodiscard_helper(OPLINE_D)
|
||||
{
|
||||
zend_execute_data *call = (zend_execute_data *) opline;
|
||||
zend_function *fbc = call->func;
|
||||
|
||||
if (fbc->common.fn_flags & ZEND_ACC_DEPRECATED) {
|
||||
if (zend_jit_deprecated_helper(OPLINE_C) == 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (fbc->common.fn_flags & ZEND_ACC_NODISCARD) {
|
||||
if (zend_jit_nodiscard_helper(OPLINE_C) == 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ZEND_FASTCALL zend_jit_undefined_long_key(EXECUTE_DATA_D)
|
||||
{
|
||||
const zend_op *opline = EX(opline);
|
||||
|
|
|
@ -2732,6 +2732,7 @@ function proc_nice(int $priority): bool {}
|
|||
* @param resource $stream
|
||||
* @param int $would_block
|
||||
*/
|
||||
#[\NoDiscard(message: "as locking the stream might have failed")]
|
||||
function flock($stream, int $operation, &$would_block = null): bool {}
|
||||
|
||||
/**
|
||||
|
|
13
ext/standard/basic_functions_arginfo.h
generated
13
ext/standard/basic_functions_arginfo.h
generated
|
@ -1,5 +1,5 @@
|
|||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: 85677dc3476d25b7820fd3a26fe39f2e9378b6e7 */
|
||||
* Stub hash: 824ccb41163307bd0fad452b705a8222b6f42d09 */
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0)
|
||||
|
@ -3205,7 +3205,7 @@ static const zend_function_entry ext_functions[] = {
|
|||
#if defined(HAVE_NICE)
|
||||
ZEND_FE(proc_nice, arginfo_proc_nice)
|
||||
#endif
|
||||
ZEND_FE(flock, arginfo_flock)
|
||||
ZEND_RAW_FENTRY("flock", zif_flock, arginfo_flock, ZEND_ACC_NODISCARD, NULL, NULL)
|
||||
ZEND_FE(get_meta_tags, arginfo_get_meta_tags)
|
||||
ZEND_FE(pclose, arginfo_pclose)
|
||||
ZEND_FE(popen, arginfo_popen)
|
||||
|
@ -4039,6 +4039,15 @@ static void register_basic_functions_symbols(int module_number)
|
|||
ZVAL_COPY_VALUE(&attribute_Deprecated_func_utf8_decode_0->args[1].value, &attribute_Deprecated_func_utf8_decode_0_arg1);
|
||||
attribute_Deprecated_func_utf8_decode_0->args[1].name = ZSTR_KNOWN(ZEND_STR_MESSAGE);
|
||||
|
||||
zend_string *attribute_name_NoDiscard_func_flock_0 = zend_string_init_interned("NoDiscard", sizeof("NoDiscard") - 1, 1);
|
||||
zend_attribute *attribute_NoDiscard_func_flock_0 = zend_add_function_attribute(zend_hash_str_find_ptr(CG(function_table), "flock", sizeof("flock") - 1), attribute_name_NoDiscard_func_flock_0, 1);
|
||||
zend_string_release(attribute_name_NoDiscard_func_flock_0);
|
||||
zval attribute_NoDiscard_func_flock_0_arg0;
|
||||
zend_string *attribute_NoDiscard_func_flock_0_arg0_str = zend_string_init("as locking the stream might have failed", strlen("as locking the stream might have failed"), 1);
|
||||
ZVAL_STR(&attribute_NoDiscard_func_flock_0_arg0, attribute_NoDiscard_func_flock_0_arg0_str);
|
||||
ZVAL_COPY_VALUE(&attribute_NoDiscard_func_flock_0->args[0].value, &attribute_NoDiscard_func_flock_0_arg0);
|
||||
attribute_NoDiscard_func_flock_0->args[0].name = ZSTR_KNOWN(ZEND_STR_MESSAGE);
|
||||
|
||||
zend_add_parameter_attribute(zend_hash_str_find_ptr(CG(function_table), "password_hash", sizeof("password_hash") - 1), 0, ZSTR_KNOWN(ZEND_STR_SENSITIVEPARAMETER), 0);
|
||||
|
||||
zend_add_parameter_attribute(zend_hash_str_find_ptr(CG(function_table), "password_verify", sizeof("password_verify") - 1), 0, ZSTR_KNOWN(ZEND_STR_SENSITIVEPARAMETER), 0);
|
||||
|
|
|
@ -19,7 +19,7 @@ class test_wrapper extends test_wrapper_base {
|
|||
}
|
||||
function test($name, $fd, $mode) {
|
||||
echo "------ $name: -------\n";
|
||||
flock($fd, $mode);
|
||||
(void)flock($fd, $mode);
|
||||
$data = stream_get_meta_data($fd);
|
||||
var_dump($data['wrapper_data']->mode === $mode);
|
||||
}
|
||||
|
|
|
@ -124,6 +124,13 @@ static ZEND_FUNCTION(zend_test_deprecated_attr)
|
|||
ZEND_PARSE_PARAMETERS_NONE();
|
||||
}
|
||||
|
||||
static ZEND_FUNCTION(zend_test_deprecated_nodiscard)
|
||||
{
|
||||
ZEND_PARSE_PARAMETERS_NONE();
|
||||
|
||||
RETURN_LONG(1);
|
||||
}
|
||||
|
||||
/* Create a string without terminating null byte. Must be terminated with
|
||||
* zend_terminate_string() before destruction, otherwise a warning is issued
|
||||
* in debug builds. */
|
||||
|
|
|
@ -218,6 +218,11 @@ namespace {
|
|||
#[\Deprecated(message: "custom message")]
|
||||
function zend_test_deprecated_attr(): void {}
|
||||
|
||||
|
||||
#[\Deprecated(message: "custom message")]
|
||||
#[\NoDiscard(message: "custom message 2")]
|
||||
function zend_test_deprecated_nodiscard(): int {}
|
||||
|
||||
/** @alias zend_test_void_return */
|
||||
function zend_test_aliased(): void {}
|
||||
|
||||
|
|
34
ext/zend_test/test_arginfo.h
generated
34
ext/zend_test/test_arginfo.h
generated
|
@ -1,5 +1,5 @@
|
|||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: 80b2dbc373baccd5ee4df047070d95e4c44effcd */
|
||||
* Stub hash: eebe535d0295f707201ff751e38a5ad3837dbbd2 */
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_array_return, 0, 0, IS_ARRAY, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
@ -22,6 +22,9 @@ ZEND_END_ARG_INFO()
|
|||
|
||||
#define arginfo_zend_test_deprecated_attr arginfo_zend_test_void_return
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_deprecated_nodiscard, 0, 0, IS_LONG, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_zend_test_aliased arginfo_zend_test_void_return
|
||||
|
||||
#define arginfo_zend_test_deprecated_aliased arginfo_zend_test_void_return
|
||||
|
@ -128,8 +131,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_is_string_marked_as_va
|
|||
ZEND_ARG_TYPE_INFO(0, string, IS_STRING, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_get_map_ptr_last, 0, 0, IS_LONG, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
#define arginfo_zend_get_map_ptr_last arginfo_zend_test_deprecated_nodiscard
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_crash, 0, 0, IS_VOID, 0)
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, message, IS_STRING, 1, "null")
|
||||
|
@ -187,7 +189,7 @@ ZEND_END_ARG_INFO()
|
|||
|
||||
#define arginfo_ZendTestNS2_ZendSubNS_namespaced_deprecated_aliased_func arginfo_zend_test_void_return
|
||||
|
||||
#define arginfo_class__ZendTestClass_is_object arginfo_zend_get_map_ptr_last
|
||||
#define arginfo_class__ZendTestClass_is_object arginfo_zend_test_deprecated_nodiscard
|
||||
|
||||
#define arginfo_class__ZendTestClass___toString arginfo_zend_get_current_func_name
|
||||
|
||||
|
@ -262,6 +264,7 @@ static ZEND_FUNCTION(zend_test_void_return);
|
|||
static ZEND_FUNCTION(zend_test_compile_string);
|
||||
static ZEND_FUNCTION(zend_test_deprecated);
|
||||
static ZEND_FUNCTION(zend_test_deprecated_attr);
|
||||
static ZEND_FUNCTION(zend_test_deprecated_nodiscard);
|
||||
static ZEND_FUNCTION(zend_create_unterminated_string);
|
||||
static ZEND_FUNCTION(zend_terminate_string);
|
||||
static ZEND_FUNCTION(zend_leak_variable);
|
||||
|
@ -358,6 +361,11 @@ static const zend_function_entry ext_functions[] = {
|
|||
#else
|
||||
ZEND_RAW_FENTRY("zend_test_deprecated_attr", zif_zend_test_deprecated_attr, arginfo_zend_test_deprecated_attr, ZEND_ACC_DEPRECATED)
|
||||
#endif
|
||||
#if (PHP_VERSION_ID >= 80400)
|
||||
ZEND_RAW_FENTRY("zend_test_deprecated_nodiscard", zif_zend_test_deprecated_nodiscard, arginfo_zend_test_deprecated_nodiscard, ZEND_ACC_DEPRECATED|ZEND_ACC_NODISCARD, NULL, NULL)
|
||||
#else
|
||||
ZEND_RAW_FENTRY("zend_test_deprecated_nodiscard", zif_zend_test_deprecated_nodiscard, arginfo_zend_test_deprecated_nodiscard, ZEND_ACC_DEPRECATED|ZEND_ACC_NODISCARD)
|
||||
#endif
|
||||
#if (PHP_VERSION_ID >= 80400)
|
||||
ZEND_RAW_FENTRY("zend_test_aliased", zif_zend_test_void_return, arginfo_zend_test_aliased, 0, NULL, NULL)
|
||||
#else
|
||||
|
@ -564,6 +572,24 @@ static void register_test_symbols(int module_number)
|
|||
ZVAL_COPY_VALUE(&attribute_Deprecated_func_zend_test_deprecated_attr_0->args[0].value, &attribute_Deprecated_func_zend_test_deprecated_attr_0_arg0);
|
||||
attribute_Deprecated_func_zend_test_deprecated_attr_0->args[0].name = ZSTR_KNOWN(ZEND_STR_MESSAGE);
|
||||
|
||||
zend_string *attribute_name_Deprecated_func_zend_test_deprecated_nodiscard_0 = zend_string_init_interned("Deprecated", sizeof("Deprecated") - 1, 1);
|
||||
zend_attribute *attribute_Deprecated_func_zend_test_deprecated_nodiscard_0 = zend_add_function_attribute(zend_hash_str_find_ptr(CG(function_table), "zend_test_deprecated_nodiscard", sizeof("zend_test_deprecated_nodiscard") - 1), attribute_name_Deprecated_func_zend_test_deprecated_nodiscard_0, 1);
|
||||
zend_string_release(attribute_name_Deprecated_func_zend_test_deprecated_nodiscard_0);
|
||||
zval attribute_Deprecated_func_zend_test_deprecated_nodiscard_0_arg0;
|
||||
zend_string *attribute_Deprecated_func_zend_test_deprecated_nodiscard_0_arg0_str = zend_string_init("custom message", strlen("custom message"), 1);
|
||||
ZVAL_STR(&attribute_Deprecated_func_zend_test_deprecated_nodiscard_0_arg0, attribute_Deprecated_func_zend_test_deprecated_nodiscard_0_arg0_str);
|
||||
ZVAL_COPY_VALUE(&attribute_Deprecated_func_zend_test_deprecated_nodiscard_0->args[0].value, &attribute_Deprecated_func_zend_test_deprecated_nodiscard_0_arg0);
|
||||
attribute_Deprecated_func_zend_test_deprecated_nodiscard_0->args[0].name = ZSTR_KNOWN(ZEND_STR_MESSAGE);
|
||||
|
||||
zend_string *attribute_name_NoDiscard_func_zend_test_deprecated_nodiscard_1 = zend_string_init_interned("NoDiscard", sizeof("NoDiscard") - 1, 1);
|
||||
zend_attribute *attribute_NoDiscard_func_zend_test_deprecated_nodiscard_1 = zend_add_function_attribute(zend_hash_str_find_ptr(CG(function_table), "zend_test_deprecated_nodiscard", sizeof("zend_test_deprecated_nodiscard") - 1), attribute_name_NoDiscard_func_zend_test_deprecated_nodiscard_1, 1);
|
||||
zend_string_release(attribute_name_NoDiscard_func_zend_test_deprecated_nodiscard_1);
|
||||
zval attribute_NoDiscard_func_zend_test_deprecated_nodiscard_1_arg0;
|
||||
zend_string *attribute_NoDiscard_func_zend_test_deprecated_nodiscard_1_arg0_str = zend_string_init("custom message 2", strlen("custom message 2"), 1);
|
||||
ZVAL_STR(&attribute_NoDiscard_func_zend_test_deprecated_nodiscard_1_arg0, attribute_NoDiscard_func_zend_test_deprecated_nodiscard_1_arg0_str);
|
||||
ZVAL_COPY_VALUE(&attribute_NoDiscard_func_zend_test_deprecated_nodiscard_1->args[0].value, &attribute_NoDiscard_func_zend_test_deprecated_nodiscard_1_arg0);
|
||||
attribute_NoDiscard_func_zend_test_deprecated_nodiscard_1->args[0].name = ZSTR_KNOWN(ZEND_STR_MESSAGE);
|
||||
|
||||
zend_string *attribute_name_ZendTestParameterAttribute_func_zend_test_parameter_with_attribute_arg0_0 = zend_string_init_interned("ZendTestParameterAttribute", sizeof("ZendTestParameterAttribute") - 1, 1);
|
||||
zend_attribute *attribute_ZendTestParameterAttribute_func_zend_test_parameter_with_attribute_arg0_0 = zend_add_parameter_attribute(zend_hash_str_find_ptr(CG(function_table), "zend_test_parameter_with_attribute", sizeof("zend_test_parameter_with_attribute") - 1), 0, attribute_name_ZendTestParameterAttribute_func_zend_test_parameter_with_attribute_arg0_0, 1);
|
||||
zend_string_release(attribute_name_ZendTestParameterAttribute_func_zend_test_parameter_with_attribute_arg0_0);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue