summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/AST/DeclCXX.h4
-rw-r--r--clang/include/clang/AST/ExprCXX.h4
-rw-r--r--clang/lib/AST/DeclCXX.cpp18
-rw-r--r--clang/lib/AST/ExprCXX.cpp5
-rw-r--r--clang/lib/Analysis/CallGraph.cpp5
-rw-r--r--clang/test/Analysis/debug-CallGraph.cpp21
6 files changed, 49 insertions, 8 deletions
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h
index 0b835ecd736..de0aa5f9b90 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -1172,6 +1172,10 @@ public:
/// if this is a closure type.
CXXMethodDecl *getLambdaCallOperator() const;
+ /// Retrieve the dependent lambda call operator of the closure type
+ /// if this is a templated closure type.
+ FunctionTemplateDecl *getDependentLambdaCallOperator() const;
+
/// Retrieve the lambda static invoker, the address of which
/// is returned by the conversion operator, and the body of which
/// is forwarded to the lambda call operator.
diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index bc7d7c0a320..8e13eb5fdba 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -1907,6 +1907,10 @@ public:
/// lambda expression.
CXXMethodDecl *getCallOperator() const;
+ /// Retrieve the function template call operator associated with this
+ /// lambda expression.
+ FunctionTemplateDecl *getDependentCallOperator() const;
+
/// If this is a generic lambda expression, retrieve the template
/// parameter list associated with it, or else return null.
TemplateParameterList *getTemplateParameterList() const;
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 297a598911d..942588f4ede 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -1399,17 +1399,25 @@ static bool allLookupResultsAreTheSame(const DeclContext::lookup_result &R) {
}
#endif
-CXXMethodDecl* CXXRecordDecl::getLambdaCallOperator() const {
- if (!isLambda()) return nullptr;
+NamedDecl* getLambdaCallOperatorHelper(const CXXRecordDecl &RD) {
+ if (!RD.isLambda()) return nullptr;
DeclarationName Name =
- getASTContext().DeclarationNames.getCXXOperatorName(OO_Call);
- DeclContext::lookup_result Calls = lookup(Name);
+ RD.getASTContext().DeclarationNames.getCXXOperatorName(OO_Call);
+ DeclContext::lookup_result Calls = RD.lookup(Name);
assert(!Calls.empty() && "Missing lambda call operator!");
assert(allLookupResultsAreTheSame(Calls) &&
"More than one lambda call operator!");
+ return Calls.front();
+}
+
+FunctionTemplateDecl* CXXRecordDecl::getDependentLambdaCallOperator() const {
+ NamedDecl *CallOp = getLambdaCallOperatorHelper(*this);
+ return dyn_cast<FunctionTemplateDecl>(CallOp);
+}
- NamedDecl *CallOp = Calls.front();
+CXXMethodDecl *CXXRecordDecl::getLambdaCallOperator() const {
+ NamedDecl *CallOp = getLambdaCallOperatorHelper(*this);
if (const auto *CallOpTmpl = dyn_cast<FunctionTemplateDecl>(CallOp))
return cast<CXXMethodDecl>(CallOpTmpl->getTemplatedDecl());
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index 30c28314d5b..1d5fd80d0d4 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -1218,6 +1218,11 @@ CXXMethodDecl *LambdaExpr::getCallOperator() const {
return Record->getLambdaCallOperator();
}
+FunctionTemplateDecl *LambdaExpr::getDependentCallOperator() const {
+ CXXRecordDecl *Record = getLambdaClass();
+ return Record->getDependentLambdaCallOperator();
+}
+
TemplateParameterList *LambdaExpr::getTemplateParameterList() const {
CXXRecordDecl *Record = getLambdaClass();
return Record->getGenericLambdaTemplateParameterList();
diff --git a/clang/lib/Analysis/CallGraph.cpp b/clang/lib/Analysis/CallGraph.cpp
index 865840eb341..76be292dad8 100644
--- a/clang/lib/Analysis/CallGraph.cpp
+++ b/clang/lib/Analysis/CallGraph.cpp
@@ -80,7 +80,10 @@ public:
}
void VisitLambdaExpr(LambdaExpr *LE) {
- if (CXXMethodDecl *MD = LE->getCallOperator())
+ if (FunctionTemplateDecl *FTD = LE->getDependentCallOperator())
+ for (FunctionDecl *FD : FTD->specializations())
+ G->VisitFunctionDecl(FD);
+ else if (CXXMethodDecl *MD = LE->getCallOperator())
G->VisitFunctionDecl(MD);
}
diff --git a/clang/test/Analysis/debug-CallGraph.cpp b/clang/test/Analysis/debug-CallGraph.cpp
index 1d6844fad94..0f5a83b268a 100644
--- a/clang/test/Analysis/debug-CallGraph.cpp
+++ b/clang/test/Analysis/debug-CallGraph.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCallGraph %s -fblocks 2>&1 | FileCheck %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCallGraph %s -fblocks -std=c++14 2>&1 | FileCheck %s
int get5() {
return 5;
@@ -68,8 +68,25 @@ void templUser() {
}
}
+namespace Lambdas {
+ void Callee(){}
+
+ void f1() {
+ [](int i) {
+ Callee();
+ }(1);
+ [](auto i) {
+ Callee();
+ }(1);
+ }
+}
+
// CHECK:--- Call graph Dump ---
-// CHECK-NEXT: {{Function: < root > calls: get5 add test_add mmm foo aaa < > bbb ddd ccc eee fff do_nothing test_single_call SomeNS::templ SomeNS::templ SomeNS::templUser $}}
+// CHECK-NEXT: {{Function: < root > calls: get5 add test_add mmm foo aaa < > bbb ddd ccc eee fff do_nothing test_single_call SomeNS::templ SomeNS::templ SomeNS::templUser Lambdas::Callee Lambdas::f1 Lambdas::f1\(\)::\(anonymous class\)::operator\(\) Lambdas::f1\(\)::\(anonymous class\)::operator\(\) $}}
+// CHECK-NEXT: {{Function: Lambdas::f1 calls: Lambdas::f1\(\)::\(anonymous class\)::operator\(\) Lambdas::f1\(\)::\(anonymous class\)::operator\(\) $}}
+// CHECK-NEXT: {{Function: Lambdas::f1\(\)::\(anonymous class\)::operator\(\) calls: Lambdas::Callee $}}
+// CHECK-NEXT: {{Function: Lambdas::f1\(\)::\(anonymous class\)::operator\(\) calls: Lambdas::Callee $}}
+// CHECK-NEXT: {{Function: Lambdas::Callee calls: $}}
// CHECK-NEXT: {{Function: SomeNS::templUser calls: SomeNS::templ SomeNS::templ $}}
// CHECK-NEXT: {{Function: SomeNS::templ calls: eee $}}
// CHECK-NEXT: {{Function: SomeNS::templ calls: ccc $}}
OpenPOWER on IntegriCloud