diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2013-03-18 21:12:30 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2013-03-18 21:12:30 +0000 |
commit | 07b0fdcee8d64222b274779d02851cc53d18e0db (patch) | |
tree | b41546507621a780fb34e63269396ac526ae391f /test/CXX | |
parent | 5b222059399ec9cccba7a393dc470adfb8a3db0f (diff) |
Bring inheriting constructor implementation up-to-date with current defect
reports, and implement implicit definition of inheriting constructors.
Remaining missing features: inheriting constructor templates, implicit
exception specifications for inheriting constructors, inheriting constructors
from dependent bases.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@177320 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test/CXX')
-rw-r--r-- | test/CXX/special/class.inhctor/elsewhere.cpp | 20 | ||||
-rw-r--r-- | test/CXX/special/class.inhctor/p1.cpp | 31 | ||||
-rw-r--r-- | test/CXX/special/class.inhctor/p2.cpp | 87 | ||||
-rw-r--r-- | test/CXX/special/class.inhctor/p3.cpp | 12 | ||||
-rw-r--r-- | test/CXX/special/class.inhctor/p4.cpp | 70 | ||||
-rw-r--r-- | test/CXX/special/class.inhctor/p7.cpp | 12 | ||||
-rw-r--r-- | test/CXX/special/class.inhctor/p8.cpp | 21 |
7 files changed, 231 insertions, 22 deletions
diff --git a/test/CXX/special/class.inhctor/elsewhere.cpp b/test/CXX/special/class.inhctor/elsewhere.cpp index 09fd3d50dc..184e90298b 100644 --- a/test/CXX/special/class.inhctor/elsewhere.cpp +++ b/test/CXX/special/class.inhctor/elsewhere.cpp @@ -9,49 +9,49 @@ struct B1 { B1(int); }; -using B1::B1; // expected-error {{using declaration can not refer to class member}} expected-error {{not supported}} +using B1::B1; // expected-error {{using declaration can not refer to class member}} -// C++0x [namespace.udecl]p10: +// C++11 [namespace.udecl]p10: // A using-declaration is a declaration and can therefore be used repeatedly // where (and only where) multiple declarations are allowed. struct I1 : B1 { - using B1::B1; // expected-note {{previous using declaration}} expected-error {{not supported}} - using B1::B1; // expected-error {{redeclaration of using decl}} expected-error {{not supported}} + using B1::B1; // expected-note {{previous using declaration}} + using B1::B1; // expected-error {{redeclaration of using decl}} }; -// C++0x [namespace.udecl]p3: +// C++11 [namespace.udecl]p3: // In a using declaration used as a member-declaration, the nested-name- // specifier shall name a base class of the class being defined. // If such a using-declaration names a constructor, the nested-name-specifier // shall name a direct base class of the class being defined. struct D1 : I1 { - using B1::B1; // expected-error {{'B1' is not a direct base of 'D1', can not inherit constructors}} expected-error {{not supported}} + using B1::B1; // expected-error {{'B1' is not a direct base of 'D1', can not inherit constructors}} }; template<typename T> struct A {}; template<typename T> struct B : A<bool>, A<char> { - using A<T>::A; // expected-error {{'A<double>::', which is not a base class of 'B<double>'}} expected-error {{not supported}} + using A<T>::A; // expected-error {{'A<double>::', which is not a base class of 'B<double>'}} }; B<bool> bb; B<char> bc; B<double> bd; // expected-note {{here}} template<typename T> struct C : A<T> { - using A<bool>::A; // expected-error {{'A<bool>::', which is not a base class of 'C<char>'}} expected-error {{not supported}} + using A<bool>::A; // expected-error {{'A<bool>::', which is not a base class of 'C<char>'}} }; C<bool> cb; C<char> cc; // expected-note {{here}} template<typename T> struct D : A<T> {}; template<typename T> struct E : D<T> { - using A<bool>::A; // expected-error {{'A<bool>' is not a direct base of 'E<bool>', can not inherit}} expected-error {{not supported}} + using A<bool>::A; // expected-error {{'A<bool>' is not a direct base of 'E<bool>', can not inherit}} }; E<bool> eb; // expected-note {{here}} template<typename T> struct F : D<bool> { - using A<T>::A; // expected-error {{'A<bool>' is not a direct base of 'F<bool>'}} expected-error {{not supported}} + using A<T>::A; // expected-error {{'A<bool>' is not a direct base of 'F<bool>'}} }; F<bool> fb; // expected-note {{here}} diff --git a/test/CXX/special/class.inhctor/p1.cpp b/test/CXX/special/class.inhctor/p1.cpp new file mode 100644 index 0000000000..57e91504d6 --- /dev/null +++ b/test/CXX/special/class.inhctor/p1.cpp @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -std=c++11 -verify %s +// Per a core issue (no number yet), an ellipsis is always dropped. +struct A { + A(...); // expected-note {{here}} + A(int = 0, int = 0, int = 0, int = 0, ...); // expected-note 5{{here}} + A(int = 0, int = 0, ...); // expected-note {{here}} +}; + +struct B : A { // expected-note 3{{candidate}} + using A::A; // expected-warning 3{{inheriting constructor does not inherit ellipsis}} expected-note 4{{candidate}} expected-note 2{{deleted}} +}; + +B b0{}; +// expected-error@-1 {{call to implicitly-deleted default constructor}} +// expected-note@9 {{default constructor of 'B' is implicitly deleted because base class 'A' has multiple default constructors}} + +B b1{1}; +// FIXME: explain why the inheriting constructor was deleted +// expected-error@-2 {{call to implicitly-deleted function of 'B'}} + +B b2{1,2}; +// expected-error@-1 {{call to implicitly-deleted function of 'B'}} + +B b3{1,2,3}; +// ok + +B b4{1,2,3,4}; +// ok + +B b5{1,2,3,4,5}; +// expected-error@-1 {{no matching constructor for initialization of 'B'}} diff --git a/test/CXX/special/class.inhctor/p2.cpp b/test/CXX/special/class.inhctor/p2.cpp new file mode 100644 index 0000000000..e4267385ce --- /dev/null +++ b/test/CXX/special/class.inhctor/p2.cpp @@ -0,0 +1,87 @@ +// RUN: %clang_cc1 -std=c++11 -verify %s + +template<int> struct X {}; + +// Constructor characteristics are: +// - the template parameter list [FIXME] +// - the parameter-type-list +// - absence or presence of explicit +// - absence or presence of constexpr +struct A { + A(X<0>) {} // expected-note 2{{here}} + constexpr A(X<1>) {} + explicit A(X<2>) {} // expected-note 3{{here}} + explicit constexpr A(X<3>) {} // expected-note 2{{here}} +}; + +A a0 { X<0>{} }; +A a0i = { X<0>{} }; +constexpr A a0c { X<0>{} }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}} +constexpr A a0ic = { X<0>{} }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}} + +A a1 { X<1>{} }; +A a1i = { X<1>{} }; +constexpr A a1c { X<1>{} }; +constexpr A a1ic = { X<1>{} }; + +A a2 { X<2>{} }; +A a2i = { X<2>{} }; // expected-error {{constructor is explicit}} +constexpr A a2c { X<2>{} }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}} +constexpr A a2ic = { X<2>{} }; // expected-error {{constructor is explicit}} + +A a3 { X<3>{} }; +A a3i = { X<3>{} }; // expected-error {{constructor is explicit}} +constexpr A a3c { X<3>{} }; +constexpr A a3ic = { X<3>{} }; // expected-error {{constructor is explicit}} + + +struct B : A { + using A::A; // expected-note 7{{here}} +}; + +B b0 { X<0>{} }; +B b0i = { X<0>{} }; +constexpr B b0c { X<0>{} }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}} +constexpr B b0ic = { X<0>{} }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}} + +B b1 { X<1>{} }; +B b1i = { X<1>{} }; +constexpr B b1c { X<1>{} }; +constexpr B b1ic = { X<1>{} }; + +B b2 { X<2>{} }; +B b2i = { X<2>{} }; // expected-error {{constructor is explicit}} +constexpr B b2c { X<2>{} }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}} +constexpr B b2ic = { X<2>{} }; // expected-error {{constructor is explicit}} + +B b3 { X<3>{} }; +B b3i = { X<3>{} }; // expected-error {{constructor is explicit}} +constexpr B b3c { X<3>{} }; +constexpr B b3ic = { X<3>{} }; // expected-error {{constructor is explicit}} + + +// 'constexpr' is OK even if the constructor doesn't obey the constraints. +struct NonLiteral { NonLiteral(); }; +struct NonConstexpr { NonConstexpr(); constexpr NonConstexpr(int); }; // expected-note {{here}} +struct Constexpr { constexpr Constexpr(int) {} }; + +struct BothNonLiteral : NonLiteral, Constexpr { using Constexpr::Constexpr; }; // expected-note {{base class 'NonLiteral' of non-literal type}} +constexpr BothNonLiteral bothNL{42}; // expected-error {{constexpr variable cannot have non-literal type 'const BothNonLiteral'}} + +struct BothNonConstexpr : NonConstexpr, Constexpr { using Constexpr::Constexpr; }; // expected-note {{non-constexpr constructor 'NonConstexpr}} +constexpr BothNonConstexpr bothNC{42}; // expected-error {{must be initialized by a constant expression}} expected-note {{in call to 'BothNonConstexpr(42)'}} + + +struct ConstexprEval { + constexpr ConstexprEval(int a, const char *p) : k(p[a]) {} + char k; +}; +struct ConstexprEval2 { + char k2 = 'x'; +}; +struct ConstexprEval3 : ConstexprEval, ConstexprEval2 { + using ConstexprEval::ConstexprEval; +}; +constexpr ConstexprEval3 ce{4, "foobar"}; +static_assert(ce.k == 'a', ""); +static_assert(ce.k2 == 'x', ""); diff --git a/test/CXX/special/class.inhctor/p3.cpp b/test/CXX/special/class.inhctor/p3.cpp index d7093fb369..f71ab16c0f 100644 --- a/test/CXX/special/class.inhctor/p3.cpp +++ b/test/CXX/special/class.inhctor/p3.cpp @@ -5,7 +5,7 @@ struct B1 { B1(int, int); }; struct D1 : B1 { - using B1::B1; // expected-error {{not supported}} + using B1::B1; }; D1 d1a(1), d1b(1, 1); @@ -15,7 +15,7 @@ struct B2 { explicit B2(int, int = 0, int = 0); }; struct D2 : B2 { // expected-note 2 {{candidate constructor}} - using B2::B2; // expected-error {{not supported}} + using B2::B2; }; D2 d2a(1), d2b(1, 1), d2c(1, 1, 1); @@ -25,18 +25,18 @@ struct B3 { B3(void*); // expected-note {{inherited from here}} }; struct D3 : B3 { // expected-note 2 {{candidate constructor}} - using B3::B3; // expected-note {{candidate constructor (inherited)}} expected-error {{not supported}} + using B3::B3; // expected-note {{candidate constructor (inherited)}} }; D3 fd3() { return 1; } // expected-error {{no viable conversion}} template<typename T> struct T1 : B1 { - using B1::B1; // expected-error {{not supported}} + using B1::B1; }; template<typename T> struct T2 : T1<T> { - using T1<int>::T1; // expected-error {{not supported}} + using T1<int>::T1; }; template<typename T> struct T3 : T1<int> { - using T1<T>::T1; // expected-error {{not supported}} + using T1<T>::T1; }; struct U { friend T1<int>::T1(int); diff --git a/test/CXX/special/class.inhctor/p4.cpp b/test/CXX/special/class.inhctor/p4.cpp new file mode 100644 index 0000000000..eea3bf2973 --- /dev/null +++ b/test/CXX/special/class.inhctor/p4.cpp @@ -0,0 +1,70 @@ +// RUN: %clang_cc1 -std=c++11 -verify %s + +template<int> struct X {}; + +// A[n inheriting] constructor [...] has the same access as the corresponding +// constructor [in the base class]. +struct A { +public: + A(X<0>) {} +protected: + A(X<1>) {} +private: + A(X<2>) {} // expected-note {{declared private here}} + friend class FA; +}; + +struct B : A { + using A::A; // expected-error {{private constructor}} expected-note {{implicitly declared protected here}} + friend class FB; +}; + +B b0{X<0>{}}; +B b1{X<1>{}}; // expected-error {{calling a protected constructor}} +B b2{X<2>{}}; // expected-note {{first required here}} + +struct C : B { + C(X<0> x) : B(x) {} + C(X<1> x) : B(x) {} +}; + +struct FB { + B b0{X<0>{}}; + B b1{X<1>{}}; +}; + +struct FA : A { + using A::A; // expected-note 2{{here}} +}; +FA fa0{X<0>{}}; +FA fa1{X<1>{}}; // expected-error {{calling a protected constructor}} +FA fa2{X<2>{}}; // expected-error {{calling a private constructor}} + + +// It is deleted if the corresponding constructor [...] is deleted. +struct G { + G(int) = delete; +}; +struct H : G { + using G::G; // expected-note {{marked deleted here}} +}; +H h(5); // expected-error {{call to implicitly-deleted function of 'H'}} + + +// Core defect: It is also deleted if multiple base constructors generate the +// same signature. +namespace DRnnnn { + struct A { + constexpr A(int, float = 0) {} + explicit A(int, int = 0) {} + + A(int, int, int = 0) = delete; + }; + struct B : A { + // FIXME: produce notes indicating why it was deleted + using A::A; // expected-note {{here}} + }; + + constexpr B b0(0, 0.0f); // ok, constexpr + B b1(0, 1); // expected-error {{call to implicitly-deleted}} +} diff --git a/test/CXX/special/class.inhctor/p7.cpp b/test/CXX/special/class.inhctor/p7.cpp index bfaa3ac359..9ae160f054 100644 --- a/test/CXX/special/class.inhctor/p7.cpp +++ b/test/CXX/special/class.inhctor/p7.cpp @@ -8,12 +8,12 @@ struct B2 { B2(int); // expected-note {{conflicting constructor}} }; struct D1 : B1, B2 { - using B1::B1; // expected-note {{inherited here}} expected-error {{not supported}} - using B2::B2; // expected-error {{already inherited constructor with the same signature}} expected-error {{not supported}} + using B1::B1; // expected-note {{inherited here}} + using B2::B2; // expected-error {{already inherited constructor with the same signature}} }; struct D2 : B1, B2 { - using B1::B1; // expected-error {{not supported}} - using B2::B2; // expected-error {{not supported}} + using B1::B1; + using B2::B2; D2(int); }; @@ -22,8 +22,8 @@ template<typename T> struct B3 { }; template<typename T> struct B4 : B3<T>, B1 { B4(); - using B3<T>::B3; // expected-note {{inherited here}} expected-error {{not supported}} - using B1::B1; // expected-error {{already inherited}} expected-error {{not supported}} + using B3<T>::B3; // expected-note {{inherited here}} + using B1::B1; // expected-error {{already inherited}} }; B4<char> b4c; B4<int> b4i; // expected-note {{here}} diff --git a/test/CXX/special/class.inhctor/p8.cpp b/test/CXX/special/class.inhctor/p8.cpp new file mode 100644 index 0000000000..e2b07dfae8 --- /dev/null +++ b/test/CXX/special/class.inhctor/p8.cpp @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -std=c++11 -verify %s + +// expected-no-diagnostics +struct A { + constexpr A(const int&) : rval(false) {} + constexpr A(const int&&) : rval(true) {} + bool rval; +}; +struct B : A { + using A::A; +}; + +constexpr int k = 0; +constexpr A a0{0}; +constexpr A a1{k}; +constexpr B b0{0}; +// This performs static_cast<(const int&)&&>(k), so calls the A(const int&) +// constructor. +constexpr B b1{k}; + +static_assert(a0.rval && !a1.rval && b0.rval && !b1.rval, ""); |