Implement support for C++11 in-class initialization of non-static data members.
llvm-svn: 132878
diff --git a/clang/test/SemaCXX/PR9572.cpp b/clang/test/SemaCXX/PR9572.cpp
index d1b7077..25c0c01 100644
--- a/clang/test/SemaCXX/PR9572.cpp
+++ b/clang/test/SemaCXX/PR9572.cpp
@@ -1,13 +1,13 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
class Base {
- virtual ~Base();
+ virtual ~Base(); // expected-note {{implicitly declared private here}}
};
-struct Foo : public Base {
- const int kBlah = 3; // expected-error{{fields can only be initialized in constructors}}
+struct Foo : public Base { // expected-error {{base class 'Base' has private destructor}}
+ const int kBlah = 3; // expected-warning {{accepted as a C++0x extension}}
Foo();
};
struct Bar : public Foo {
- Bar() { }
+ Bar() { } // expected-note {{implicit default destructor for 'Foo' first required here}}
};
struct Baz {
Foo f;
diff --git a/clang/test/SemaCXX/class.cpp b/clang/test/SemaCXX/class.cpp
index 52140cb..44fa0ce 100644
--- a/clang/test/SemaCXX/class.cpp
+++ b/clang/test/SemaCXX/class.cpp
@@ -34,7 +34,7 @@
enum E1 { en1, en2 };
- int i = 0; // expected-error {{fields can only be initialized in constructors}}
+ int i = 0; // expected-warning {{in-class initialization of non-static data member accepted as a C++0x extension}}
static int si = 0; // expected-error {{non-const static data member must be initialized out of line}}
static const NestedC ci = 0; // expected-error {{static data member of type 'const C::NestedC' must be initialized out of line}}
static const int nci = vs; // expected-error {{in-class initializer is not a constant expression}}
diff --git a/clang/test/SemaCXX/implicit-exception-spec.cpp b/clang/test/SemaCXX/implicit-exception-spec.cpp
new file mode 100644
index 0000000..81babc0
--- /dev/null
+++ b/clang/test/SemaCXX/implicit-exception-spec.cpp
@@ -0,0 +1,63 @@
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -verify -std=c++0x -Wall %s
+
+template<bool b> struct ExceptionIf { static int f(); };
+template<> struct ExceptionIf<false> { typedef int f; };
+
+// The exception specification of a defaulted default constructor depends on
+// the contents of in-class member initializers. However, the in-class member
+// initializers can depend on the exception specification of the constructor,
+// since the class is considered complete within them. We reject any such cases.
+namespace InClassInitializers {
+ // Noexcept::Noexcept() is implicitly declared as noexcept(false), because it
+ // directly invokes ThrowSomething(). However...
+ //
+ // If noexcept(Noexcept()) is false, then Noexcept() is a constant expression,
+ // so noexcept(Noexcept()) is true. But if noexcept(Noexcept()) is true, then
+ // Noexcept::Noexcept is not declared constexpr, therefore noexcept(Noexcept())
+ // is false.
+ bool ThrowSomething() noexcept(false);
+ struct ConstExpr {
+ bool b = noexcept(ConstExpr()) && ThrowSomething(); // expected-error {{exception specification is not available until end of class definition}}
+ };
+ // We can use it now.
+ bool w = noexcept(ConstExpr());
+
+ // Much more obviously broken: we can't parse the initializer without already
+ // knowing whether it produces a noexcept expression.
+ struct TemplateArg {
+ int n = ExceptionIf<noexcept(TemplateArg())>::f(); // expected-error {{exception specification is not available until end of class definition}}
+ };
+ bool x = noexcept(TemplateArg());
+
+ // And within a nested class.
+ struct Nested {
+ struct Inner {
+ int n = ExceptionIf<noexcept(Nested())>::f(); // expected-error {{exception specification is not available until end of class definition}}
+ } inner;
+ };
+ bool y = noexcept(Nested());
+ bool z = noexcept(Nested::Inner());
+}
+
+// FIXME:
+// The same problem arises in delayed parsing of exception specifications,
+// which clang does not yet support.
+namespace ExceptionSpecification {
+ struct Nested { // expected-note {{not complete}}
+ struct T {
+ T() noexcept(!noexcept(Nested())); // expected-error {{incomplete type}}
+ } t;
+ };
+}
+
+// FIXME:
+// The same problem arises in delayed parsing of default arguments,
+// which clang does not yet support.
+namespace DefaultArgument {
+ // FIXME: this diagnostic is completely wrong.
+ struct Default { // expected-note {{explicitly marked deleted here}}
+ struct T {
+ T(int = ExceptionIf<noexcept(Default())::f()); // expected-error {{call to deleted constructor}}
+ } t;
+ };
+}
diff --git a/clang/test/SemaCXX/member-init.cpp b/clang/test/SemaCXX/member-init.cpp
new file mode 100644
index 0000000..1b8c523
--- /dev/null
+++ b/clang/test/SemaCXX/member-init.cpp
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -verify -std=c++0x -Wall %s
+
+struct Bitfield {
+ int n : 3 = 7; // expected-error {{bitfield member cannot have an in-class initializer}}
+};
+
+int a;
+class NoWarning {
+ int &n = a;
+public:
+ int &GetN() { return n; }
+};
+
+bool b();
+int k;
+struct Recurse {
+ int &n = b() ? Recurse().n : k; // ok
+};
+
+struct UnknownBound {
+ int as[] = { 1, 2, 3 }; // expected-error {{array bound cannot be deduced from an in-class initializer}}
+ int bs[4] = { 4, 5, 6, 7 };
+ int cs[] = { 8, 9, 10 }; // expected-error {{array bound cannot be deduced from an in-class initializer}}
+};
+
+template<int n> struct T { static const int B; };
+template<> struct T<2> { template<int C, int D> using B = int; };
+const int C = 0, D = 0;
+struct S {
+ int as[] = { decltype(x)::B<C, D>(0) }; // expected-error {{array bound cannot be deduced from an in-class initializer}}
+ T<sizeof(as) / sizeof(int)> x; // expected-error {{requires a type specifier}}
+};
+
+struct ThrowCtor { ThrowCtor(int) noexcept(false); };
+struct NoThrowCtor { NoThrowCtor(int) noexcept(true); };
+
+struct Throw { ThrowCtor tc = 42; };
+struct NoThrow { NoThrowCtor tc = 42; };
+
+static_assert(!noexcept(Throw()), "incorrect exception specification");
+static_assert(noexcept(NoThrow()), "incorrect exception specification");
+
+struct CheckExcSpec {
+ CheckExcSpec() noexcept(true) = default;
+ int n = 0;
+};
+struct CheckExcSpecFail {
+ CheckExcSpecFail() noexcept(true) = default; // expected-error {{exception specification of explicitly defaulted default constructor does not match the calculated one}}
+ ThrowCtor tc = 123;
+};
diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp
index c3470d4..30cc6a3 100644
--- a/clang/test/SemaCXX/type-traits.cpp
+++ b/clang/test/SemaCXX/type-traits.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++0x %s
#define T(b) (b) ? 1 : -1
#define F(b) (b) ? -1 : 1
@@ -38,8 +38,7 @@
struct DerivesEmpty : Empty {};
struct HasCons { HasCons(int); };
struct HasCopyAssign { HasCopyAssign operator =(const HasCopyAssign&); };
-struct HasMoveAssign { HasMoveAssign operator =(const HasMoveAssign&&); }; // \
- // expected-warning {{rvalue references}}
+struct HasMoveAssign { HasMoveAssign operator =(const HasMoveAssign&&); };
struct HasDest { ~HasDest(); };
class HasPriv { int priv; };
class HasProt { protected: int prot; };
@@ -1069,7 +1068,7 @@
};
struct HasMove {
- HasMove(HasMove&& cp); // expected-warning {{rvalue references}}
+ HasMove(HasMove&& cp);
};
struct HasTemplateCons {
@@ -1253,6 +1252,9 @@
{ int arr[F(__has_nothrow_copy(cvoid))]; }
}
+template<bool b> struct assert_expr;
+template<> struct assert_expr<true> {};
+
void has_nothrow_constructor() {
{ int arr[T(__has_nothrow_constructor(Int))]; }
{ int arr[T(__has_nothrow_constructor(IntAr))]; }
@@ -1280,6 +1282,11 @@
{ int arr[F(__has_nothrow_constructor(void))]; }
{ int arr[F(__has_nothrow_constructor(cvoid))]; }
{ int arr[F(__has_nothrow_constructor(HasTemplateCons))]; }
+
+ // While parsing an in-class initializer, the constructor is not known to be
+ // non-throwing yet.
+ struct HasInClassInit { int n = (assert_expr<!__has_nothrow_constructor(HasInClassInit)>(), 0); };
+ { int arr[T(__has_nothrow_constructor(HasInClassInit))]; }
}
void has_virtual_destructor() {