Skip to content

Commit c5f93d1

Browse files
committed
Fix detection of code outside namespace
Due to improvements to early binding, the opcode based check is no longer accurate. Reuse the syntactic check we're already using for declares instead.
1 parent ef9ab91 commit c5f93d1

File tree

4 files changed

+36
-29
lines changed

4 files changed

+36
-29
lines changed

Zend/tests/attributes/004_name_resolution.phpt

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@
22
Resolve attribute names
33
--FILE--
44
<?php
5-
function dump_attributes($attributes) {
6-
$arr = [];
7-
foreach ($attributes as $attribute) {
8-
$arr[] = ['name' => $attribute->getName(), 'args' => $attribute->getArguments()];
5+
6+
namespace {
7+
function dump_attributes($attributes) {
8+
$arr = [];
9+
foreach ($attributes as $attribute) {
10+
$arr[] = ['name' => $attribute->getName(), 'args' => $attribute->getArguments()];
11+
}
12+
var_dump($arr);
913
}
10-
var_dump($arr);
1114
}
1215

1316
namespace Doctrine\ORM\Mapping {
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
--TEST--
2+
Function declaration should not be allowed before namespace declaration
3+
--FILE--
4+
<?php
5+
6+
function foo() {}
7+
8+
namespace Bar;
9+
10+
?>
11+
--EXPECTF--
12+
Fatal error: Namespace declaration statement has to be the very first statement or after any declare call in the script in %s on line %d

Zend/tests/type_declarations/confusable_type_warning.phpt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ Warnings for confusable types
33
--FILE--
44
<?php
55

6-
function test1(integer $x) {}
7-
function test2(double $x) {}
8-
function test3(boolean $x) {}
9-
function test4(resource $x) {}
6+
namespace {
7+
function test1(integer $x) {}
8+
function test2(double $x) {}
9+
function test3(boolean $x) {}
10+
function test4(resource $x) {}
11+
}
1012

1113
namespace Foo {
1214
use integer as foo;

Zend/zend_compile.c

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5864,20 +5864,19 @@ zend_bool zend_handle_encoding_declaration(zend_ast *ast) /* {{{ */
58645864
}
58655865
/* }}} */
58665866

5867-
static zend_result zend_declare_is_first_statement(zend_ast *ast) /* {{{ */
5867+
/* Check whether this is the first statement, not counting declares. */
5868+
static zend_result zend_is_first_statement(zend_ast *ast) /* {{{ */
58685869
{
58695870
uint32_t i = 0;
58705871
zend_ast_list *file_ast = zend_ast_get_list(CG(ast));
58715872

5872-
/* Check to see if this declare is preceded only by declare statements */
58735873
while (i < file_ast->children) {
58745874
if (file_ast->child[i] == ast) {
58755875
return SUCCESS;
58765876
} else if (file_ast->child[i] == NULL) {
5877-
/* Empty statements are not allowed prior to a declare */
5877+
/* Empty statements count as statements. */
58785878
return FAILURE;
58795879
} else if (file_ast->child[i]->kind != ZEND_AST_DECLARE) {
5880-
/* declares can only be preceded by other declares */
58815880
return FAILURE;
58825881
}
58835882
i++;
@@ -5910,14 +5909,14 @@ void zend_compile_declare(zend_ast *ast) /* {{{ */
59105909
zval_ptr_dtor_nogc(&value_zv);
59115910
} else if (zend_string_equals_literal_ci(name, "encoding")) {
59125911

5913-
if (FAILURE == zend_declare_is_first_statement(ast)) {
5912+
if (FAILURE == zend_is_first_statement(ast)) {
59145913
zend_error_noreturn(E_COMPILE_ERROR, "Encoding declaration pragma must be "
59155914
"the very first statement in the script");
59165915
}
59175916
} else if (zend_string_equals_literal_ci(name, "strict_types")) {
59185917
zval value_zv;
59195918

5920-
if (FAILURE == zend_declare_is_first_statement(ast)) {
5919+
if (FAILURE == zend_is_first_statement(ast)) {
59215920
zend_error_noreturn(E_COMPILE_ERROR, "strict_types declaration must be "
59225921
"the very first statement in the script");
59235922
}
@@ -7682,20 +7681,11 @@ void zend_compile_namespace(zend_ast *ast) /* {{{ */
76827681
}
76837682
}
76847683

7685-
if (((!with_bracket && !FC(current_namespace))
7686-
|| (with_bracket && !FC(has_bracketed_namespaces))) && CG(active_op_array)->last > 0
7687-
) {
7688-
/* ignore ZEND_EXT_STMT and ZEND_TICKS */
7689-
uint32_t num = CG(active_op_array)->last;
7690-
while (num > 0 &&
7691-
(CG(active_op_array)->opcodes[num-1].opcode == ZEND_EXT_STMT ||
7692-
CG(active_op_array)->opcodes[num-1].opcode == ZEND_TICKS)) {
7693-
--num;
7694-
}
7695-
if (num > 0) {
7696-
zend_error_noreturn(E_COMPILE_ERROR, "Namespace declaration statement has to be "
7697-
"the very first statement or after any declare call in the script");
7698-
}
7684+
zend_bool is_first_namespace = (!with_bracket && !FC(current_namespace))
7685+
|| (with_bracket && !FC(has_bracketed_namespaces));
7686+
if (is_first_namespace && FAILURE == zend_is_first_statement(ast)) {
7687+
zend_error_noreturn(E_COMPILE_ERROR, "Namespace declaration statement has to be "
7688+
"the very first statement or after any declare call in the script");
76997689
}
77007690

77017691
if (FC(current_namespace)) {

0 commit comments

Comments
 (0)