[clang][AST] Handle overload callee type in CallExpr::getCallReturnType.
authorBalázs Kéri <1.int32@gmail.com>
Mon, 12 Apr 2021 06:52:40 +0000 (08:52 +0200)
committerBalázs Kéri <1.int32@gmail.com>
Mon, 12 Apr 2021 07:44:17 +0000 (09:44 +0200)
The function did not handle every case. In some cases this
caused assertion failure.
After the fix the function returns DependentTy if the exact
return type can not be determined.

It seems that clang itself does not call the function in the
affected cases but some checker or other code may call it.

Reviewed By: hokein

Differential Revision: https://reviews.llvm.org/D95244

clang/lib/AST/Expr.cpp
clang/unittests/Tooling/SourceCodeTest.cpp

index eccb42e..a4a70be 100644 (file)
@@ -1391,8 +1391,15 @@ QualType CallExpr::getCallReturnType(const ASTContext &Ctx) const {
     if (isa<CXXPseudoDestructorExpr>(Callee->IgnoreParens()))
       return Ctx.VoidTy;
 
+    if (isa<UnresolvedMemberExpr>(Callee->IgnoreParens()))
+      return Ctx.DependentTy;
+
     // This should never be overloaded and so should never return null.
     CalleeType = Expr::findBoundMemberType(Callee);
+    assert(!CalleeType.isNull());
+  } else if (CalleeType->isDependentType() ||
+             CalleeType->isSpecificPlaceholderType(BuiltinType::Overload)) {
+    return Ctx.DependentTy;
   }
 
   const FunctionType *FnType = CalleeType->castAs<FunctionType>();
index eb652cf..badc6f8 100644 (file)
@@ -621,4 +621,71 @@ int c = BAR 3.0;
   };
   Visitor.runOver(Code);
 }
+
+TEST(SourceCodeTest, GetCallReturnType_Dependent) {
+  llvm::Annotations Code{R"cpp(
+template<class T, class F>
+void templ(const T& t, F f) {}
+
+template<class T, class F>
+void templ1(const T& t, F f) {
+  $test1[[f(t)]];
+}
+
+int f_overload(int) { return 1; }
+int f_overload(double) { return 2; }
+
+void f1() {
+  int i = 0;
+  templ(i, [](const auto &p) {
+    $test2[[f_overload(p)]];
+  });
+}
+
+struct A {
+  void f_overload(int);
+  void f_overload(double);
+};
+
+void f2() {
+ int i = 0;
+ templ(i, [](const auto &p) {
+   A a;
+   $test3[[a.f_overload(p)]];
+ });
+}
+)cpp"};
+
+  llvm::Annotations::Range R1 = Code.range("test1");
+  llvm::Annotations::Range R2 = Code.range("test2");
+  llvm::Annotations::Range R3 = Code.range("test3");
+
+  CallsVisitor Visitor;
+  Visitor.OnCall = [&R1, &R2, &R3](CallExpr *Expr, ASTContext *Context) {
+    unsigned Begin = Context->getSourceManager().getFileOffset(
+        Expr->getSourceRange().getBegin());
+    unsigned End = Context->getSourceManager().getFileOffset(
+        Expr->getSourceRange().getEnd());
+    llvm::Annotations::Range R{Begin, End + 1};
+
+    QualType CalleeType = Expr->getCallee()->getType();
+    if (R == R1) {
+      ASSERT_TRUE(CalleeType->isDependentType());
+      EXPECT_EQ(Expr->getCallReturnType(*Context), Context->DependentTy);
+    } else if (R == R2) {
+      ASSERT_FALSE(CalleeType->isDependentType());
+      ASSERT_TRUE(CalleeType->isSpecificPlaceholderType(BuiltinType::Overload));
+      ASSERT_TRUE(isa<UnresolvedLookupExpr>(Expr->getCallee()));
+      EXPECT_EQ(Expr->getCallReturnType(*Context), Context->DependentTy);
+    } else if (R == R3) {
+      ASSERT_FALSE(CalleeType->isDependentType());
+      ASSERT_TRUE(
+          CalleeType->isSpecificPlaceholderType(BuiltinType::BoundMember));
+      ASSERT_TRUE(isa<UnresolvedMemberExpr>(Expr->getCallee()));
+      EXPECT_EQ(Expr->getCallReturnType(*Context), Context->DependentTy);
+    }
+  };
+  Visitor.runOver(Code.code(), CallsVisitor::Lang_CXX14);
+}
+
 } // end anonymous namespace