Quuxplusone created this revision.
Quuxplusone added reviewers: sammccall, rsmith, dblaikie, majnemer, mizvekov, 
ChuanqiXu.
Quuxplusone added a project: clang.
Quuxplusone requested review of this revision.
Herald added a subscriber: cfe-commits.

Emit the note when we fail to deduce a return type, or deduce conflicting 
return types.

It's emitted a //little// too eagerly, e.g. I wish we could avoid it in cases 
like

  $ bin/clang++ x.cpp
  x.cpp:1:19: error: use of undeclared identifier 'x'
  auto f() { return x; }
                    ^
  x.cpp:1:1: note: deducing return type for 'f'
  auto f() { return x; }
  ^~~~
  1 error generated.

But Clang doesn't seem to be able to distinguish "parsing and type-checking the 
return //expression//" from "deducing the function's actual return //type//," 
and I'm not inclined to dig this rabbit hole deeper than I already have. I 
think this is still a reasonably clean place to stop digging.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D119778

Files:
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Sema/SemaStmt.cpp
  clang/test/Sema/invalid-bitwidth-expr.mm
  clang/test/SemaCXX/cxx20-p0388-unbound-ary.cpp
  clang/test/SemaCXX/cxx2b-consteval-if.cpp
  clang/test/SemaCXX/deduced-return-type-cxx14.cpp
  clang/test/SemaCXX/deduced-return-void.cpp
  clang/test/SemaCXX/std-compare-cxx2a.cpp
  clang/test/SemaCXX/typo-correction-crash.cpp
  clang/test/SemaOpenCLCXX/template-astype.cl
  clang/test/SemaTemplate/concepts.cpp

Index: clang/test/SemaTemplate/concepts.cpp
===================================================================
--- clang/test/SemaTemplate/concepts.cpp
+++ clang/test/SemaTemplate/concepts.cpp
@@ -114,6 +114,7 @@
   }
   template<typename ...T> void g5() {
     ([]() -> C<T> auto{ // expected-error-re {{deduced type {{.*}} does not satisfy}}
+                        // expected-note@-1 {{deducing return type for 'operator()'}}
      return T();
      }(), ...);
   }
@@ -174,11 +175,17 @@
   template<class T> concept C = false;     // expected-note 6 {{because 'false' evaluated to false}}
 
   C auto f1() { return void(); }           // expected-error {{deduced type 'void' does not satisfy 'C'}}
+                                           // expected-note@-1 {{deducing return type for 'f1'}}
   C auto f2() { return; }                  // expected-error {{deduced type 'void' does not satisfy 'C'}}
+                                           // expected-note@-1 {{deducing return type for 'f2'}}
   C auto f3() {}                           // expected-error {{deduced type 'void' does not satisfy 'C'}}
+                                           // expected-note@-1 {{deducing return type for 'f3'}}
   C decltype(auto) f4() { return void(); } // expected-error {{deduced type 'void' does not satisfy 'C'}}
+                                           // expected-note@-1 {{deducing return type for 'f4'}}
   C decltype(auto) f5() { return; }        // expected-error {{deduced type 'void' does not satisfy 'C'}}
+                                           // expected-note@-1 {{deducing return type for 'f5'}}
   C decltype(auto) f6() {}                 // expected-error {{deduced type 'void' does not satisfy 'C'}}
+                                           // expected-note@-1 {{deducing return type for 'f6'}}
 
   void g() {
     f1();
Index: clang/test/SemaOpenCLCXX/template-astype.cl
===================================================================
--- clang/test/SemaOpenCLCXX/template-astype.cl
+++ clang/test/SemaOpenCLCXX/template-astype.cl
@@ -11,6 +11,7 @@
 
 auto neg_test_int(int x) { return templated_astype(x); }
 // expected-note@-1{{in instantiation of function template specialization 'templated_astype<int>' requested here}}
+// expected-note@-2{{deducing return type for 'neg_test_int'}}
 
 auto test_short4(short4 x) { return templated_astype(x); }
 
Index: clang/test/SemaCXX/typo-correction-crash.cpp
===================================================================
--- clang/test/SemaCXX/typo-correction-crash.cpp
+++ clang/test/SemaCXX/typo-correction-crash.cpp
@@ -2,6 +2,7 @@
 auto check1() {
   return 1;
   return s; // expected-error {{use of undeclared identifier 's'}}
+            // expected-note@-3 {{deducing return type for 'check1'}}
 }
 
 int test = 11; // expected-note 2 {{'test' declared here}}
@@ -9,6 +10,7 @@
   return "s";
   return tes; // expected-error {{use of undeclared identifier 'tes'; did you mean 'test'?}}
               // expected-error@-1 {{deduced as 'int' here but deduced as 'const char *' in earlier}}
+              // expected-note@-4 {{deducing return type for 'check2'}}
 }
 
 template <class A, class B> struct is_same { static constexpr bool value = false; };
