Skip to content

Commit 20a0567

Browse files
authored
[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 #71015
1 parent ace69e6 commit 20a0567

File tree

4 files changed

+69
-0
lines changed

4 files changed

+69
-0
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,9 @@ Bug Fixes in This Version
692692
Fixes (`#64347 <https://github.com/llvm/llvm-project/issues/64347>`_)
693693
- Fix crash when using C++ only tokens like ``::`` in C compiler clang.
694694
Fixes (`#73559 <https://github.com/llvm/llvm-project/issues/73559>`_)
695+
- Clang now accepts recursive non-dependent calls to functions with deduced
696+
return type.
697+
Fixes (`#71015 <https://github.com/llvm/llvm-project/issues/71015>`_)
695698

696699

697700
Bug Fixes to Compiler Builtins

clang/lib/AST/ComputeDependence.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,8 @@ ExprDependence clang::computeDependence(PredefinedExpr *E) {
603603
ExprDependence clang::computeDependence(CallExpr *E,
604604
llvm::ArrayRef<Expr *> PreArgs) {
605605
auto D = E->getCallee()->getDependence();
606+
if (E->getType()->isDependentType())
607+
D |= ExprDependence::Type;
606608
for (auto *A : llvm::ArrayRef(E->getArgs(), E->getNumArgs())) {
607609
if (A)
608610
D |= A->getDependence();

clang/lib/Sema/SemaOverload.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13994,6 +13994,24 @@ ExprResult Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn,
1399413994
OverloadCandidateSet::iterator Best;
1399513995
OverloadingResult OverloadResult =
1399613996
CandidateSet.BestViableFunction(*this, Fn->getBeginLoc(), Best);
13997+
FunctionDecl *FDecl = Best->Function;
13998+
13999+
// Model the case with a call to a templated function whose definition
14000+
// encloses the call and whose return type contains a placeholder type as if
14001+
// the UnresolvedLookupExpr was type-dependent.
14002+
if (OverloadResult == OR_Success && FDecl &&
14003+
FDecl->isTemplateInstantiation() &&
14004+
FDecl->getReturnType()->isUndeducedType()) {
14005+
if (auto TP = FDecl->getTemplateInstantiationPattern(false)) {
14006+
if (TP->willHaveBody()) {
14007+
CallExpr *CE =
14008+
CallExpr::Create(Context, Fn, Args, Context.DependentTy, VK_PRValue,
14009+
RParenLoc, CurFPFeatureOverrides());
14010+
result = CE;
14011+
return result;
14012+
}
14013+
}
14014+
}
1399714015

1399814016
return FinishOverloadedCallExpr(*this, S, Fn, ULE, LParenLoc, Args, RParenLoc,
1399914017
ExecConfig, &CandidateSet, &Best,

clang/test/SemaCXX/deduced-return-type-cxx14.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,3 +640,49 @@ namespace PR46637 {
640640
template<typename T> struct Y { T x; };
641641
Y<auto() -> auto> y; // expected-error {{'auto' not allowed in template argument}}
642642
}
643+
644+
namespace GH71015 {
645+
646+
// Check that there is no error in case a templated function is recursive and
647+
// has a placeholder return type.
648+
struct Node {
649+
int value;
650+
Node* left;
651+
Node* right;
652+
};
653+
654+
bool parse(const char*);
655+
Node* parsePrimaryExpr();
656+
657+
auto parseMulExpr(auto node) { // cxx14-error {{'auto' not allowed in function prototype}} \
658+
// cxx14-note {{not viable}}
659+
if (node == nullptr) node = parsePrimaryExpr();
660+
if (!parse("*")) return node;
661+
return parseMulExpr(new Node{.left = node, .right = parsePrimaryExpr()});
662+
}
663+
664+
template <typename T>
665+
auto parseMulExpr2(T node) {
666+
if (node == nullptr) node = parsePrimaryExpr();
667+
if (!parse("*")) return node;
668+
return parseMulExpr2(new Node{.left = node, .right = parsePrimaryExpr()});
669+
}
670+
671+
template <typename T>
672+
auto parseMulExpr3(T node) { // expected-note {{declared here}}
673+
if (node == nullptr) node = parsePrimaryExpr();
674+
return parseMulExpr3(new Node{.left = node, .right = parsePrimaryExpr()}); // expected-error {{cannot be used before it is defined}}
675+
}
676+
677+
void foo() {
678+
parseMulExpr(new Node{}); // cxx14-error {{no matching function}}
679+
parseMulExpr2(new Node{});
680+
parseMulExpr3(new Node{}); // expected-note {{in instantiation}}
681+
}
682+
683+
auto f(auto x) { // cxx14-error {{'auto' not allowed in function prototype}}
684+
if (x == 0) return 0;
685+
return f(1) + 1;
686+
}
687+
688+
}

0 commit comments

Comments
 (0)