From 60e141e1f87211ca831de6821003d80fe20a06f3 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Sat, 4 May 2013 07:00:32 +0000 Subject: Implement most of N3638 (return type deduction for normal functions). Missing (somewhat ironically) is support for the new deduction rules in lambda functions, plus PCH support for return type patching. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181108 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp | 33 +- .../dcl.spec/dcl.type/dcl.spec.auto/p6-1y.cpp | 31 ++ test/SemaCXX/cxx1y-deduced-return-type.cpp | 338 +++++++++++++++++++++ 3 files changed, 401 insertions(+), 1 deletion(-) create mode 100644 test/SemaCXX/cxx1y-deduced-return-type.cpp (limited to 'test') diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp index 7245b9b47f..39c547b9ae 100644 --- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp +++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++1y +// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++1y -DCXX1Y // RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11 -Wno-c++1y-extensions // FIXME: This is in p11 (?) in C++1y. @@ -41,3 +41,34 @@ void i() { decltype(auto) x = 5; decltype(auto) int r; // expected-error {{cannot combine with previous 'decltype(auto)' declaration specifier}} expected-error {{requires an initializer}} } + +namespace p3_example { + template struct is_same_impl { + static const bool value = false; + }; + template struct is_same_impl { + static const bool value = true; + }; + template constexpr bool is_same() { + return is_same_impl::value; + } + + auto x = 5; + const auto *v = &x, u = 6; + static auto y = 0.0; + auto int r; // expected-warning {{storage class}} expected-error {{file-scope}} + + static_assert(is_same(), ""); + static_assert(is_same(), ""); + static_assert(is_same(), ""); + static_assert(is_same(), ""); + +#ifdef CXX1Y + auto f() -> int; + auto g() { return 0.0; } + auto h(); + + static_assert(is_same(), ""); + static_assert(is_same(), ""); +#endif +} diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6-1y.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6-1y.cpp index 25b5f1984c..66085eda3d 100644 --- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6-1y.cpp +++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6-1y.cpp @@ -64,3 +64,34 @@ decltype(auto) *v4 = { 0 }; // expected-error {{cannot form pointer to 'decltype auto multi1a = 0, &multi1b = multi1a; auto multi1c = multi1a, multi1d = multi1b; decltype(auto) multi1e = multi1a, multi1f = multi1b; // expected-error {{'decltype(auto)' deduced as 'int' in declaration of 'multi1e' and deduced as 'int &' in declaration of 'multi1f'}} + +auto f1a() { return 0; } +decltype(auto) f1d() { return 0; } +using Int = decltype(f1a()); +using Int = decltype(f1d()); + +auto f2a(int n) { return n; } +decltype(auto) f2d(int n) { return n; } +using Int = decltype(f2a(0)); +using Int = decltype(f2d(0)); + +auto f3a(int n) { return (n); } +decltype(auto) f3d(int n) { return (n); } // expected-warning {{reference to stack memory}} +using Int = decltype(f3a(0)); +using IntLRef = decltype(f3d(0)); + +auto f4a(int n) { return f(); } +decltype(auto) f4d(int n) { return f(); } +using Int = decltype(f4a(0)); +using IntRRef = decltype(f4d(0)); + +auto f5aa(int n) { auto x = f(); return x; } +auto f5ad(int n) { decltype(auto) x = f(); return x; } +decltype(auto) f5da(int n) { auto x = f(); return x; } +decltype(auto) f5dd(int n) { decltype(auto) x = f(); return x; } // expected-error {{rvalue reference to type 'int' cannot bind to lvalue}} +using Int = decltype(f5aa(0)); +using Int = decltype(f5ad(0)); +using Int = decltype(f5da(0)); + +auto init_list_1() { return { 1, 2, 3 }; } // expected-error {{cannot deduce return type from initializer list}} +decltype(auto) init_list_2() { return { 1, 2, 3 }; } // expected-error {{cannot deduce return type from initializer list}} diff --git a/test/SemaCXX/cxx1y-deduced-return-type.cpp b/test/SemaCXX/cxx1y-deduced-return-type.cpp new file mode 100644 index 0000000000..f0146f88d6 --- /dev/null +++ b/test/SemaCXX/cxx1y-deduced-return-type.cpp @@ -0,0 +1,338 @@ +// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only %s + +auto f(); // expected-note {{previous}} +int f(); // expected-error {{differ only in their return type}} + +auto &g(); +auto g() -> auto &; + +auto h() -> auto *; +auto *h(); + +struct Conv1 { + operator auto(); // expected-note {{declared here}} +} conv1; +int conv1a = conv1; // expected-error {{function 'operator auto' with deduced return type cannot be used before it is defined}} +// expected-error@-1 {{no viable conversion}} +Conv1::operator auto() { return 123; } +int conv1b = conv1; +int conv1c = conv1.operator auto(); +int conv1d = conv1.operator int(); // expected-error {{no member named 'operator int'}} + +struct Conv2 { + operator auto() { return 0; } // expected-note 2{{previous}} + operator auto() { return 0.; } // expected-error {{cannot be redeclared}} expected-error {{redefinition of 'operator auto'}} +}; + +struct Conv3 { + operator auto() { int *p = nullptr; return p; } // expected-note {{candidate}} + operator auto*() { int *p = nullptr; return p; } // expected-note {{candidate}} +} conv3; +int *conv3a = conv3; // expected-error {{ambiguous}} +int *conv3b = conv3.operator auto(); +int *conv3c = conv3.operator auto*(); + +template +struct Conv4 { + operator auto() { return T(); } +}; +Conv4 conv4int; +int conv4a = conv4int; +int conv4b = conv4int.operator auto(); + +auto a(); +auto a() { return 0; } +using T = decltype(a()); +using T = int; +auto a(); // expected-note {{previous}} +using T = decltype(a()); +auto *a(); // expected-error {{differ only in their return type}} + +auto b(bool k) { + if (k) + return "hello"; + return "goodbye"; +} + +auto *ptr_1() { + return 100; // expected-error {{cannot deduce return type 'auto *' from returned value of type 'int'}} +} + +const auto &ref_1() { + return 0; // expected-warning {{returning reference to local temporary}} +} + +auto init_list() { + return { 1, 2, 3 }; // expected-error {{cannot deduce return type from initializer list}} +} + +auto fwd_decl(); // expected-note 2{{here}} + +int n = fwd_decl(); // expected-error {{function 'fwd_decl' with deduced return type cannot be used before it is defined}} +int k = sizeof(fwd_decl()); // expected-error {{used before it is defined}} + +auto fac(int n) { + if (n <= 2) + return n; + return n * fac(n-1); // ok +} + +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}} + return n; +} + +auto void_ret() {} +using Void = void; +using Void = decltype(void_ret()); + +auto &void_ret_2() {} // expected-error {{cannot deduce return type 'auto &' for function with no return statements}} +const auto void_ret_3() {} // ok, return type 'const void' is adjusted to 'void' + +const auto void_ret_4() { + if (false) + return void(); + if (false) + return; + return 0; // expected-error {{'auto' in return type deduced as 'int' here but deduced as 'void' in earlier return statement}} +} + +namespace Templates { + template auto f1() { + return T() + 1; + } + template auto &f2(T &&v) { return v; } + int a = f1(); + const int &b = f2(0); + double d; + float &c = f2(0.0); // expected-error {{non-const lvalue reference to type 'float' cannot bind to a value of unrelated type 'double'}} + + template auto fwd_decl(); // expected-note {{declared here}} + int e = fwd_decl(); // expected-error {{cannot be used before it is defined}} + template auto fwd_decl() { return 0; } + int f = fwd_decl(); + template auto fwd_decl(); + int g = fwd_decl(); + + auto (*p)() = f1; // expected-error {{incompatible initializer}} + auto (*q)() = f1; // ok + + typedef decltype(f2(1.2)) dbl; // expected-note {{previous}} + typedef float dbl; // expected-error {{typedef redefinition with different types ('float' vs 'decltype(f2(1.2))' (aka 'double &'))}} + + extern template auto fwd_decl(); + int k1 = fwd_decl(); + extern template int fwd_decl(); // expected-error {{does not refer to a function template}} + int k2 = fwd_decl(); + + template auto instantiate() { T::error; } // expected-error {{has no members}} + extern template auto instantiate(); // ok + int k = instantiate(); // expected-note {{in instantiation of}} + template<> auto instantiate() {} // ok + template<> void instantiate() {} // expected-error {{no function template matches}} + + template auto arg_single() { return 0; } + template auto arg_multi() { return 0l; } + template auto arg_multi(int) { return "bad"; } + template struct Outer { + static auto arg_single() { return 0.f; } + static auto arg_multi() { return 0.; } + static auto arg_multi(int) { return "bad"; } + }; + template T &take_fn(T (*p)()); + + int &check1 = take_fn(arg_single); // expected-error {{no matching}} expected-note@-2 {{couldn't infer}} + int &check2 = take_fn(arg_single); + int &check3 = take_fn(arg_single); // expected-error {{no matching}} expected-note@-4{{no overload of 'arg_single'}} + int &check4 = take_fn(arg_single); + long &check5 = take_fn(arg_multi); // expected-error {{no matching}} expected-note@-6 {{couldn't infer}} + long &check6 = take_fn(arg_multi); + long &check7 = take_fn(arg_multi); // expected-error {{no matching}} expected-note@-8{{no overload of 'arg_multi'}} + long &check8 = take_fn(arg_multi); + + float &mem_check1 = take_fn(Outer::arg_single); + float &mem_check2 = take_fn(Outer::arg_single); + double &mem_check3 = take_fn(Outer::arg_multi); + double &mem_check4 = take_fn(Outer::arg_multi); + + namespace Deduce1 { + template auto f() { return 0; } // expected-note {{candidate}} + template void g(T(*)()); // expected-note 2{{candidate}} + void h() { + auto p = f; + auto (*q)() = f; + int (*r)() = f; // expected-error {{does not match}} + g(f); + g(f); // expected-error {{no matching function}} + g(f); // expected-error {{no matching function}} + } + } + + namespace Deduce2 { + template auto f(int) { return 0; } // expected-note {{candidate}} + template void g(T(*)(int)); // expected-note 2{{candidate}} + void h() { + auto p = f; + auto (*q)(int) = f; + int (*r)(int) = f; // expected-error {{does not match}} + g(f); + g(f); // expected-error {{no matching function}} + g(f); // expected-error {{no matching function}} + } + } + + namespace Deduce3 { + template auto f(T) { return 0; } + template void g(T(*)(int)); // expected-note {{couldn't infer}} + void h() { + auto p = f; + auto (*q)(int) = f; + int (*r)(int) = f; // ok + g(f); + g(f); // ok + g(f); // expected-error {{no matching function}} + } + } + + namespace DeduceInDeducedReturnType { + template auto f() -> auto (T::*)(U) { + int (T::*result)(U) = nullptr; + return result; + } + struct S {}; + int (S::*(*p)())(double) = f; + int (S::*(*q)())(double) = f; + } +} + +auto fwd_decl_using(); +namespace N { using ::fwd_decl_using; } +auto fwd_decl_using() { return 0; } +namespace N { int k = N::fwd_decl_using(); } + +namespace OverloadResolutionNonTemplate { + auto f(); + auto f(int); // expected-note {{here}} + + int &g(int (*f)()); // expected-note {{not viable: no overload of 'f' matching 'int (*)()'}} + char &g(int (*f)(int)); // expected-note {{not viable: no overload of 'f' matching 'int (*)(int)'}} + + int a = g(f); // expected-error {{no matching function}} + + auto f() { return 0; } + + // FIXME: It's not completely clear whether this should be ill-formed. + int &b = g(f); // expected-error {{used before it is defined}} + + auto f(int) { return 0.0; } + + int &c = g(f); // ok +} + +namespace OverloadResolutionTemplate { + auto f(); + template auto f(T); + + int &g(int (*f)()); // expected-note {{not viable: no overload of 'f' matching 'int (*)()'}} expected-note {{candidate}} + char &g(int (*f)(int)); // expected-note {{not viable: no overload of 'f' matching 'int (*)(int)'}} expected-note {{candidate}} + + int a = g(f); // expected-error {{no matching function}} + + auto f() { return 0; } + + int &b = g(f); // ok (presumably), due to deduction failure forming type of 'f' + + template auto f(T) { return 0; } + + int &c = g(f); // expected-error {{ambiguous}} +} + +namespace DefaultedMethods { + struct A { + auto operator=(const A&) = default; // expected-error {{must return 'DefaultedMethods::A &'}} + A &operator=(A&&); // expected-note {{previous}} + }; + auto A::operator=(A&&) = default; // expected-error {{differs from the declaration in the return type}} +} + +namespace Constexpr { + constexpr auto f1(int n) { return n; } + struct NonLiteral { ~NonLiteral(); } nl; // expected-note {{user-provided destructor}} + constexpr auto f2(int n) { return nl; } // expected-error {{return type 'Constexpr::NonLiteral' is not a literal type}} +} + +// It's not really clear whether these are valid, but this matches g++. +using size_t = decltype(sizeof(0)); +auto operator new(size_t n, const char*); // expected-error {{must return type 'void *'}} +auto operator delete(void *, const char*); // expected-error {{must return type 'void'}} + +namespace Virtual { + struct S { + virtual auto f() { return 0; } // expected-error {{function with deduced return type cannot be virtual}} expected-note {{here}} + }; + // Allow 'auto' anyway for error recovery. + struct T : S { + int f(); + }; + struct U : S { + auto f(); // expected-error {{different return}} + }; + + // And here's why... + struct V { virtual auto f(); }; // expected-error {{cannot be virtual}} + struct W : V { virtual auto f(); }; // expected-error {{cannot be virtual}} + auto V::f() { return 0; } // in tu1.cpp + auto W::f() { return 0.0; } // in tu2.cpp + W w; + int k1 = w.f(); + int k2 = ((V&)w).f(); +} + +namespace std_examples { + +namespace NoReturn { + auto f() {} + void (*p)() = &f; + + auto *g() {} // expected-error {{cannot deduce return type 'auto *' for function with no return statements}} +} + +namespace UseBeforeComplete { + auto n = n; // expected-error {{variable 'n' declared with 'auto' type cannot appear in its own initializer}} + auto f(); // expected-note {{declared here}} + void g() { &f; } // expected-error {{function 'f' with deduced return type cannot be used before it is defined}} + auto sum(int i) { + if (i == 1) + return i; + else + return sum(i - 1) + i; + } +} + +namespace Redecl { + auto f(); + auto f() { return 42; } + auto f(); // expected-note 2{{previous}} + int f(); // expected-error {{functions that differ only in their return type cannot be overloaded}} + decltype(auto) f(); // expected-error {{cannot be overloaded}} + + template auto g(T t) { return t; } // expected-note {{candidate}} + template auto g(int); + template char g(char); // expected-error {{does not refer to a function}} + template<> auto g(double); + + template T g(T t) { return t; } // expected-note {{candidate}} + template char g(char); + template auto g(float); + + void h() { return g(42); } // expected-error {{ambiguous}} +} + +namespace ExplicitInstantiationDecl { + template auto f(T t) { return t; } + extern template auto f(int); + int (*p)(int) = f; +} + +} -- cgit v1.2.3-18-g5258