Index: clang/test/SemaCXX/std-compare-cxx2a.cpp
===================================================================
--- clang/test/SemaCXX/std-compare-cxx2a.cpp
+++ clang/test/SemaCXX/std-compare-cxx2a.cpp
@@ -32,6 +32,7 @@
 auto compare_incomplete_test() {
   // expected-error@+1 {{incomplete type 'std::partial_ordering' where a complete type is required}}
   return (-1.2 <=> 123.0);
+  // expected-note@-3 {{deducing return type for 'compare_incomplete_test'}}
 }
 
 namespace std {
@@ -45,6 +46,7 @@
 auto missing_member_test() {
   // expected-error@+1 {{standard library implementation of 'std::partial_ordering' is not supported; member 'equivalent' is missing}}
   return (1.0 <=> 1.0);
+  // expected-note@-3 {{deducing return type for 'missing_member_test'}}
 }
 
 namespace std {
@@ -59,6 +61,7 @@
 auto test_non_constexpr_var() {
   // expected-error@+1 {{standard library implementation of 'std::strong_ordering' is not supported; member 'equal' does not have expected form}}
   return (1 <=> 0);
+  // expected-note@-3 {{deducing return type for 'test_non_constexpr_var'}}
 }
 
 #else
@@ -77,6 +80,7 @@
 auto test_non_trivial(int LHS, int RHS) {
   // expected-error@+1 {{standard library implementation of 'std::strong_ordering' is not supported; the type is not trivially copyable}}
   return LHS <=> RHS;
+  // expected-note@-3 {{deducing return type for 'test_non_trivial'}}
 }
 
 #endif
Index: clang/test/SemaCXX/deduced-return-void.cpp
===================================================================
--- clang/test/SemaCXX/deduced-return-void.cpp
+++ clang/test/SemaCXX/deduced-return-void.cpp
@@ -16,10 +16,12 @@
 auto f4() {
   return i;
   return; // expected-error {{'auto' in return type deduced as 'void' here but deduced as 'int' in earlier return statement}}
+          // expected-note@-3 {{deducing return type for 'f4'}}
 }
 auto f5() {
   return i;
   return void(); // expected-error {{'auto' in return type deduced as 'void' here but deduced as 'int' in earlier return statement}}
+                 // expected-note@-3 {{deducing return type for 'f5'}}
 }
 
 auto l1 = []() { };
@@ -44,10 +46,12 @@
 decltype(auto) f4() {
   return i;
   return; // expected-error {{'decltype(auto)' in return type deduced as 'void' here but deduced as 'int' in earlier return statement}}
+          // expected-note@-3 {{deducing return type for 'f4'}}
 }
 decltype(auto) f5() {
   return i;
   return void(); // expected-error {{'decltype(auto)' in return type deduced as 'void' here but deduced as 'int' in earlier return statement}}
+                 // expected-note@-3 {{deducing return type for 'f5'}}
 }
 
 auto l1 = []() -> decltype(auto) { };
@@ -56,10 +60,12 @@
 auto l4 = []() -> decltype(auto) {
   return i;
   return; // expected-error {{'decltype(auto)' in return type deduced as 'void' here but deduced as 'int' in earlier return statement}}
+          // expected-note@-3 {{deducing return type for 'operator()'}}
 };
 auto l5 = []() -> decltype(auto) {
   return i;
   return void(); // expected-error {{'decltype(auto)' in return type deduced as 'void' here but deduced as 'int' in earlier return statement}}
+                 // expected-note@-3 {{deducing return type for 'operator()'}}
 };
 
 } // namespace DecltypeAuto
@@ -69,33 +75,41 @@
 auto *f1() { } // expected-error {{cannot deduce return type 'auto *' for function with no return statements}}
 auto *f2() {
   return; // expected-error {{cannot deduce return type 'auto *' from omitted return expression}}
+          // expected-note@-2 {{deducing return type for 'f2'}}
 }
 auto *f3() {
   return void(); // expected-error {{cannot deduce return type 'auto *' from returned value of type 'void'}}
+                 // expected-note@-2 {{deducing return type for 'f3'}}
 }
 auto *f4() {
   return &i;
   return; // expected-error {{cannot deduce return type 'auto *' from omitted return expression}}
+          // expected-note@-3 {{deducing return type for 'f4'}}
 }
 auto *f5() {
   return &i;
   return void(); // expected-error {{cannot deduce return type 'auto *' from returned value of type 'void'}}
+                 // expected-note@-3 {{deducing return type for 'f5'}}
 }
 
 auto l1 = []() -> auto* { }; // expected-error {{cannot deduce return type 'auto *' for function with no return statements}}
 auto l2 = []() -> auto* {
   return; // expected-error {{cannot deduce return type 'auto *' from omitted return expression}}
+          // expected-note@-2 {{deducing return type for 'operator()'}}
 };
 auto l3 = []() -> auto* {
   return void(); // expected-error {{cannot deduce return type 'auto *' from returned value of type 'void'}}
+                 // expected-note@-2 {{deducing return type for 'operator()'}}
 };
 auto l4 = []() -> auto* {
   return &i;
   return; // expected-error {{cannot deduce return type 'auto *' from omitted return expression}}
+          // expected-note@-3 {{deducing return type for 'operator()'}}
 };
 auto l5 = []() -> auto* {
   return &i;
   return void(); // expected-error {{cannot deduce return type 'auto *' from returned value of type 'void'}}
+                 // expected-note@-3 {{deducing return type for 'operator()'}}
 };
 } // namespace AutoPtr
 
