[clang] 20a0567 - [clang] Accept recursive non-dependent calls to functions with deduced return type (#75456)

via cfe-commits cfe-commits at lists.llvm.org
Fri Jan 5 04:14:54 PST 2024


Author: Mariya Podchishchaeva
Date: 2024-01-05T13:14:51+01:00
New Revision: 20a05677f9394d4bc9467fe7bc93a4ebd3aeda61

URL: https://github.com/llvm/llvm-project/commit/20a05677f9394d4bc9467fe7bc93a4ebd3aeda61
DIFF: https://github.com/llvm/llvm-project/commit/20a05677f9394d4bc9467fe7bc93a4ebd3aeda61.diff

LOG: [clang] Accept recursive non-dependent calls to functions with deduced return type (#75456)

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

Fixes https://github.com/llvm/llvm-project/issues/71015

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/lib/AST/ComputeDependence.cpp
    clang/lib/Sema/SemaOverload.cpp
    clang/test/SemaCXX/deduced-return-type-cxx14.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 903a50a4d4d3a4..cd7d504551875c 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -692,6 +692,9 @@ Bug Fixes in This Version
   Fixes (`#64347 <https://github.com/llvm/llvm-project/issues/64347>`_)
 - Fix crash when using C++ only tokens like ``::`` in C compiler clang.
   Fixes (`#73559 <https://github.com/llvm/llvm-project/issues/73559>`_)
+- 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..eac9c587869f55 100644
--- a/clang/test/SemaCXX/deduced-return-type-cxx14.cpp
+++ b/clang/test/SemaCXX/deduced-return-type-cxx14.cpp
@@ -640,3 +640,49 @@ 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}} \
+                               // cxx14-note {{not viable}}
+  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()});
+}
+
+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 cfe-commits mailing list