diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -5409,11 +5409,17 @@ : getApproximateType(CDSME->getBase()); if (CDSME->isArrow() && !Base.isNull()) Base = Base->getPointeeType(); // could handle unique_ptr etc here? - RecordDecl *RD = Base.isNull() ? nullptr : getAsRecordDecl(Base); + auto *RD = Base.isNull() + ? nullptr + : llvm::dyn_cast(getAsRecordDecl(Base)); if (RD && RD->isCompleteDefinition()) { - for (const auto *Member : RD->lookup(CDSME->getMember())) - if (const ValueDecl *VD = llvm::dyn_cast(Member)) - return VD->getType().getNonReferenceType(); + // Look up member heuristically, including in bases. + for (const auto *Member : RD->lookupDependentName( + CDSME->getMember(), [](const NamedDecl *Member) { + return llvm::isa(Member); + })) { + return llvm::cast(Member)->getType().getNonReferenceType(); + } } } return Unresolved; diff --git a/clang/test/CodeCompletion/member-access.cpp b/clang/test/CodeCompletion/member-access.cpp --- a/clang/test/CodeCompletion/member-access.cpp +++ b/clang/test/CodeCompletion/member-access.cpp @@ -296,3 +296,18 @@ } // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:295:17 %s -o - | FileCheck -check-prefix=CHECK-OVERLOAD %s // CHECK-OVERLOAD: [#int#]member + +struct Base4 { + Base4 base4(); +}; + +template +struct Derived2 : Base4 {}; + +template +void testMembersFromBasesInDependentContext() { + Derived2 X; + (void)X.base4().base4(); + // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:310:19 %s -o - | FileCheck -check-prefix=CHECK-MEMBERS-FROM-BASE-DEPENDENT %s + // CHECK-MEMBERS-FROM-BASE-DEPENDENT: [#Base4#]base4 +}