@@ -105,32 +119,39 @@
 }
 auto& f2() {
   return; // expected-error {{cannot deduce return type 'auto &' from omitted return expression}}
+          // expected-note@-2 {{deducing return type for 'f2'}}
 }
 auto& f3() {
   return void(); // expected-error@-1 {{cannot form a reference to 'void'}}
+                 // expected-note@-2 {{deducing return type for 'f3'}}
 }
 auto& f4() {
   return i;
   return; // expected-error {{cannot deduce return type 'auto &' from omitted return expression}}
+          // expected-note@-3 {{deducing return type for 'f4'}}
 }
 auto& f5() {
   return i;
   return void(); // expected-error@-2 {{cannot form a reference to 'void'}}
+                 // expected-note@-3 {{deducing return type for 'f5'}}
 }
 auto& f6() { return 42; } // expected-error {{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'}}
 
 auto l1 = []() -> auto& { }; // expected-error {{cannot deduce return type 'auto &' for function with no return statements}}
 auto l2 = []() -> auto& {
   return; // expected-error {{cannot deduce return type 'auto &' from omitted return expression}}
+          // expected-note@-2 {{deducing return type for 'operator()'}}
 };
 auto l3 = []() -> auto& { // expected-error {{cannot form a reference to 'void'}}
+                          // expected-note@-1 {{deducing return type for 'operator()'}}
   return void();
 };
