ClangPlugins: Make sure forward declared fields are visited as well

Instead of ignoring fields using forward-delcared types, always assume
they inherit from GC::Cell. This improves the worst case from a missed
unvisited field, to a slightly wrong error message.

Fixes #5959.
This commit is contained in:
Idan Horowitz 2025-08-23 20:02:46 +03:00 committed by Jelle Raaijmakers
commit bcb8b06a74
Notes: github-actions[bot] 2025-08-23 19:22:13 +00:00
2 changed files with 13 additions and 2 deletions

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2024, Matthew Olsson <mattco@serenityos.org> * Copyright (c) 2024, Matthew Olsson <mattco@serenityos.org>
* Copyright (c) 2025, Idan Horowitz <idan.horowitz@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
@ -130,8 +131,13 @@ static std::optional<QualTypeGCInfo> validate_qualified_type(clang::QualType con
return {}; return {};
auto const* record_decl = record_type->getAsCXXRecordDecl(); auto const* record_decl = record_type->getAsCXXRecordDecl();
if (!record_decl->hasDefinition()) if (!record_decl->hasDefinition()) {
return {}; // If we don't have a definition (this is a forward declaration), assume that the type inherits from
// GC::Cell instead of not checking it at all. If it does inherit from GC:Cell, this will make sure it's
// visited. If it does not, any attempt to visit it will fail compilation on the visit call itself,
// ensuring it's no longer wrapped in a GC::Ptr.
return QualTypeGCInfo { outer_type, true };
}
return QualTypeGCInfo { outer_type, record_inherits_from_cell(*record_decl) }; return QualTypeGCInfo { outer_type, record_inherits_from_cell(*record_decl) };
} else if (auto const* record = type->getAsCXXRecordDecl()) { } else if (auto const* record = type->getAsCXXRecordDecl()) {

View file

@ -8,6 +8,8 @@
#include <LibJS/Runtime/Object.h> #include <LibJS/Runtime/Object.h>
class ForwardDeclaredObject;
class TestClass : public JS::Object { class TestClass : public JS::Object {
JS_OBJECT(TestClass, JS::Object); JS_OBJECT(TestClass, JS::Object);
@ -21,4 +23,7 @@ class TestClass : public JS::Object {
// expected-error@+1 {{GC-allocated member is not visited in TestClass::visit_edges}} // expected-error@+1 {{GC-allocated member is not visited in TestClass::visit_edges}}
JS::Value m_value; JS::Value m_value;
// expected-error@+1 {{GC-allocated member is not visited in TestClass::visit_edges}}
GC::Ptr<ForwardDeclaredObject> m_forward_declared_object;
}; };