[libcxx-commits] [libc] [compiler-rt] [clang] [llvm] [clang-tools-extra] [flang] [libcxx] [clang] Accept recursive non-dependent calls to functions with deduced return type (PR #75456)

Mariya Podchishchaeva via libcxx-commits libcxx-commits at lists.llvm.org
Fri Jan 5 02:08:09 PST 2024


https://github.com/Fznamznon updated https://github.com/llvm/llvm-project/pull/75456

>From 0e190f131862dd8f4b07891c3ee712a0a163f936 Mon Sep 17 00:00:00 2001
From: "Podchishchaeva, Mariya" <mariya.podchishchaeva at intel.com>
Date: Thu, 14 Dec 2023 01:33:17 -0800
Subject: [PATCH 1/2] [clang] Accept recursive non-dependent calls to functions
 with deduced return type

Treat such calls as dependent since it is much easier to implement.

Fixes https://github.com/llvm/llvm-project/issues/71015
---
 clang/docs/ReleaseNotes.rst                   |  3 ++
 clang/lib/AST/ComputeDependence.cpp           |  2 ++
 clang/lib/Sema/SemaOverload.cpp               | 18 ++++++++++
 .../SemaCXX/deduced-return-type-cxx14.cpp     | 33 +++++++++++++++++++
 4 files changed, 56 insertions(+)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 05d59d0da264f3..9ffc7500414981 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -688,6 +688,9 @@ Bug Fixes in This Version
 - Fixed false positive error emitted when templated alias inside a class
   used private members of the same class.
   Fixes (`#41693 <https://github.com/llvm/llvm-project/issues/41693>`_)
+- Clang now accepts recursive non-dependent calls to functions with deduced return
+  type.
+  Fixes (`#71015 <https://github.com/llvm/llvm-project/issues/71015>`_)
 
 Bug Fixes to Compiler Builtins
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp
index 097753fd3267b5..584b58473294be 100644
--- a/clang/lib/AST/ComputeDependence.cpp
+++ b/clang/lib/AST/ComputeDependence.cpp
@@ -603,6 +603,8 @@ ExprDependence clang::computeDependence(PredefinedExpr *E) {
 ExprDependence clang::computeDependence(CallExpr *E,
                                         llvm::ArrayRef<Expr *> PreArgs) {
   auto D = E->getCallee()->getDependence();
+  if (E->getType()->isDependentType())
+    D |= ExprDependence::Type;
   for (auto *A : llvm::ArrayRef(E->getArgs(), E->getNumArgs())) {
     if (A)
       D |= A->getDependence();
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 5026e1d603e5ee..9fb767101e1eb7 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -13994,6 +13994,24 @@ ExprResult Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn,
   OverloadCandidateSet::iterator Best;
   OverloadingResult OverloadResult =
       CandidateSet.BestViableFunction(*this, Fn->getBeginLoc(), Best);
+  FunctionDecl *FDecl = Best->Function;
+
+  // Model the case with a call to a templated function whose definition
+  // encloses the call and whose return type contains a placeholder type as if
+  // the UnresolvedLookupExpr was type-dependent.
+  if (OverloadResult == OR_Success && FDecl &&
+      FDecl->isTemplateInstantiation() &&
+      FDecl->getReturnType()->isUndeducedType()) {
+    if (auto TP = FDecl->getTemplateInstantiationPattern(false)) {
+      if (TP->willHaveBody()) {
+        CallExpr *CE =
+            CallExpr::Create(Context, Fn, Args, Context.DependentTy, VK_PRValue,
+                             RParenLoc, CurFPFeatureOverrides());
+        result = CE;
+        return result;
+      }
+    }
+  }
 
   return FinishOverloadedCallExpr(*this, S, Fn, ULE, LParenLoc, Args, RParenLoc,
                                   ExecConfig, &CandidateSet, &Best,
diff --git a/clang/test/SemaCXX/deduced-return-type-cxx14.cpp b/clang/test/SemaCXX/deduced-return-type-cxx14.cpp
index 6344d1df3fbaeb..1da597499d34f5 100644
--- a/clang/test/SemaCXX/deduced-return-type-cxx14.cpp
+++ b/clang/test/SemaCXX/deduced-return-type-cxx14.cpp
@@ -640,3 +640,36 @@ namespace PR46637 {
   template<typename T> struct Y { T x; };
   Y<auto() -> auto> y; // expected-error {{'auto' not allowed in template argument}}
 }
+
+namespace GH71015 {
+
+// Check that there is no error in case a templated function is recursive and
+// has a placeholder return type.
+struct Node {
+  int value;
+  Node* left;
+  Node* right;
+};
+
+bool parse(const char*);
+Node* parsePrimaryExpr();
+
+auto parseMulExpr(auto node) { // cxx14-error {{'auto' not allowed in function prototype}}
+  if (node == nullptr) node = parsePrimaryExpr();
+  if (!parse("*")) return node;
+  return parseMulExpr(new Node{.left = node, .right = parsePrimaryExpr()});
+}
+
+template <typename T>
+auto parseMulExpr2(T node) {
+  if (node == nullptr) node = parsePrimaryExpr();
+  if (!parse("*")) return node;
+  return parseMulExpr2(new Node{.left = node, .right = parsePrimaryExpr()});
+}
+
+auto f(auto x) { // cxx14-error {{'auto' not allowed in function prototype}}
+  if (x == 0) return 0;
+  return f(1) + 1;
+}
+
+}

>From 9981ec5663fd039cb2ddfc00ae8f1468f2b56d61 Mon Sep 17 00:00:00 2001
From: "Podchishchaeva, Mariya" <mariya.podchishchaeva at intel.com>
Date: Thu, 4 Jan 2024 02:23:33 -0800
Subject: [PATCH 2/2] Add a testcase

---
 clang/test/SemaCXX/deduced-return-type-cxx14.cpp | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/clang/test/SemaCXX/deduced-return-type-cxx14.cpp b/clang/test/SemaCXX/deduced-return-type-cxx14.cpp
index 1da597499d34f5..eac9c587869f55 100644
--- a/clang/test/SemaCXX/deduced-return-type-cxx14.cpp
+++ b/clang/test/SemaCXX/deduced-return-type-cxx14.cpp
@@ -654,7 +654,8 @@ struct Node {
 bool parse(const char*);
 Node* parsePrimaryExpr();
 
-auto parseMulExpr(auto node) { // cxx14-error {{'auto' not allowed in function prototype}}
+auto parseMulExpr(auto node) { // cxx14-error {{'auto' not allowed in function prototype}} \
+                               // cxx14-note {{not viable}}
   if (node == nullptr) node = parsePrimaryExpr();
   if (!parse("*")) return node;
   return parseMulExpr(new Node{.left = node, .right = parsePrimaryExpr()});
@@ -667,6 +668,18 @@ auto parseMulExpr2(T node) {
   return parseMulExpr2(new Node{.left = node, .right = parsePrimaryExpr()});
 }
 
+template <typename T>
+auto parseMulExpr3(T node) { // expected-note {{declared here}}
+  if (node == nullptr) node = parsePrimaryExpr();
+  return parseMulExpr3(new Node{.left = node, .right = parsePrimaryExpr()}); // expected-error {{cannot be used before it is defined}}
+}
+
+void foo() {
+  parseMulExpr(new Node{}); // cxx14-error {{no matching function}}
+  parseMulExpr2(new Node{});
+  parseMulExpr3(new Node{}); // expected-note {{in instantiation}}
+}
+
 auto f(auto x) { // cxx14-error {{'auto' not allowed in function prototype}}
   if (x == 0) return 0;
   return f(1) + 1;



More information about the libcxx-commits mailing list