From 53a40386bc81da824468ac3aa8b1962ab7029238 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Mon, 30 Mar 2015 22:05:26 +0200 Subject: [PATCH] Implement additional type reservations * The class names false, true and null are now reserved. * The code dealing with reserved class names is now decoupled from scalar type hint handling. It also includes self, parent, and static, which are class names which were already reserved previously. * Reuse existing messages for reserved class names. Fallout: class_alias() can no longer alias self, parent and static. However this never really worked in the first place, as the test which was testing this shows. --- Zend/tests/class_alias_003.phpt | 22 ---- .../scalar_relative_typehint_disallowed.phpt | 2 +- Zend/tests/typehints/scalar_reserved2.phpt | 2 +- .../scalar_reserved2_class_alias.phpt | 2 +- .../tests/typehints/scalar_reserved2_use.phpt | 2 +- Zend/tests/typehints/scalar_reserved3.phpt | 2 +- .../scalar_reserved3_class_alias.phpt | 2 +- .../tests/typehints/scalar_reserved3_use.phpt | 2 +- Zend/tests/typehints/scalar_reserved4.phpt | 2 +- .../scalar_reserved4_class_alias.phpt | 2 +- .../tests/typehints/scalar_reserved4_use.phpt | 2 +- Zend/tests/typehints/scalar_reserved6.phpt | 2 +- .../scalar_reserved6_class_alias.phpt | 2 +- .../tests/typehints/scalar_reserved6_use.phpt | 2 +- Zend/tests/typehints/scalar_reserved7.phpt | 2 +- Zend/zend_compile.c | 102 ++++++++++-------- 16 files changed, 72 insertions(+), 80 deletions(-) delete mode 100644 Zend/tests/class_alias_003.phpt diff --git a/Zend/tests/class_alias_003.phpt b/Zend/tests/class_alias_003.phpt deleted file mode 100644 index 57e2fd572e6..00000000000 --- a/Zend/tests/class_alias_003.phpt +++ /dev/null @@ -1,22 +0,0 @@ ---TEST-- -Testing declaration of alias to 'static' ---FILE-- -test()); - -?> ---EXPECTF-- -object(foo)#%d (0) { -} diff --git a/Zend/tests/typehints/scalar_relative_typehint_disallowed.phpt b/Zend/tests/typehints/scalar_relative_typehint_disallowed.phpt index 30d2bd8b745..d85091253c0 100644 --- a/Zend/tests/typehints/scalar_relative_typehint_disallowed.phpt +++ b/Zend/tests/typehints/scalar_relative_typehint_disallowed.phpt @@ -11,4 +11,4 @@ foo(10); ?> --EXPECTF-- -Fatal error: "bar\int" cannot be used as a type declaration in %s on line %d \ No newline at end of file +Fatal error: Cannot use 'bar\int' as class name as it is reserved in %s on line %d diff --git a/Zend/tests/typehints/scalar_reserved2.phpt b/Zend/tests/typehints/scalar_reserved2.phpt index 8ed41024974..01f36fd1543 100644 --- a/Zend/tests/typehints/scalar_reserved2.phpt +++ b/Zend/tests/typehints/scalar_reserved2.phpt @@ -5,4 +5,4 @@ Scalar type hint names cannot be used as class, trait or interface names (2) class int {} --EXPECTF-- -Fatal error: "int" cannot be used as a class name in %s on line %d +Fatal error: Cannot use 'int' as class name as it is reserved in %s on line %d diff --git a/Zend/tests/typehints/scalar_reserved2_class_alias.phpt b/Zend/tests/typehints/scalar_reserved2_class_alias.phpt index 2348f76df8f..02d6bb4a832 100644 --- a/Zend/tests/typehints/scalar_reserved2_class_alias.phpt +++ b/Zend/tests/typehints/scalar_reserved2_class_alias.phpt @@ -6,4 +6,4 @@ Scalar type hint names cannot be used as class, trait or interface names (2) - c class foobar {} class_alias("foobar", "int"); --EXPECTF-- -Fatal error: "int" cannot be used as a class name in %s on line %d +Fatal error: Cannot use 'int' as class name as it is reserved in %s on line %d diff --git a/Zend/tests/typehints/scalar_reserved2_use.phpt b/Zend/tests/typehints/scalar_reserved2_use.phpt index b7a1baed36b..e61db5c87a8 100644 --- a/Zend/tests/typehints/scalar_reserved2_use.phpt +++ b/Zend/tests/typehints/scalar_reserved2_use.phpt @@ -5,4 +5,4 @@ Scalar type hint names cannot be used as class, trait or interface names (2) - u use foobar as int; --EXPECTF-- -Fatal error: "int" cannot be used as a class name in %s on line %d +Fatal error: Cannot use foobar as int because 'int' is a special class name in %s on line %d diff --git a/Zend/tests/typehints/scalar_reserved3.phpt b/Zend/tests/typehints/scalar_reserved3.phpt index 00750955b72..425365bc65a 100644 --- a/Zend/tests/typehints/scalar_reserved3.phpt +++ b/Zend/tests/typehints/scalar_reserved3.phpt @@ -5,4 +5,4 @@ Scalar type hint names cannot be used as class, trait or interface names (3) class float {} --EXPECTF-- -Fatal error: "float" cannot be used as a class name in %s on line %d +Fatal error: Cannot use 'float' as class name as it is reserved in %s on line %d diff --git a/Zend/tests/typehints/scalar_reserved3_class_alias.phpt b/Zend/tests/typehints/scalar_reserved3_class_alias.phpt index 05438b579cf..39c2e2a62c1 100644 --- a/Zend/tests/typehints/scalar_reserved3_class_alias.phpt +++ b/Zend/tests/typehints/scalar_reserved3_class_alias.phpt @@ -6,4 +6,4 @@ Scalar type hint names cannot be used as class, trait or interface names (3) - c class foobar {} class_alias("foobar", "float"); --EXPECTF-- -Fatal error: "float" cannot be used as a class name in %s on line %d +Fatal error: Cannot use 'float' as class name as it is reserved in %s on line %d diff --git a/Zend/tests/typehints/scalar_reserved3_use.phpt b/Zend/tests/typehints/scalar_reserved3_use.phpt index 6f52e060fff..23be15e1a3b 100644 --- a/Zend/tests/typehints/scalar_reserved3_use.phpt +++ b/Zend/tests/typehints/scalar_reserved3_use.phpt @@ -5,4 +5,4 @@ Scalar type hint names cannot be used as class, trait or interface names (3) - u use foobar as float; --EXPECTF-- -Fatal error: "float" cannot be used as a class name in %s on line %d +Fatal error: Cannot use foobar as float because 'float' is a special class name in %s on line %d diff --git a/Zend/tests/typehints/scalar_reserved4.phpt b/Zend/tests/typehints/scalar_reserved4.phpt index 2e92514b8bb..5a190ce51a9 100644 --- a/Zend/tests/typehints/scalar_reserved4.phpt +++ b/Zend/tests/typehints/scalar_reserved4.phpt @@ -5,4 +5,4 @@ Scalar type hint names cannot be used as class, trait or interface names (4) class string {} --EXPECTF-- -Fatal error: "string" cannot be used as a class name in %s on line %d +Fatal error: Cannot use 'string' as class name as it is reserved in %s on line %d diff --git a/Zend/tests/typehints/scalar_reserved4_class_alias.phpt b/Zend/tests/typehints/scalar_reserved4_class_alias.phpt index ff7c6adc79b..ffaf934a012 100644 --- a/Zend/tests/typehints/scalar_reserved4_class_alias.phpt +++ b/Zend/tests/typehints/scalar_reserved4_class_alias.phpt @@ -6,4 +6,4 @@ Scalar type hint names cannot be used as class, trait or interface names (4) - c class foobar {} class_alias("foobar", "string"); --EXPECTF-- -Fatal error: "string" cannot be used as a class name in %s on line %d +Fatal error: Cannot use 'string' as class name as it is reserved in %s on line %d diff --git a/Zend/tests/typehints/scalar_reserved4_use.phpt b/Zend/tests/typehints/scalar_reserved4_use.phpt index 1d7e4039d8c..05a2ea1069a 100644 --- a/Zend/tests/typehints/scalar_reserved4_use.phpt +++ b/Zend/tests/typehints/scalar_reserved4_use.phpt @@ -5,4 +5,4 @@ Scalar type hint names cannot be used as class, trait or interface names (4) - u use foobar as string; --EXPECTF-- -Fatal error: "string" cannot be used as a class name in %s on line %d +Fatal error: Cannot use foobar as string because 'string' is a special class name in %s on line %d diff --git a/Zend/tests/typehints/scalar_reserved6.phpt b/Zend/tests/typehints/scalar_reserved6.phpt index 46b8c730e9e..1dee41ff584 100644 --- a/Zend/tests/typehints/scalar_reserved6.phpt +++ b/Zend/tests/typehints/scalar_reserved6.phpt @@ -5,4 +5,4 @@ Scalar type hint names cannot be used as class, trait or interface names (6) class bool {} --EXPECTF-- -Fatal error: "bool" cannot be used as a class name in %s on line %d +Fatal error: Cannot use 'bool' as class name as it is reserved in %s on line %d diff --git a/Zend/tests/typehints/scalar_reserved6_class_alias.phpt b/Zend/tests/typehints/scalar_reserved6_class_alias.phpt index 4a4c824eb63..fd3c328504d 100644 --- a/Zend/tests/typehints/scalar_reserved6_class_alias.phpt +++ b/Zend/tests/typehints/scalar_reserved6_class_alias.phpt @@ -6,4 +6,4 @@ Scalar type hint names cannot be used as class, trait or interface names (6) - c class foobar {} class_alias("foobar", "bool"); --EXPECTF-- -Fatal error: "bool" cannot be used as a class name in %s on line %d +Fatal error: Cannot use 'bool' as class name as it is reserved in %s on line %d diff --git a/Zend/tests/typehints/scalar_reserved6_use.phpt b/Zend/tests/typehints/scalar_reserved6_use.phpt index 6a6cb7a34c2..9cb7857a50b 100644 --- a/Zend/tests/typehints/scalar_reserved6_use.phpt +++ b/Zend/tests/typehints/scalar_reserved6_use.phpt @@ -5,4 +5,4 @@ Scalar type hint names cannot be used as class, trait or interface names (6) - u use foobar as bool; --EXPECTF-- -Fatal error: "bool" cannot be used as a class name in %s on line %d +Fatal error: Cannot use foobar as bool because 'bool' is a special class name in %s on line %d diff --git a/Zend/tests/typehints/scalar_reserved7.phpt b/Zend/tests/typehints/scalar_reserved7.phpt index 330235d9dbc..d641d178d16 100644 --- a/Zend/tests/typehints/scalar_reserved7.phpt +++ b/Zend/tests/typehints/scalar_reserved7.phpt @@ -6,4 +6,4 @@ namespace foo; class int {} --EXPECTF-- -Fatal error: "int" cannot be used as a class name in %s on line %d +Fatal error: Cannot use 'int' as class name as it is reserved in %s on line %d diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 9d5bd0f1f15..2a76ff39e66 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -129,6 +129,53 @@ static zend_bool zend_get_unqualified_name(const zend_string *name, const char * } /* }}} */ +struct reserved_class_name { + const char *name; + size_t len; +}; +static const struct reserved_class_name reserved_class_names[] = { + {ZEND_STRL("bool")}, + {ZEND_STRL("false")}, + {ZEND_STRL("float")}, + {ZEND_STRL("int")}, + {ZEND_STRL("null")}, + {ZEND_STRL("parent")}, + {ZEND_STRL("self")}, + {ZEND_STRL("static")}, + {ZEND_STRL("string")}, + {ZEND_STRL("true")}, + {NULL, 0} +}; + +static zend_bool zend_is_reserved_class_name(const zend_string *name) /* {{{ */ +{ + const struct reserved_class_name *reserved = reserved_class_names; + + const char *uqname = name->val; + size_t uqname_len = name->len; + zend_get_unqualified_name(name, &uqname, &uqname_len); + + for (; reserved->name; ++reserved) { + if (uqname_len == reserved->len + && zend_binary_strcasecmp(uqname, uqname_len, reserved->name, reserved->len) == 0 + ) { + return 1; + } + } + + return 0; +} +/* }}} */ + +ZEND_API void zend_assert_valid_class_name(const zend_string *name) /* {{{ */ +{ + if (zend_is_reserved_class_name(name)) { + zend_error_noreturn(E_COMPILE_ERROR, + "Cannot use '%s' as class name as it is reserved", name->val); + } +} +/* }}} */ + typedef struct _scalar_typehint_info { const char* name; const size_t name_len; @@ -143,39 +190,19 @@ static const scalar_typehint_info scalar_typehints[] = { {NULL, 0, IS_UNDEF} }; -static zend_always_inline const scalar_typehint_info* zend_find_scalar_typehint(const zend_string *const_name) /* {{{ */ +static zend_always_inline const scalar_typehint_info* zend_find_scalar_typehint(const zend_string *name) /* {{{ */ { const scalar_typehint_info *info = &scalar_typehints[0]; - const char *uqname; - size_t uqname_len; - if (!zend_get_unqualified_name(const_name, &uqname, &uqname_len)) { - uqname = const_name->val; - uqname_len = const_name->len; - } - - while (info->name) { - if (uqname_len == info->name_len && zend_binary_strcasecmp(uqname, uqname_len, info->name, info->name_len) == 0) { - break; + for (; info->name; ++info) { + if (name->len == info->name_len + && zend_binary_strcasecmp(name->val, name->len, info->name, info->name_len) == 0 + ) { + return info; } - info++; } - if (info->name) { - return info; - } else { - return NULL; - } -} -/* }}} */ - -ZEND_API void zend_assert_valid_class_name(const zend_string *const_name) /* {{{ */ -{ - const scalar_typehint_info *info = zend_find_scalar_typehint(const_name); - - if (info) { - zend_error_noreturn(E_COMPILE_ERROR, "\"%s\" cannot be used as a class name", info->name); - } + return NULL; } /* }}} */ @@ -184,9 +211,6 @@ static zend_always_inline zend_uchar zend_lookup_scalar_typehint_by_name(const z const scalar_typehint_info *info = zend_find_scalar_typehint(const_name); if (info) { - if (const_name->len != info->name_len) { - zend_error_noreturn(E_COMPILE_ERROR, "\"%s\" cannot be used as a type declaration", const_name->val); - } return info->type; } else { return 0; @@ -4099,6 +4123,7 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, zend_bool is_ } else { if (zend_is_const_default_class_ref(return_type_ast)) { class_name = zend_resolve_class_name_ast(return_type_ast); + zend_assert_valid_class_name(class_name); } else { zend_string_addref(class_name); if (!is_method) { @@ -4225,9 +4250,9 @@ 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)) { class_name = zend_resolve_class_name_ast(type_ast); + zend_assert_valid_class_name(class_name); } else { zend_string_addref(class_name); } @@ -4846,10 +4871,7 @@ void zend_compile_class_decl(zend_ast *ast) /* {{{ */ return; } - if (ZEND_FETCH_CLASS_DEFAULT != zend_get_class_fetch_type(name)) { - zend_error_noreturn(E_COMPILE_ERROR, "Cannot use '%s' as class name as it is reserved", - name->val); - } + zend_assert_valid_class_name(name); lcname = zend_string_tolower(name); @@ -4857,8 +4879,6 @@ void zend_compile_class_decl(zend_ast *ast) /* {{{ */ import_name = zend_hash_find_ptr(CG(current_import), lcname); } - zend_assert_valid_class_name(name); - if (CG(current_namespace)) { name = zend_prefix_with_ns(name); @@ -5094,19 +5114,13 @@ void zend_compile_use(zend_ast *ast) /* {{{ */ } } - if (type == T_CLASS) { - zend_assert_valid_class_name(new_name); - } - if (case_sensitive) { lookup_name = zend_string_copy(new_name); } else { lookup_name = zend_string_tolower(new_name); } - if (type == T_CLASS && (zend_string_equals_literal(lookup_name, "self") - || zend_string_equals_literal(lookup_name, "parent")) - ) { + if (type == T_CLASS && zend_is_reserved_class_name(new_name)) { zend_error_noreturn(E_COMPILE_ERROR, "Cannot use %s as %s because '%s' " "is a special class name", old_name->val, new_name->val, new_name->val); }