diff options
-rw-r--r-- | Zend/tests/bug30922.phpt | 2 | ||||
-rw-r--r-- | Zend/tests/type_declarations/variance/unlinked_parent_1.phpt | 15 | ||||
-rw-r--r-- | Zend/tests/type_declarations/variance/unlinked_parent_2.phpt | 15 | ||||
-rw-r--r-- | Zend/zend_compile.h | 6 | ||||
-rw-r--r-- | Zend/zend_execute_API.c | 8 | ||||
-rw-r--r-- | Zend/zend_inheritance.c | 10 |
6 files changed, 47 insertions, 9 deletions
diff --git a/Zend/tests/bug30922.phpt b/Zend/tests/bug30922.phpt index 001845a7cb..444758c903 100644 --- a/Zend/tests/bug30922.phpt +++ b/Zend/tests/bug30922.phpt @@ -10,4 +10,4 @@ var_dump($a instanceOf A); echo "ok\n"; ?> --EXPECTF-- -Fatal error: Interface RecurisiveFooFar cannot implement itself in %s on line %d +Fatal error: Interface 'RecurisiveFooFar' not found in %s on line %d diff --git a/Zend/tests/type_declarations/variance/unlinked_parent_1.phpt b/Zend/tests/type_declarations/variance/unlinked_parent_1.phpt new file mode 100644 index 0000000000..2030f3bd8b --- /dev/null +++ b/Zend/tests/type_declarations/variance/unlinked_parent_1.phpt @@ -0,0 +1,15 @@ +--TEST-- +Using an unlinked parent class +--FILE-- +<?php + +spl_autoload_register(function($class) { + class X extends B {} +}); + +class B extends A { +} + +?> +--EXPECTF-- +Fatal error: Class 'B' not found in %s on line %d diff --git a/Zend/tests/type_declarations/variance/unlinked_parent_2.phpt b/Zend/tests/type_declarations/variance/unlinked_parent_2.phpt new file mode 100644 index 0000000000..9e21f85770 --- /dev/null +++ b/Zend/tests/type_declarations/variance/unlinked_parent_2.phpt @@ -0,0 +1,15 @@ +--TEST-- +Using an unlinked parent interface +--FILE-- +<?php + +spl_autoload_register(function($class) { + class X implements B {} +}); + +interface B extends A { +} + +?> +--EXPECTF-- +Fatal error: Interface 'B' not found in %s on line %d diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 61b71cbc06..81e8e873f0 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -229,7 +229,7 @@ typedef struct _zend_oparray_context { /* op_array or class is preloaded | | | */ #define ZEND_ACC_PRELOADED (1 << 10) /* X | X | | */ /* | | | */ -/* Class Flags (unused: 22...) | | | */ +/* Class Flags (unused: 23...) | | | */ /* =========== | | | */ /* | | | */ /* Special class types | | | */ @@ -278,6 +278,9 @@ typedef struct _zend_oparray_context { /* Class has unresolved variance obligations. | | | */ #define ZEND_ACC_UNRESOLVED_VARIANCE (1 << 21) /* X | | | */ /* | | | */ +/* Class is linked apart from variance obligations. | | | */ +#define ZEND_ACC_NEARLY_LINKED (1 << 22) /* X | | | */ +/* | | | */ /* Function Flags (unused: 17, 23, 26) | | | */ /* ============== | | | */ /* | | | */ @@ -860,6 +863,7 @@ void zend_assert_valid_class_name(const zend_string *const_name); #define ZEND_FETCH_CLASS_SILENT 0x0100 #define ZEND_FETCH_CLASS_EXCEPTION 0x0200 #define ZEND_FETCH_CLASS_ALLOW_UNLINKED 0x0400 +#define ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED 0x0800 #define ZEND_PARAM_REF (1<<0) #define ZEND_PARAM_VARIADIC (1<<1) diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 7bc830da2b..7544fdb141 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -863,8 +863,12 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string * zend_string_release_ex(lc_name, 0); } ce = (zend_class_entry*)Z_PTR_P(zv); - if (UNEXPECTED(!(ce->ce_flags & ZEND_ACC_LINKED)) && - !(flags & ZEND_FETCH_CLASS_ALLOW_UNLINKED)) { + if (UNEXPECTED(!(ce->ce_flags & ZEND_ACC_LINKED))) { + if ((flags & ZEND_FETCH_CLASS_ALLOW_UNLINKED) || + ((flags & ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED) && + (ce->ce_flags & ZEND_ACC_NEARLY_LINKED))) { + return ce; + } return NULL; } return ce; diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index 6d1aef5b30..5f386f4d87 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -975,9 +975,8 @@ static inline void do_implement_interface(zend_class_entry *ce, zend_class_entry if (!(ce->ce_flags & ZEND_ACC_INTERFACE) && iface->interface_gets_implemented && iface->interface_gets_implemented(iface, ce) == FAILURE) { zend_error_noreturn(E_CORE_ERROR, "Class %s could not implement interface %s", ZSTR_VAL(ce->name), ZSTR_VAL(iface->name)); } - if (UNEXPECTED(ce == iface)) { - zend_error_noreturn(E_ERROR, "Interface %s cannot implement itself", ZSTR_VAL(ce->name)); - } + /* This should be prevented by the class lookup logic. */ + ZEND_ASSERT(ce != iface); } /* }}} */ @@ -1427,7 +1426,7 @@ static void zend_do_implement_interfaces(zend_class_entry *ce) /* {{{ */ for (i = 0; i < ce->num_interfaces; i++) { iface = zend_fetch_class_by_name( ce->interface_names[i].name, ce->interface_names[i].lc_name, - ZEND_FETCH_CLASS_INTERFACE|ZEND_FETCH_CLASS_ALLOW_UNLINKED); + ZEND_FETCH_CLASS_INTERFACE|ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED); if (!(iface->ce_flags & ZEND_ACC_LINKED)) { add_dependency_obligation(ce, iface); } @@ -2324,7 +2323,7 @@ ZEND_API void zend_do_link_class(zend_class_entry *ce, zend_string *lc_parent_na { if (ce->parent_name) { zend_class_entry *parent = zend_fetch_class_by_name( - ce->parent_name, lc_parent_name, ZEND_FETCH_CLASS_ALLOW_UNLINKED); + ce->parent_name, lc_parent_name, ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED); if (!(parent->ce_flags & ZEND_ACC_LINKED)) { add_dependency_obligation(ce, parent); } @@ -2347,6 +2346,7 @@ ZEND_API void zend_do_link_class(zend_class_entry *ce, zend_string *lc_parent_na return; } + ce->ce_flags |= ZEND_ACC_NEARLY_LINKED; load_delayed_classes(); if (ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE) { resolve_delayed_variance_obligations(ce); |