summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Zend/tests/bug30922.phpt2
-rw-r--r--Zend/tests/type_declarations/variance/unlinked_parent_1.phpt15
-rw-r--r--Zend/tests/type_declarations/variance/unlinked_parent_2.phpt15
-rw-r--r--Zend/zend_compile.h6
-rw-r--r--Zend/zend_execute_API.c8
-rw-r--r--Zend/zend_inheritance.c10
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);