-auto l4 = []() -> auto& {
+auto l4 = []() -> auto& { // expected-note {{deducing return type for 'operator()'}}
   return i;
   return; // expected-error {{cannot deduce return type 'auto &' from omitted return expression}}
 };
 auto l5 = []() -> auto& { // expected-error {{cannot form a reference to 'void'}}
+                          // expected-note@-1 {{deducing return type for 'operator()'}}
   return i;
   return void();
 };
Index: clang/test/SemaCXX/deduced-return-type-cxx14.cpp
===================================================================
--- clang/test/SemaCXX/deduced-return-type-cxx14.cpp
+++ clang/test/SemaCXX/deduced-return-type-cxx14.cpp
@@ -82,6 +82,7 @@
 
 auto *ptr_1() {
   return 100; // expected-error {{cannot deduce return type 'auto *' from returned value of type 'int'}}
+              // expected-note@-2 {{deducing return type for 'ptr_1'}}
 }
 
 const auto &ref_1() {
@@ -106,6 +107,7 @@
 auto fac_2(int n) { // expected-note {{declared here}}
   if (n > 2)
     return n * fac_2(n-1); // expected-error {{cannot be used before it is defined}}
+                           // expected-note@-3 {{deducing return type for 'fac_2'}}
   return n;
 }
 
@@ -122,6 +124,7 @@
   if (false)
     return;
   return 0; // expected-error {{'auto' in return type deduced as 'int' here but deduced as 'void' in earlier return statement}}
+            // expected-note@-6 {{deducing return type for 'void_ret_4'}}
 }
 
 namespace Templates {
Index: clang/test/SemaCXX/cxx2b-consteval-if.cpp
===================================================================
--- clang/test/SemaCXX/cxx2b-consteval-if.cpp
+++ clang/test/SemaCXX/cxx2b-consteval-if.cpp
@@ -4,11 +4,13 @@
 constexpr auto f() {
   if consteval  { return 0;   }
   if !consteval { return 0.0; } // expected-error {{'auto' in return type deduced as 'double' here but deduced as 'int' in earlier return statement}}
+                                // expected-note@-3 {{deducing return type for 'f'}}
 }
 
 constexpr auto g() {
   if !consteval { return 0;   }
   if consteval  { return 0.0; } // expected-error {{'auto' in return type deduced as 'double' here but deduced as 'int' in earlier return statement}}
+                                // expected-note@-3 {{deducing return type for 'g'}}
 }
 
 constexpr auto h() {
@@ -19,11 +21,12 @@
 constexpr auto i() {
   if consteval {
     if consteval { // expected-warning {{consteval if is always true in an immediate context}}
-	  return 1;
-	}
-	return 2;
+      return 1;
+    }
+    return 2;
   } else {
     return 1.0; // expected-error {{'auto' in return type deduced as 'double' here but deduced as 'int' in earlier return statement}}
+                // expected-note@-8 {{deducing return type for 'i'}}
   }
 }
 
Index: clang/test/SemaCXX/cxx20-p0388-unbound-ary.cpp
===================================================================
--- clang/test/SemaCXX/cxx20-p0388-unbound-ary.cpp
+++ clang/test/SemaCXX/cxx20-p0388-unbound-ary.cpp
@@ -11,6 +11,7 @@
   int(&r1)[] = ga;
 #if __cplusplus < 202002
   // expected-error@-2{{cannot bind to a value of unrelated type}}
+  // expected-note@-4{{deducing return type for 'frob1'}}
 #endif
 
   return r1;
@@ -20,6 +21,7 @@
   int(&r2)[] = arp;
 #if __cplusplus < 202002
   // expected-error@-2{{cannot bind to a value of unrelated type}}
+  // expected-note@-4{{deducing return type for 'frob2'}}
 #endif
 
   return r2;
Index: clang/test/Sema/invalid-bitwidth-expr.mm
===================================================================
--- clang/test/Sema/invalid-bitwidth-expr.mm
+++ clang/test/Sema/invalid-bitwidth-expr.mm
@@ -13,6 +13,7 @@
 
 auto func() {
   return undef(); // expected-error {{use of undeclared identifier}}
+                  // expected-note@-2 {{deducing return type for 'func'}}
 }
 struct Y {
   int X : func();
@@ -23,7 +24,7 @@
 template <typename T>
 struct Base {};
 template <typename T>
-auto func() {
+auto func() { // expected-note {{deducing return type for 'func<int>'}}
   // error-bit should be propagated from TemplateArgument to NestNameSpecifier.
   class Base<decltype(Foo(T()))>::type C; // expected-error {{no matching function for call to 'Foo'}}
   return C;
Index: clang/lib/Sema/SemaStmt.cpp
===================================================================
--- clang/lib/Sema/SemaStmt.cpp
+++ clang/lib/Sema/SemaStmt.cpp
@@ -3801,8 +3801,12 @@
       Diag(RetExpr->getExprLoc(), diag::err_auto_fn_deduction_failure)
         << OrigResultType.getType() << RetExpr->getType();
 
-    if (DAR != DAR_Succeeded)
+    if (DAR != DAR_Succeeded) {
+      if (OrigResultType.getBeginLoc().isValid())
+        Diag(OrigResultType.getBeginLoc(), diag::note_deducing_return_type_for)
+            << FD << OrigResultType.getSourceRange();
       return true;
+    }
 
     // If a local type is part of the returned type, mark its fields as
     // referenced.
@@ -3815,6 +3819,9 @@
     if (!FD->getReturnType()->getAs<AutoType>()) {
       Diag(ReturnLoc, diag::err_auto_fn_return_void_but_not_auto)
           << OrigResultType.getType();
+      if (OrigResultType.getBeginLoc().isValid())
+        Diag(OrigResultType.getBeginLoc(), diag::note_deducing_return_type_for)
+            << FD << OrigResultType.getSourceRange();
       return true;
     }
     // In the case of a return with no operand, the initializer is considered
@@ -3828,8 +3835,12 @@
       Diag(ReturnLoc, diag::err_auto_fn_deduction_failure)
         << OrigResultType.getType() << Dummy->getType();
 
-    if (DAR != DAR_Succeeded)
+    if (DAR != DAR_Succeeded) {
+      if (OrigResultType.getBeginLoc().isValid())
+        Diag(OrigResultType.getBeginLoc(), diag::note_deducing_return_type_for)
+            << FD << OrigResultType.getSourceRange();
       return true;
+    }
   }
 
   // CUDA: Kernel function must have 'void' return type.
@@ -3866,6 +3877,9 @@
         Diag(ReturnLoc, diag::err_auto_fn_different_deductions)
           << (AT->isDecltypeAuto() ? 1 : 0)
           << NewAT->getDeducedType() << DeducedT;
+        if (OrigResultType.getBeginLoc().isValid())
+          Diag(OrigResultType.getBeginLoc(), diag::note_deducing_return_type_for)
+            << FD << OrigResultType.getSourceRange();
       }
       return true;
     }
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2466,6 +2466,8 @@
 def warn_cxx11_compat_deduced_return_type : Warning<
   "return type deduction is incompatible with C++ standards before C++14">,
   InGroup<CXXPre14Compat>, DefaultIgnore;
+def note_deducing_return_type_for : Note<
+  "deducing return type for %0">;
 
 // C++11 override control
 def override_keyword_only_allowed_on_virtual_member_functions : Error<
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to