aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2013-05-04 07:00:32 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2013-05-04 07:00:32 +0000
commit60e141e1f87211ca831de6821003d80fe20a06f3 (patch)
tree1d3062ca5c7b78cecae06c05ea1f90973d95d059 /test
parent82f145d4ed86d19cb2a1680cda53fdc39bb38eb6 (diff)
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
Diffstat (limited to 'test')
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp33
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6-1y.cpp31
-rw-r--r--test/SemaCXX/cxx1y-deduced-return-type.cpp338
3 files changed, 401 insertions, 1 deletions
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<typename T, typename U> struct is_same_impl {
+ static const bool value = false;
+ };
+ template<typename T> struct is_same_impl<T, T> {
+ static const bool value = true;
+ };
+ template<typename T, typename U> constexpr bool is_same() {
+ return is_same_impl<T,U>::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<decltype(x), int>(), "");
+ static_assert(is_same<decltype(v), const int*>(), "");
+ static_assert(is_same<decltype(u), const int>(), "");
+ static_assert(is_same<decltype(y), double>(), "");
+
+#ifdef CXX1Y
+ auto f() -> int;
+ auto g() { return 0.0; }
+ auto h();
+
+ static_assert(is_same<decltype(f), int()>(), "");
+ static_assert(is_same<decltype(g), double()>(), "");
+#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<typename T>
+struct Conv4 {
+ operator auto() { return T(); }
+};
+Conv4<int> 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<typename T> auto f1() {
+ return T() + 1;
+ }
+ template<typename T> auto &f2(T &&v) { return v; }
+ int a = f1<int>();
+ 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<typename T> auto fwd_decl(); // expected-note {{declared here}}
+ int e = fwd_decl<int>(); // expected-error {{cannot be used before it is defined}}
+ template<typename T> auto fwd_decl() { return 0; }
+ int f = fwd_decl<int>();
+ template<typename T> auto fwd_decl();
+ int g = fwd_decl<char>();
+
+ auto (*p)() = f1; // expected-error {{incompatible initializer}}
+ auto (*q)() = f1<int>; // 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<double>();
+ int k1 = fwd_decl<double>();
+ extern template int fwd_decl<char>(); // expected-error {{does not refer to a function template}}
+ int k2 = fwd_decl<char>();
+
+ template<typename T> auto instantiate() { T::error; } // expected-error {{has no members}}
+ extern template auto instantiate<int>(); // ok
+ int k = instantiate<int>(); // expected-note {{in instantiation of}}
+ template<> auto instantiate<char>() {} // ok
+ template<> void instantiate<double>() {} // expected-error {{no function template matches}}
+
+ template<typename T> auto arg_single() { return 0; }
+ template<typename T> auto arg_multi() { return 0l; }
+ template<typename T> auto arg_multi(int) { return "bad"; }
+ template<typename T> struct Outer {
+ static auto arg_single() { return 0.f; }
+ static auto arg_multi() { return 0.; }
+ static auto arg_multi(int) { return "bad"; }
+ };
+ template<typename T> 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>);
+ int &check3 = take_fn<int>(arg_single); // expected-error {{no matching}} expected-note@-4{{no overload of 'arg_single'}}
+ int &check4 = take_fn<int>(arg_single<int>);
+ long &check5 = take_fn(arg_multi); // expected-error {{no matching}} expected-note@-6 {{couldn't infer}}
+ long &check6 = take_fn(arg_multi<int>);
+ long &check7 = take_fn<long>(arg_multi); // expected-error {{no matching}} expected-note@-8{{no overload of 'arg_multi'}}
+ long &check8 = take_fn<long>(arg_multi<int>);
+
+ float &mem_check1 = take_fn(Outer<int>::arg_single);
+ float &mem_check2 = take_fn<float>(Outer<char>::arg_single);
+ double &mem_check3 = take_fn(Outer<long>::arg_multi);
+ double &mem_check4 = take_fn<double>(Outer<double>::arg_multi);
+
+ namespace Deduce1 {
+ template<typename T> auto f() { return 0; } // expected-note {{candidate}}
+ template<typename T> void g(T(*)()); // expected-note 2{{candidate}}
+ void h() {
+ auto p = f<int>;
+ auto (*q)() = f<int>;
+ int (*r)() = f; // expected-error {{does not match}}
+ g(f<int>);
+ g<int>(f); // expected-error {{no matching function}}
+ g(f); // expected-error {{no matching function}}
+ }
+ }
+
+ namespace Deduce2 {
+ template<typename T> auto f(int) { return 0; } // expected-note {{candidate}}
+ template<typename T> void g(T(*)(int)); // expected-note 2{{candidate}}
+ void h() {
+ auto p = f<int>;
+ auto (*q)(int) = f<int>;
+ int (*r)(int) = f; // expected-error {{does not match}}
+ g(f<int>);
+ g<int>(f); // expected-error {{no matching function}}
+ g(f); // expected-error {{no matching function}}
+ }
+ }
+
+ namespace Deduce3 {
+ template<typename T> auto f(T) { return 0; }
+ template<typename T> void g(T(*)(int)); // expected-note {{couldn't infer}}
+ void h() {
+ auto p = f<int>;
+ auto (*q)(int) = f<int>;
+ int (*r)(int) = f; // ok
+ g(f<int>);
+ g<int>(f); // ok
+ g(f); // expected-error {{no matching function}}
+ }
+ }
+
+ namespace DeduceInDeducedReturnType {
+ template<typename T, typename U> auto f() -> auto (T::*)(U) {
+ int (T::*result)(U) = nullptr;
+ return result;
+ }
+ struct S {};
+ int (S::*(*p)())(double) = f;
+ int (S::*(*q)())(double) = f<S, double>;
+ }
+}
+
+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<typename T> 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<int>'
+
+ template<typename T> 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<typename T> 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<typename T> 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<typename T> auto f(T t) { return t; }
+ extern template auto f(int);
+ int (*p)(int) = f;
+}
+
+}