Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions compiler/pipes/calc-func-dep.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ VertexPtr CalcFuncDepPass::on_enter_vertex(VertexPtr vertex) {
}

if (auto instanceof = vertex.try_as<op_instanceof>()) {
// mark_as_used() is required here for the same reason as in op_catch below:
// a class used only in instanceof may never be instantiated elsewhere,
// so without this call the code-gen pass would crash trying to include
// a header that was never generated (see #68)
instanceof->derived_class->mark_as_used();
current_function->class_dep.insert(instanceof->derived_class);
}

Expand Down
22 changes: 22 additions & 0 deletions tests/phpt/interfaces/135_instanceof_unused_class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
@ok
<?php

// Regression test for https://github.com/VKCOM/kphp/issues/68
// A class that appears only inside instanceof (never directly instantiated)
// must compile without crashing with "Can't find header".

class Bar {}
class Foo extends Bar {}

function check_foo(Bar $obj): bool {
return $obj instanceof Foo;
}

// Foo is never instantiated — only used in instanceof.
// Before the fix, kphp crashed trying to include cl/C@Foo.h
// which was never generated because Foo was never mark_as_used().
$bar = new Bar();
var_dump(check_foo($bar)); // bool(false)

$foo = new Foo();
var_dump(check_foo($foo)); // bool(true)
30 changes: 30 additions & 0 deletions tests/phpt/interfaces/136_instanceof_only_in_condition.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
@ok
<?php

// Additional regression for #68: instanceof with a class that is
// referenced nowhere else in the translation unit.

interface Shape {}

class Circle implements Shape {
public float $radius;
public function __construct(float $r) { $this->radius = $r; }
}

class Square implements Shape {
public float $side;
public function __construct(float $s) { $this->side = $s; }
}

// Triangle is declared but never instantiated — only appears in instanceof.
class Triangle implements Shape {}

function describe(Shape $s): string {
if ($s instanceof Circle) return 'circle';
if ($s instanceof Square) return 'square';
if ($s instanceof Triangle) return 'triangle'; // Triangle: only in instanceof
return 'unknown';
}

var_dump(describe(new Circle(1.0))); // string(6) "circle"
var_dump(describe(new Square(2.0))); // string(6) "square"