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() {