From: Erik Verbruggen Date: Tue, 28 Mar 2017 07:22:21 +0000 (+0000) Subject: [libclang] Fix crash in member access code completion with implicit base X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0ba785f458ab9138391703e94f2c835005549e1f;p=clang [libclang] Fix crash in member access code completion with implicit base If there is an unresolved member access AST node, and the base is implicit, do not access/use it for generating candidate overloads for code completion results. Fixes PR31093. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@298903 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index ea4a33d3f5..cfac3f1dc1 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -4318,7 +4318,10 @@ void Sema::CodeCompleteCall(Scope *S, Expr *Fn, ArrayRef Args) { UME->copyTemplateArgumentsInto(TemplateArgsBuffer); TemplateArgs = &TemplateArgsBuffer; } - SmallVector ArgExprs(1, UME->getBase()); + + // Add the base as first argument (use a nullptr if the base is implicit). + SmallVector ArgExprs( + 1, UME->isImplicitAccess() ? nullptr : UME->getBase()); ArgExprs.append(Args.begin(), Args.end()); UnresolvedSet<8> Decls; Decls.append(UME->decls_begin(), UME->decls_end()); diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 82834057ee..bba8216fa2 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -6307,30 +6307,45 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns, for (UnresolvedSetIterator F = Fns.begin(), E = Fns.end(); F != E; ++F) { NamedDecl *D = F.getDecl()->getUnderlyingDecl(); if (FunctionDecl *FD = dyn_cast(D)) { - if (isa(FD) && !cast(FD)->isStatic()) + if (isa(FD) && !cast(FD)->isStatic()) { + QualType ObjectType; + Expr::Classification ObjectClassification; + if (Expr *E = Args[0]) { + // Use the explit base to restrict the lookup: + ObjectType = E->getType(); + ObjectClassification = E->Classify(Context); + } // .. else there is an implit base. AddMethodCandidate(cast(FD), F.getPair(), - cast(FD)->getParent(), - Args[0]->getType(), Args[0]->Classify(Context), - Args.slice(1), CandidateSet, SuppressUserConversions, - PartialOverloading); - else + cast(FD)->getParent(), ObjectType, + ObjectClassification, Args.slice(1), CandidateSet, + SuppressUserConversions, PartialOverloading); + } else { AddOverloadCandidate(FD, F.getPair(), Args, CandidateSet, SuppressUserConversions, PartialOverloading); + } } else { FunctionTemplateDecl *FunTmpl = cast(D); if (isa(FunTmpl->getTemplatedDecl()) && - !cast(FunTmpl->getTemplatedDecl())->isStatic()) + !cast(FunTmpl->getTemplatedDecl())->isStatic()) { + QualType ObjectType; + Expr::Classification ObjectClassification; + if (Expr *E = Args[0]) { + // Use the explit base to restrict the lookup: + ObjectType = E->getType(); + ObjectClassification = E->Classify(Context); + } // .. else there is an implit base. AddMethodTemplateCandidate( FunTmpl, F.getPair(), cast(FunTmpl->getDeclContext()), - ExplicitTemplateArgs, Args[0]->getType(), - Args[0]->Classify(Context), Args.slice(1), CandidateSet, - SuppressUserConversions, PartialOverloading); - else + ExplicitTemplateArgs, ObjectType, ObjectClassification, + Args.slice(1), CandidateSet, SuppressUserConversions, + PartialOverloading); + } else { AddTemplateOverloadCandidate(FunTmpl, F.getPair(), ExplicitTemplateArgs, Args, CandidateSet, SuppressUserConversions, PartialOverloading); + } } } } diff --git a/test/CodeCompletion/member-access.cpp b/test/CodeCompletion/member-access.cpp index 8195f764fb..66872272ee 100644 --- a/test/CodeCompletion/member-access.cpp +++ b/test/CodeCompletion/member-access.cpp @@ -37,6 +37,17 @@ struct Test1 { } }; +struct Foo { + void foo() const; + static void foo(bool); +}; + +struct Bar { + void foo(bool param) { + Foo::foo( );// unresolved member expression with an implicit base + } +}; + // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:29:6 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s // CHECK-CC1: Base1 : Base1:: // CHECK-CC1: member1 : [#int#][#Base1::#]member1 @@ -52,3 +63,6 @@ struct Test1 { // Make sure this doesn't crash // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:36:7 %s -verify + +// Make sure this also doesn't crash +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:47:14 %s