diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 903a50a4d4d3a..cd7d504551875 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -692,6 +692,9 @@ Bug Fixes in This Version Fixes (`#64347 `_) - Fix crash when using C++ only tokens like ``::`` in C compiler clang. Fixes (`#73559 `_) +- Clang now accepts recursive non-dependent calls to functions with deduced + return type. + Fixes (`#71015 `_) Bug Fixes to Compiler Builtins diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp index 097753fd3267b..584b58473294b 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 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 5026e1d603e5e..9fb767101e1eb 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 6344d1df3fbae..eac9c587869f5 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 struct Y { T x; }; Y 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 +auto parseMulExpr2(T node) { + if (node == nullptr) node = parsePrimaryExpr(); + if (!parse("*")) return node; + return parseMulExpr2(new Node{.left = node, .right = parsePrimaryExpr()}); +} + +template +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; +} + +}