. Fixed bug #76446 (zend_variables.c:73: zend_string_destroy: Assertion
`!(zval_gc_flags((str)->gc)). (Nikita, Laruence)
+- Tokenizer:
+ . Fixed bug #75218 (Change remaining uncatchable fatal errors for parsing
+ into ParseError). (Nikita)
+
- ZIP:
. Fixed bug #76461 (OPSYS_Z_CPM defined instead of OPSYS_CPM).
(Dennis Birkholz, Remi)
(RFC: https://wiki.php.net/rfc/list_reference_assignment)
. instanceof now allows literals as the first operand,
in which case the result is always FALSE.
+ . A new CompileError exception has been added, from which ParseError inherits.
+ A small number of compilation errors will now throw a CompileError instead
+ of generating a fatal error. Currently this only affects compilation errors
+ that may be thrown by token_get_all() in TOKEN_PARSE mode, but more errors
+ may be converted in the future.
BCMath:
. bcscale() can now also be used as getter to retrieve the current scale in use.
--- /dev/null
+--TEST--
+Bug #75218: Change remaining uncatchable fatal errors for parsing into ParseError
+--FILE--
+<?php
+
+function try_eval($code) {
+ try {
+ eval($code);
+ } catch (CompileError $e) {
+ echo $e->getMessage(), "\n";
+ }
+}
+
+try_eval('if (false) {class C { final final function foo($fff) {}}}');
+try_eval('if (false) {class C { private protected $x; }}');
+try_eval('if (true) { __HALT_COMPILER(); }');
+try_eval('declare(encoding=[]);');
+
+?>
+--EXPECT--
+Multiple final modifiers are not allowed
+Multiple access type modifiers are not allowed
+__HALT_COMPILER() can only be used from the outermost scope
+Encoding must be a literal
{
uint32_t new_flags = flags | new_flag;
if ((flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) && (new_flag & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) {
- zend_error_noreturn(E_COMPILE_ERROR, "Multiple abstract modifiers are not allowed");
+ zend_throw_exception(zend_ce_compile_error,
+ "Multiple abstract modifiers are not allowed", 0);
+ return 0;
}
if ((flags & ZEND_ACC_FINAL) && (new_flag & ZEND_ACC_FINAL)) {
- zend_error_noreturn(E_COMPILE_ERROR, "Multiple final modifiers are not allowed");
+ zend_throw_exception(zend_ce_compile_error, "Multiple final modifiers are not allowed", 0);
+ return 0;
}
if ((new_flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) && (new_flags & ZEND_ACC_FINAL)) {
- zend_error_noreturn(E_COMPILE_ERROR, "Cannot use the final modifier on an abstract class");
+ zend_throw_exception(zend_ce_compile_error,
+ "Cannot use the final modifier on an abstract class", 0);
+ return 0;
}
return new_flags;
}
{
uint32_t new_flags = flags | new_flag;
if ((flags & ZEND_ACC_PPP_MASK) && (new_flag & ZEND_ACC_PPP_MASK)) {
- zend_error_noreturn(E_COMPILE_ERROR, "Multiple access type modifiers are not allowed");
+ zend_throw_exception(zend_ce_compile_error,
+ "Multiple access type modifiers are not allowed", 0);
+ return 0;
}
if ((flags & ZEND_ACC_ABSTRACT) && (new_flag & ZEND_ACC_ABSTRACT)) {
- zend_error_noreturn(E_COMPILE_ERROR, "Multiple abstract modifiers are not allowed");
+ zend_throw_exception(zend_ce_compile_error, "Multiple abstract modifiers are not allowed", 0);
+ return 0;
}
if ((flags & ZEND_ACC_STATIC) && (new_flag & ZEND_ACC_STATIC)) {
- zend_error_noreturn(E_COMPILE_ERROR, "Multiple static modifiers are not allowed");
+ zend_throw_exception(zend_ce_compile_error, "Multiple static modifiers are not allowed", 0);
+ return 0;
}
if ((flags & ZEND_ACC_FINAL) && (new_flag & ZEND_ACC_FINAL)) {
- zend_error_noreturn(E_COMPILE_ERROR, "Multiple final modifiers are not allowed");
+ zend_throw_exception(zend_ce_compile_error, "Multiple final modifiers are not allowed", 0);
+ return 0;
}
if ((new_flags & ZEND_ACC_ABSTRACT) && (new_flags & ZEND_ACC_FINAL)) {
- zend_error_noreturn(E_COMPILE_ERROR, "Cannot use the final modifier on an abstract class member");
+ zend_throw_exception(zend_ce_compile_error,
+ "Cannot use the final modifier on an abstract class member", 0);
+ return 0;
}
return new_flags;
}
/* }}} */
/* Encoding declarations must already be handled during parsing */
-void zend_handle_encoding_declaration(zend_ast *ast) /* {{{ */
+zend_bool zend_handle_encoding_declaration(zend_ast *ast) /* {{{ */
{
zend_ast_list *declares = zend_ast_get_list(ast);
uint32_t i;
if (zend_string_equals_literal_ci(name, "encoding")) {
if (value_ast->kind != ZEND_AST_ZVAL) {
- zend_error_noreturn(E_COMPILE_ERROR, "Encoding must be a literal");
+ zend_throw_exception(zend_ce_compile_error, "Encoding must be a literal", 0);
+ return 0;
}
if (CG(multibyte)) {
}
}
}
+
+ return 1;
}
/* }}} */
zend_ast *zend_negate_num_string(zend_ast *ast);
uint32_t zend_add_class_modifier(uint32_t flags, uint32_t new_flag);
uint32_t zend_add_member_modifier(uint32_t flags, uint32_t new_flag);
-void zend_handle_encoding_declaration(zend_ast *ast);
+zend_bool zend_handle_encoding_declaration(zend_ast *ast);
/* parser-driven code generators */
void zend_do_free(znode *op1);
ZEND_API zend_class_entry *zend_ce_exception;
ZEND_API zend_class_entry *zend_ce_error_exception;
ZEND_API zend_class_entry *zend_ce_error;
+ZEND_API zend_class_entry *zend_ce_compile_error;
ZEND_API zend_class_entry *zend_ce_parse_error;
ZEND_API zend_class_entry *zend_ce_type_error;
ZEND_API zend_class_entry *zend_ce_argument_count_error;
}
}
if (!EG(current_execute_data)) {
- if (exception && Z_OBJCE_P(exception) == zend_ce_parse_error) {
+ if (exception && (Z_OBJCE_P(exception) == zend_ce_parse_error || Z_OBJCE_P(exception) == zend_ce_compile_error)) {
return;
}
if(EG(exception)) {
base_ce = i_get_exception_base(&obj);
- if (EXPECTED(class_type != zend_ce_parse_error || !(filename = zend_get_compiled_filename()))) {
+ if (EXPECTED((class_type != zend_ce_parse_error && class_type != zend_ce_compile_error)
+ || !(filename = zend_get_compiled_filename()))) {
ZVAL_STRING(&tmp, zend_get_executed_filename());
zend_update_property_ex(base_ce, &obj, ZSTR_KNOWN(ZEND_STR_FILE), &tmp);
zval_ptr_dtor(&tmp);
zend_declare_property_null(zend_ce_error, "trace", sizeof("trace")-1, ZEND_ACC_PRIVATE);
zend_declare_property_null(zend_ce_error, "previous", sizeof("previous")-1, ZEND_ACC_PRIVATE);
+ INIT_CLASS_ENTRY(ce, "CompileError", NULL);
+ zend_ce_compile_error = zend_register_internal_class_ex(&ce, zend_ce_error);
+ zend_ce_compile_error->create_object = zend_default_exception_new;
+
INIT_CLASS_ENTRY(ce, "ParseError", NULL);
- zend_ce_parse_error = zend_register_internal_class_ex(&ce, zend_ce_error);
+ zend_ce_parse_error = zend_register_internal_class_ex(&ce, zend_ce_compile_error);
zend_ce_parse_error->create_object = zend_default_exception_new;
INIT_CLASS_ENTRY(ce, "TypeError", NULL);
ZVAL_OBJ(&exception, ex);
ce_exception = Z_OBJCE(exception);
EG(exception) = NULL;
- if (ce_exception == zend_ce_parse_error) {
+ if (ce_exception == zend_ce_parse_error || ce_exception == zend_ce_compile_error) {
zend_string *message = zval_get_string(GET_PROPERTY(&exception, ZEND_STR_MESSAGE));
zend_string *file = zval_get_string(GET_PROPERTY_SILENT(&exception, ZEND_STR_FILE));
zend_long line = zval_get_long(GET_PROPERTY_SILENT(&exception, ZEND_STR_LINE));
- zend_error_helper(E_PARSE, ZSTR_VAL(file), line, "%s", ZSTR_VAL(message));
+ zend_error_helper(ce_exception == zend_ce_parse_error ? E_PARSE : E_COMPILE_ERROR,
+ ZSTR_VAL(file), line, "%s", ZSTR_VAL(message));
zend_string_release_ex(file, 0);
zend_string_release_ex(message, 0);
extern ZEND_API zend_class_entry *zend_ce_exception;
extern ZEND_API zend_class_entry *zend_ce_error_exception;
extern ZEND_API zend_class_entry *zend_ce_error;
+extern ZEND_API zend_class_entry *zend_ce_compile_error;
extern ZEND_API zend_class_entry *zend_ce_parse_error;
extern ZEND_API zend_class_entry *zend_ce_type_error;
extern ZEND_API zend_class_entry *zend_ce_argument_count_error;
#include "zend_API.h"
#include "zend_constants.h"
#include "zend_language_scanner.h"
+#include "zend_exceptions.h"
#define YYSIZE_T size_t
#define yytnamerr zend_yytnamerr
| trait_declaration_statement { $$ = $1; }
| interface_declaration_statement { $$ = $1; }
| T_HALT_COMPILER '(' ')' ';'
- { $$ = NULL; zend_error_noreturn(E_COMPILE_ERROR,
- "__HALT_COMPILER() can only be used from the outermost scope"); }
+ { $$ = NULL; zend_throw_exception(zend_ce_compile_error,
+ "__HALT_COMPILER() can only be used from the outermost scope", 0); YYERROR; }
;
foreach_statement
{ $$ = zend_ast_create(ZEND_AST_FOREACH, $3, $7, $5, $9); }
| T_DECLARE '(' const_list ')'
- { zend_handle_encoding_declaration($3); }
+ { if (!zend_handle_encoding_declaration($3)) { YYERROR; } }
declare_statement
{ $$ = zend_ast_create(ZEND_AST_DECLARE, $3, $6); }
| ';' /* empty statement */ { $$ = NULL; }
class_modifiers:
class_modifier { $$ = $1; }
- | class_modifiers class_modifier { $$ = zend_add_class_modifier($1, $2); }
+ | class_modifiers class_modifier
+ { $$ = zend_add_class_modifier($1, $2); if (!$$) { YYERROR; } }
;
class_modifier:
non_empty_member_modifiers:
member_modifier { $$ = $1; }
| non_empty_member_modifiers member_modifier
- { $$ = zend_add_member_modifier($1, $2); }
+ { $$ = zend_add_member_modifier($1, $2); if (!$$) { YYERROR; } }
;
member_modifier: