[prev in list] [next in list] [prev in thread] [next in thread] 

List:       php-cvs
Subject:    [PHP-CVS] com php-src: Disallow self etc outside classes at compile-time: =?UTF-8?Q?Zend/tests/class
From:       Nikita Popov <nikic () php ! net>
Date:       2015-04-29 18:51:08
Message-ID: php-mail-392806c92ac2e3fed1aec60fe5a3e2381031094972 () git ! php ! net
[Download RAW message or body]

Commit:    16a9bc1ec20533c76ba992bfc64dd69e7b7d9001
Author:    Nikita Popov <nikic@php.net>         Mon, 27 Apr 2015 21:14:58 +0200
Parents:   d880ead8a733202be2f74228339390e81ab824b5
Branches:  master

Link:       http://git.php.net/?p=php-src.git;a=commitdiff;h=16a9bc1ec20533c76ba992bfc64dd69e7b7d9001

Log:
Disallow self etc outside classes at compile-time

Also fix a bug with return types where "self" was rejected inside
a class, but not on a method.

Fallout: A couple of tests changed to more generic error messages.

Changed paths:
  M  Zend/tests/class_name_as_scalar_error_005.phpt
  M  Zend/tests/class_name_as_scalar_error_006.phpt
  M  Zend/tests/class_name_as_scalar_error_007.phpt
  M  Zend/tests/return_types/024.phpt
  M  Zend/tests/return_types/025.phpt
  M  Zend/tests/return_types/026.phpt
  M  Zend/tests/return_types/027.phpt
  M  Zend/tests/self_class_const_outside_class.phpt
  A  Zend/tests/typehints/self_on_closure_in_method.phpt
  M  Zend/zend_compile.c


["diff_16a9bc1ec20533c76ba992bfc64dd69e7b7d9001.txt" (text/plain)]

diff --git a/Zend/tests/class_name_as_scalar_error_005.phpt \
b/Zend/tests/class_name_as_scalar_error_005.phpt index 39de69f..27700fd 100644
--- a/Zend/tests/class_name_as_scalar_error_005.phpt
+++ b/Zend/tests/class_name_as_scalar_error_005.phpt
@@ -7,4 +7,4 @@ $x = static::class;
 
 ?>
 --EXPECTF--
-Fatal error: Cannot access static::class when no class scope is active in %s on line \
%d \ No newline at end of file
+Fatal error: Cannot use "static" when no class scope is active in %s on line 3
diff --git a/Zend/tests/class_name_as_scalar_error_006.phpt \
b/Zend/tests/class_name_as_scalar_error_006.phpt index a4cc9a5..a1078d0 100644
--- a/Zend/tests/class_name_as_scalar_error_006.phpt
+++ b/Zend/tests/class_name_as_scalar_error_006.phpt
@@ -7,4 +7,4 @@ $x = parent::class;
 
 ?>
 --EXPECTF--
-Fatal error: Cannot access parent::class when no class scope is active in %s on line \
%d +Fatal error: Cannot use "parent" when no class scope is active in %s on line 3
diff --git a/Zend/tests/class_name_as_scalar_error_007.phpt \
b/Zend/tests/class_name_as_scalar_error_007.phpt index 2bfa5f3..684470d 100644
--- a/Zend/tests/class_name_as_scalar_error_007.phpt
+++ b/Zend/tests/class_name_as_scalar_error_007.phpt
@@ -7,4 +7,4 @@ var_dump(self::class);
 
 ?>
 --EXPECTF--
-Fatal error: Cannot access self::class when no class scope is active in %s on line \
%d +Fatal error: Cannot use "self" when no class scope is active in %s on line 3
diff --git a/Zend/tests/return_types/024.phpt b/Zend/tests/return_types/024.phpt
index 9f2691f..0579973 100644
--- a/Zend/tests/return_types/024.phpt
+++ b/Zend/tests/return_types/024.phpt
@@ -7,4 +7,4 @@ Return type of self is not allowed in function
 function test(): self {}
 
 --EXPECTF--
-Fatal error: Cannot declare a return type of self outside of a class scope in %s on \
line 3 +Fatal error: Cannot use "self" when no class scope is active in %s on line 3
diff --git a/Zend/tests/return_types/025.phpt b/Zend/tests/return_types/025.phpt
index 650fb08..16a608b 100644
--- a/Zend/tests/return_types/025.phpt
+++ b/Zend/tests/return_types/025.phpt
@@ -7,4 +7,4 @@ Return type of self is not allowed in closure
 $c = function(): self {};
 
 --EXPECTF--
-Fatal error: Cannot declare a return type of self outside of a class scope in %s on \
line 3 +Fatal error: Cannot use "self" when no class scope is active in %s on line 3
diff --git a/Zend/tests/return_types/026.phpt b/Zend/tests/return_types/026.phpt
index 44ae82a..5693e95 100644
--- a/Zend/tests/return_types/026.phpt
+++ b/Zend/tests/return_types/026.phpt
@@ -6,4 +6,4 @@ Return type of parent is not allowed in function
 function test(): parent {}
 
 --EXPECTF--
-Fatal error: Cannot declare a return type of parent outside of a class scope in %s \
on line 3 +Fatal error: Cannot use "parent" when no class scope is active in %s on \
                line %d
diff --git a/Zend/tests/return_types/027.phpt b/Zend/tests/return_types/027.phpt
index 4d615b4..1abc7f7 100644
--- a/Zend/tests/return_types/027.phpt
+++ b/Zend/tests/return_types/027.phpt
@@ -6,4 +6,4 @@ Return type of parent is not allowed in closure
 $c = function(): parent {};
 
 --EXPECTF--
-Fatal error: Cannot declare a return type of parent outside of a class scope in %s \
on line 3 +Fatal error: Cannot use "parent" when no class scope is active in %s on \
                line 3
diff --git a/Zend/tests/self_class_const_outside_class.phpt \
b/Zend/tests/self_class_const_outside_class.phpt index 0ef03c2..541f3da 100644
--- a/Zend/tests/self_class_const_outside_class.phpt
+++ b/Zend/tests/self_class_const_outside_class.phpt
@@ -5,4 +5,4 @@ Accessing self::FOO outside a class
 var_dump(self::FOO);
 ?>
 --EXPECTF--
-Fatal error: Cannot access self:: when no class scope is active in %s on line %d
+Fatal error: Cannot use "self" when no class scope is active in %s on line %d
diff --git a/Zend/tests/typehints/self_on_closure_in_method.phpt \
b/Zend/tests/typehints/self_on_closure_in_method.phpt new file mode 100644
index 0000000..2d5bd82
--- /dev/null
+++ b/Zend/tests/typehints/self_on_closure_in_method.phpt
@@ -0,0 +1,19 @@
+--TEST--
+self return type on closure in a method
+--FILE--
+<?php
+
+class A {
+    public function test() {
+        return function() : self {
+            return $this;
+        };
+    }
+}
+
+var_dump((new A)->test()());
+
+?>
+--EXPECT--
+object(A)#1 (0) {
+}
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index d4a9df3..c92a25a 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -1612,6 +1612,27 @@ uint32_t zend_get_class_fetch_type(zend_string *name) /* {{{ \
*/  }
 /* }}} */
 
+static uint32_t zend_get_class_fetch_type_ast(zend_ast *name_ast) /* {{{ */
+{
+	/* Fully qualified names are always default refs */
+	if (name_ast->attr == ZEND_NAME_FQ) {
+		return ZEND_FETCH_CLASS_DEFAULT;
+	}
+
+	return zend_get_class_fetch_type(zend_ast_get_str(name_ast));
+}
+/* }}} */
+
+void zend_ensure_valid_class_fetch_type(uint32_t fetch_type) /* {{{ */
+{
+	if (fetch_type != ZEND_FETCH_CLASS_DEFAULT && !CG(active_class_entry)) {
+		zend_error_noreturn(E_COMPILE_ERROR, "Cannot use \"%s\" when no class scope is \
active", +			fetch_type == ZEND_FETCH_CLASS_SELF ? "self" :
+			fetch_type == ZEND_FETCH_CLASS_PARENT ? "parent" : "static");
+	}
+}
+/* }}} */
+
 ZEND_API zend_string *zend_get_compiled_variable_name(const zend_op_array *op_array, \
uint32_t var) /* {{{ */  {
 	return op_array->vars[EX_VAR_TO_NUM(var)];
@@ -2018,19 +2039,11 @@ static inline zend_bool zend_can_write_to_variable(zend_ast \
*ast) /* {{{ */  
 static inline zend_bool zend_is_const_default_class_ref(zend_ast *name_ast) /* {{{ \
*/  {
-	zend_string *name;
-
 	if (name_ast->kind != ZEND_AST_ZVAL) {
 		return 0;
 	}
 
-	/* Fully qualified names are always default refs */
-	if (!name_ast->attr) {
-		return 1;
-	}
-
-	name = zend_ast_get_str(name_ast);
-	return ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(name);
+	return ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type_ast(name_ast);
 }
 /* }}} */
 
@@ -2077,6 +2090,8 @@ static zend_op *zend_compile_class_ref(znode *result, zend_ast \
*name_ast, int th  opline->op2_type = IS_CONST;
 			opline->op2.constant = zend_add_class_name_literal(CG(active_op_array),
 				zend_resolve_class_name(name, type));
+		} else {
+			zend_ensure_valid_class_fetch_type(fetch_type);
 		}
 
 		zend_string_release(name);
@@ -4147,7 +4162,7 @@ ZEND_API void zend_set_function_arg_flags(zend_function *func) \
/* {{{ */  }
 /* }}} */
 
