Skip to content

Commit

Permalink
[ASTImporter] Fix 'isVirtual()' assert failure while import overridde…
Browse files Browse the repository at this point in the history
…n methods

CXXMethodDecl::isVirtual() count the number of overridden methods.
This assertion is not true before overridden methods are fully loaded.
The body of this CXXMethodDecl can introduce deps on a derived class
which contains a method overriding this method, causing the assertion failure.

ImportOverriddenMethods() is moved before body loading to fix this issue.

Testcase is contributed by Balázs Kéri (balazske)

Differential Revision: https://reviews.llvm.org/D154701
  • Loading branch information
danix800 authored and veselypeta committed Sep 6, 2024
2 parents a6dfe2b + 5b99aa5 commit fc84e4c
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 5 deletions.
10 changes: 5 additions & 5 deletions clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3783,6 +3783,11 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
if (Error Err = ImportTemplateInformation(D, ToFunction))
return std::move(Err);

if (auto *FromCXXMethod = dyn_cast<CXXMethodDecl>(D))
if (Error Err = ImportOverriddenMethods(cast<CXXMethodDecl>(ToFunction),
FromCXXMethod))
return std::move(Err);

if (D->doesThisDeclarationHaveABody()) {
Error Err = ImportFunctionDeclBody(D, ToFunction);

Expand All @@ -3806,11 +3811,6 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {

addDeclToContexts(D, ToFunction);

if (auto *FromCXXMethod = dyn_cast<CXXMethodDecl>(D))
if (Error Err = ImportOverriddenMethods(cast<CXXMethodDecl>(ToFunction),
FromCXXMethod))
return std::move(Err);

// Import the rest of the chain. I.e. import all subsequent declarations.
for (++RedeclIt; RedeclIt != Redecls.end(); ++RedeclIt) {
ExpectedDecl ToRedeclOrErr = import(*RedeclIt);
Expand Down
37 changes: 37 additions & 0 deletions clang/unittests/AST/ASTImporterTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2332,6 +2332,43 @@ TEST_P(ImportFunctions,
EXPECT_EQ(ToDFOutOfClass->getPreviousDecl(), ToDFInClass);
}

TEST_P(ASTImporterOptionSpecificTestBase,
ImportVirtualOverriddenMethodOnALoopTest) {
// B::f() calls => f1() ==> C ==> C::f()
// \
// \---- A::f()
//
// C::f()'s ImportOverriddenMethods() asserts B::isVirtual(), so B::f()'s
// ImportOverriddenMethods() should be completed before B::f()'s body
const char *Code =
R"(
void f1();
class A {
virtual void f(){}
};
class B: public A {
void f() override {
f1();
}
};
class C: public B {
void f() override {}
};
void f1() { C c; }
)";
Decl *FromTU = getTuDecl(Code, Lang_CXX11);

auto *FromF = FirstDeclMatcher<CXXMethodDecl>().match(
FromTU, cxxMethodDecl(hasName("B::f")));

auto *ToBF = Import(FromF, Lang_CXX11);
EXPECT_TRUE(ToBF->isVirtual());

auto *ToCF = FirstDeclMatcher<CXXMethodDecl>().match(
ToBF->getTranslationUnitDecl(), cxxMethodDecl(hasName("C::f")));
EXPECT_TRUE(ToCF->isVirtual());
}

TEST_P(ASTImporterOptionSpecificTestBase, ImportVariableChainInC) {
std::string Code = "static int v; static int v = 0;";
auto Pattern = varDecl(hasName("v"));
Expand Down

0 comments on commit fc84e4c

Please sign in to comment.