--- /dev/null
+import lldb
+from lldbsuite.test.lldbtest import *
+import lldbsuite.test.lldbutil as lldbutil
+
+class TestCase(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+ NO_DEBUG_INFO_TESTCASE = True
+
+ def test(self):
+ self.build()
+ lldbutil.run_to_source_breakpoint(self,"// break here", lldb.SBFileSpec("main.cpp"))
+
+ # Test covariant return types for pointers to class that contains the called function.
+ self.expect_expr("derived.getPtr()", result_type="Derived *")
+ self.expect_expr("base_ptr_to_derived->getPtr()", result_type="Base *")
+ self.expect_expr("base.getPtr()", result_type="Base *")
+ # The same tests with reference types. LLDB drops the reference when it turns the
+ # result into a SBValue so check for the the underlying type of the result.
+ self.expect_expr("derived.getRef()", result_type="Derived")
+ self.expect_expr("base_ptr_to_derived->getRef()", result_type="Base")
+ self.expect_expr("base.getRef()", result_type="Base")
+
+ # Test covariant return types for pointers to class that does *not* contain the called function.
+ self.expect_expr("derived.getOtherPtr()", result_type="OtherDerived *")
+ self.expect_expr("base_ptr_to_derived->getOtherPtr()", result_type="OtherBase *")
+ self.expect_expr("base.getOtherPtr()", result_type="OtherBase *")
+ # The same tests with reference types. LLDB drops the reference when it turns the
+ # result into a SBValue so check for the the underlying type of the result.
+ self.expect_expr("derived.getOtherRef()", result_type="OtherDerived")
+ self.expect_expr("base_ptr_to_derived->getOtherRef()", result_type="OtherBase")
+ self.expect_expr("base.getOtherRef()", result_type="OtherBase")
+
+ # Test that we call the right function and get the right value back.
+ self.expect_expr("derived.getOtherPtr()->value()", result_summary='"derived"')
+ self.expect_expr("base_ptr_to_derived->getOtherPtr()->value()", result_summary='"derived"')
+ self.expect_expr("base.getOtherPtr()->value()", result_summary='"base"')
+ self.expect_expr("derived.getOtherRef().value()", result_summary='"derived"')
+ self.expect_expr("base_ptr_to_derived->getOtherRef().value()", result_summary='"derived"')
+ self.expect_expr("base.getOtherRef().value()", result_summary='"base"')
--- /dev/null
+struct OtherBase {
+ // Allow checking actual type from the test by giving
+ // this class and the subclass unique values here.
+ virtual const char *value() { return "base"; }
+};
+struct OtherDerived : public OtherBase {
+ const char *value() override { return "derived"; }
+};
+
+// Those have to be globals as they would be completed if they
+// are members (which would make this test always pass).
+OtherBase other_base;
+OtherDerived other_derived;
+
+struct Base {
+ // Function with covariant return type that is same class.
+ virtual Base* getPtr() { return this; }
+ virtual Base& getRef() { return *this; }
+ // Function with covariant return type that is a different class.
+ virtual OtherBase* getOtherPtr() { return &other_base; }
+ virtual OtherBase& getOtherRef() { return other_base; }
+};
+
+struct Derived : public Base {
+ Derived* getPtr() override { return this; }
+ Derived& getRef() override { return *this; }
+ OtherDerived* getOtherPtr() override { return &other_derived; }
+ OtherDerived& getOtherRef() override { return other_derived; }
+};
+
+int main() {
+ Derived derived;
+ Base base;
+ Base *base_ptr_to_derived = &derived;
+ (void)base_ptr_to_derived->getPtr();
+ (void)base_ptr_to_derived->getRef();
+ (void)base_ptr_to_derived->getOtherPtr();
+ (void)base_ptr_to_derived->getOtherRef();
+ return 0; // break here
+}
}
}
+/// Takes a CXXMethodDecl and completes the return type if necessary. This
+/// is currently only necessary for virtual functions with covariant return
+/// types where Clang's CodeGen expects that the underlying records are already
+/// completed.
+static void MaybeCompleteReturnType(ClangASTImporter &importer,
+ CXXMethodDecl *to_method) {
+ if (!to_method->isVirtual())
+ return;
+ QualType return_type = to_method->getReturnType();
+ if (!return_type->isPointerType() && !return_type->isReferenceType())
+ return;
+
+ clang::RecordDecl *rd = return_type->getPointeeType()->getAsRecordDecl();
+ if (!rd)
+ return;
+
+ importer.CompleteTagDecl(rd);
+}
+
void ClangASTImporter::ASTImporterDelegate::Imported(clang::Decl *from,
clang::Decl *to) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
}
}
}
+
+ if (clang::CXXMethodDecl *to_method = dyn_cast<CXXMethodDecl>(to))
+ MaybeCompleteReturnType(m_master, to_method);
}
clang::Decl *