-void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, zend_bool \
is_method) /* {{{ */ +void zend_compile_params(zend_ast *ast, zend_ast \
*return_type_ast) /* {{{ */  {
 	zend_ast_list *list = zend_ast_get_list(ast);
 	uint32_t i;
@@ -4173,15 +4188,13 @@ void zend_compile_params(zend_ast *ast, zend_ast \
*return_type_ast, zend_bool is_  if (type != 0) {
 				arg_infos->type_hint = type;
 			} else {
-				if (zend_is_const_default_class_ref(return_type_ast)) {
+				uint32_t fetch_type = zend_get_class_fetch_type_ast(return_type_ast);
+				if (fetch_type == ZEND_FETCH_CLASS_DEFAULT) {
 					class_name = zend_resolve_class_name_ast(return_type_ast);
 					zend_assert_valid_class_name(class_name);
 				} else {
+					zend_ensure_valid_class_fetch_type(fetch_type);
 					zend_string_addref(class_name);
-					if (!is_method) {
-						zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare a return type of %s \
                outside of a class scope", class_name->val);
-						return;
-					}
 				}
 
 				arg_infos->type_hint = IS_OBJECT;
@@ -4302,10 +4315,12 @@ void zend_compile_params(zend_ast *ast, zend_ast \
*return_type_ast, zend_bool is_  if (type != 0) {
 					arg_info->type_hint = type;
 				} else {
-					if (zend_is_const_default_class_ref(type_ast)) {
+					uint32_t fetch_type = zend_get_class_fetch_type_ast(type_ast);
+					if (fetch_type == ZEND_FETCH_CLASS_DEFAULT) {
 						class_name = zend_resolve_class_name_ast(type_ast);
 						zend_assert_valid_class_name(class_name);
 					} else {
+						zend_ensure_valid_class_fetch_type(fetch_type);
 						zend_string_addref(class_name);
 					}
 
@@ -4626,7 +4641,7 @@ void zend_compile_func_decl(znode *result, zend_ast *ast) /* \
{{{ */  zend_stack_push(&CG(loop_var_stack), (void *) &dummy_var);
 	}
 
-	zend_compile_params(params_ast, return_type_ast, is_method);
+	zend_compile_params(params_ast, return_type_ast);
 	if (uses_ast) {
 		zend_compile_closure_uses(uses_ast);
 	}
@@ -6329,13 +6344,10 @@ void zend_compile_resolve_class_name(znode *result, zend_ast \
*ast) /* {{{ */  {
 	zend_ast *name_ast = ast->child[0];
 	uint32_t fetch_type = zend_get_class_fetch_type(zend_ast_get_str(name_ast));
+	zend_ensure_valid_class_fetch_type(fetch_type);
 
 	switch (fetch_type) {
 		case ZEND_FETCH_CLASS_SELF:
-			if (!CG(active_class_entry)) {
-				zend_error_noreturn(E_COMPILE_ERROR,
-					"Cannot access self::class when no class scope is active");
-			}
 			if (CG(active_class_entry)->ce_flags & ZEND_ACC_TRAIT) {
 				zval class_str_zv;
 				zend_ast *class_str_ast, *class_const_ast;
@@ -6354,11 +6366,7 @@ void zend_compile_resolve_class_name(znode *result, zend_ast \
*ast) /* {{{ */  break;
 		case ZEND_FETCH_CLASS_STATIC:
 		case ZEND_FETCH_CLASS_PARENT:
-			if (!CG(active_class_entry)) {
-				zend_error_noreturn(E_COMPILE_ERROR,
-					"Cannot access %s::class when no class scope is active",
-					fetch_type == ZEND_FETCH_CLASS_STATIC ? "static" : "parent");
-			} else {
+			{
 				zval class_str_zv;
 				zend_ast *class_str_ast, *class_const_ast;
 
@@ -6611,15 +6619,12 @@ void zend_compile_const_expr_resolve_class_name(zend_ast \
**ast_ptr) /* {{{ */  {
 	zend_ast *ast = *ast_ptr;
 	zend_ast *name_ast = ast->child[0];
-	uint32_t fetch_type = zend_get_class_fetch_type(zend_ast_get_str(name_ast));
 	zval result;
+	uint32_t fetch_type = zend_get_class_fetch_type(zend_ast_get_str(name_ast));
+	zend_ensure_valid_class_fetch_type(fetch_type);
 
 	switch (fetch_type) {
 		case ZEND_FETCH_CLASS_SELF:
-			if (!CG(active_class_entry)) {
-				zend_error_noreturn(E_COMPILE_ERROR,
-					"Cannot access self::class when no class scope is active");
-			}
 			ZVAL_STR_COPY(&result, CG(active_class_entry)->name);
 			break;
         case ZEND_FETCH_CLASS_STATIC:



-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic