Restructure checking for, and warning on, lifetime extension.

This change implements C++ DR1696, which makes initialization of a
reference member of a class from a temporary object ill-formed. The
standard wording here is imprecise, but we interpret it as meaning that
any time a mem-initializer would result in lifetime extension, the
program is ill-formed.

llvm-svn: 337226
diff --git a/clang/test/Analysis/initializer.cpp b/clang/test/Analysis/initializer.cpp
index b73a94f..0cb68c4 100644
--- a/clang/test/Analysis/initializer.cpp
+++ b/clang/test/Analysis/initializer.cpp
@@ -178,29 +178,6 @@
     const MyStruct &myStruct(OtherStruct(5));
     myStruct.method(); // no-warning
   }
-
-  struct HasMyStruct {
-    const MyStruct &ms; // expected-note {{reference member declared here}}
-    const MyStruct &msWithCleanups; // expected-note {{reference member declared here}}
-
-    // clang's Sema issues a warning when binding a reference member to a
-    // temporary value.
-    HasMyStruct() : ms(5), msWithCleanups(OtherStruct(5)) {
-        // expected-warning@-1 {{binding reference member 'ms' to a temporary value}}
-        // expected-warning@-2 {{binding reference member 'msWithCleanups' to a temporary value}}
-
-      // At this point the members are not garbage so we should not expect an
-      // analyzer warning here even though binding a reference member
-      // to a member is a terrible idea.
-      ms.method(); // no-warning
-      msWithCleanups.method(); // no-warning
-    }
-  };
-
-  void referenceInitializeField() {
-    HasMyStruct hms;
-  }
-
 };
 
 namespace PR31592 {
diff --git a/clang/test/CXX/drs/dr16xx.cpp b/clang/test/CXX/drs/dr16xx.cpp
index e0af95a..54648cf 100644
--- a/clang/test/CXX/drs/dr16xx.cpp
+++ b/clang/test/CXX/drs/dr16xx.cpp
@@ -9,6 +9,20 @@
 #define static_assert(...) __extension__ _Static_assert(__VA_ARGS__)
 #endif
 
+#if __cplusplus >= 201103L
+namespace std {
+  typedef decltype(sizeof(int)) size_t;
+
+  template<typename E> class initializer_list {
+    const E *begin;
+    size_t size;
+
+  public:
+    initializer_list();
+  };
+} // std
+#endif
+
 namespace dr1611 { // dr1611: dup 1658
   struct A { A(int); };
   struct B : virtual A { virtual void f() = 0; };
@@ -269,3 +283,83 @@
   auto c = To<E1>() <=> To<E2>(); // expected-error {{invalid operands to binary expression ('To<dr1687::E1>' and 'To<dr1687::E2>')}}
 #endif
 }
+
+namespace dr1696 { // dr1696: 7
+  namespace std_examples {
+#if __cplusplus >= 201402L
+    extern struct A a;
+    struct A {
+      const A &x = { A{a, a} };
+      const A &y = { A{} }; // expected-error {{default member initializer for 'y' needed within definition of enclosing class 'A' outside of member functions}} expected-note {{here}}
+    };
+    A a{a, a};
+#endif
+  }
+
+  struct A { A(); ~A(); };
+#if __cplusplus >= 201103L
+  struct B {
+    A &&a; // expected-note {{declared here}}
+    B() : a{} {} // expected-error {{reference member 'a' binds to a temporary object whose lifetime would be shorter than the constructed object}}
+  } b;
+#endif
+
+  struct C {
+    C();
+    const A &a; // expected-note {{declared here}}
+  };
+  C::C() : a(A()) {} // expected-error {{reference member 'a' binds to a temporary object whose lifetime would be shorter than the constructed object}}
+
+#if __cplusplus >= 201103L
+  // This is OK in C++14 onwards, per DR1815, though we don't support that yet:
+  //   D1 d1 = {};
+  // is equivalent to
+  //   D1 d1 = {A()};
+  // ... which lifetime-extends the A temporary.
+  struct D1 {
+    const A &a = A();
+#if __cplusplus < 201402L
+    // expected-error@-2 {{binds to a temporary}}
+    // expected-note@-4 {{here}}
+#else
+    // expected-warning-re@-5 {{sorry, lifetime extension {{.*}} not supported}}
+#endif
+  };
+  D1 d1 = {}; // expected-note {{here}}
+
+  struct D2 {
+    const A &a = A(); // expected-error {{binds to a temporary}}
+    D2() {} // expected-note {{used here}}
+  };
+
+  struct D3 { // expected-note {{used here}}
+    const A &a = A(); // expected-error {{binds to a temporary}}
+  };
+  D3 d3; // expected-note {{first required here}}
+
+  struct haslist1 {
+    std::initializer_list<int> il; // expected-note {{'std::initializer_list' member}}
+    haslist1(int i) : il{i, 2, 3} {} // expected-error {{backing array for 'std::initializer_list' member 'il' is a temporary object}}
+  };
+
+  struct haslist2 {
+    std::initializer_list<int> il; // expected-note {{'std::initializer_list' member}}
+    haslist2();
+  };
+  haslist2::haslist2() : il{1, 2} {} // expected-error {{backing array for 'std::initializer_list' member 'il' is a temporary object}}
+
+  struct haslist3 {
+    std::initializer_list<int> il = {1, 2, 3};
+  };
+
+  struct haslist4 { // expected-note {{in default member initializer}}
+    std::initializer_list<int> il = {1, 2, 3}; // expected-error {{backing array for 'std::initializer_list' member 'il' is a temporary object}}
+  };
+  haslist4 hl4; // expected-note {{in implicit default constructor}}
+
+  struct haslist5 {
+    std::initializer_list<int> il = {1, 2, 3}; // expected-error {{backing array for 'std::initializer_list' member 'il' is a temporary object}}
+    haslist5() {} // expected-note {{in default member initializer}}
+  };
+#endif
+}
diff --git a/clang/test/CXX/drs/dr18xx.cpp b/clang/test/CXX/drs/dr18xx.cpp
index a0f470e..f6a4676 100644
--- a/clang/test/CXX/drs/dr18xx.cpp
+++ b/clang/test/CXX/drs/dr18xx.cpp
@@ -30,6 +30,17 @@
   static_assert(!__is_standard_layout(U), "");
 }
 
+namespace dr1815 { // dr1815: no
+#if __cplusplus >= 201402L
+  // FIXME: needs codegen test
+  struct A { int &&r = 0; }; // FIXME expected-warning {{not supported}}
+  A a = {}; // expected-note {{here}}
+
+  struct B { int &&r = 0; }; // expected-error {{binds to a temporary}} expected-note {{here}}
+  B b; // expected-note {{here}}
+#endif
+}
+
 namespace dr1881 { // dr1881: 7
   struct A { int a : 4; };
   struct B : A { int b : 3; };
diff --git a/clang/test/CXX/special/class.copy/p11.0x.copy.cpp b/clang/test/CXX/special/class.copy/p11.0x.copy.cpp
index 1ca0143..a4d0cdc 100644
--- a/clang/test/CXX/special/class.copy/p11.0x.copy.cpp
+++ b/clang/test/CXX/special/class.copy/p11.0x.copy.cpp
@@ -121,13 +121,22 @@
 HasNoAccessDtorBase HNADBb(HNADBa); // expected-error{{implicitly-deleted copy constructor}}
 
 // -- a non-static data member of rvalue reference type
+int some_int;
 struct RValue {
-  int && ri = 1; // expected-note{{copy constructor of 'RValue' is implicitly deleted because field 'ri' is of rvalue reference type 'int &&'}}
-  // expected-warning@-1{{binding reference member 'ri' to a temporary}} expected-note@-1 {{here}}
+  int && ri = static_cast<int&&>(some_int); // expected-note{{copy constructor of 'RValue' is implicitly deleted because field 'ri' is of rvalue reference type 'int &&'}}
 };
 RValue RVa;
 RValue RVb(RVa); // expected-error{{call to implicitly-deleted copy constructor}}
 
+// FIXME: The note on the class-name is attached to the location of the
+// constructor. This is not especially clear.
+struct RValueTmp { // expected-note {{used here}}
+  int && ri = 1; // expected-note{{copy constructor of 'RValueTmp' is implicitly deleted because field 'ri' is of rvalue reference type 'int &&'}}
+  // expected-error@-1 {{reference member 'ri' binds to a temporary}}
+};
+RValueTmp RVTa; // expected-note {{implicit default constructor for 'RValueTmp' first required here}}
+RValueTmp RVTb(RVTa); // expected-error{{call to implicitly-deleted copy constructor}}
+
 namespace PR13381 {
   struct S {
     S(const S&);
diff --git a/clang/test/CXX/special/class.copy/p11.0x.move.cpp b/clang/test/CXX/special/class.copy/p11.0x.move.cpp
index ab42595..5b01683 100644
--- a/clang/test/CXX/special/class.copy/p11.0x.move.cpp
+++ b/clang/test/CXX/special/class.copy/p11.0x.move.cpp
@@ -145,7 +145,7 @@
 // The restriction on rvalue reference members applies to only the copy
 // constructor.
 struct RValue {
-  int &&ri = 1; // expected-warning {{binding reference member 'ri' to a temporary}} expected-note {{here}}
+  int &&ri = 1;
   RValue(RValue&&);
 };
 RValue::RValue(RValue&&) = default;
diff --git a/clang/test/CXX/special/class.ctor/p5-0x.cpp b/clang/test/CXX/special/class.ctor/p5-0x.cpp
index 2360345..5558313 100644
--- a/clang/test/CXX/special/class.ctor/p5-0x.cpp
+++ b/clang/test/CXX/special/class.ctor/p5-0x.cpp
@@ -43,8 +43,12 @@
 NotDeleted2a nd2a;
 class NotDeleted2b { int &a = error; }; // expected-error {{undeclared identifier}}
 NotDeleted2b nd2b;
-class NotDeleted2c { int &&a = 0; }; // expected-warning {{binding reference member 'a' to a temporary}} expected-note {{here}}
+class NotDeleted2c { int &&a = static_cast<int&&>(n); };
 NotDeleted2c nd2c;
+// Note: this one does not have a deleted default constructor even though the
+// implicit default constructor is ill-formed!
+class NotDeleted2d { int &&a = 0; }; // expected-error {{reference member 'a' binds to a temporary object}} expected-note {{here}}
+NotDeleted2d nd2d; // expected-note {{first required here}}
 
 // - any non-variant non-static data member of const qualified type (or array
 // thereof) with no brace-or-equal-initializer does not have a user-provided
diff --git a/clang/test/CXX/temp/temp.param/p5.cpp b/clang/test/CXX/temp/temp.param/p5.cpp
index aa0d7e9..de902a5 100644
--- a/clang/test/CXX/temp/temp.param/p5.cpp
+++ b/clang/test/CXX/temp/temp.param/p5.cpp
@@ -1,13 +1,13 @@
 // RUN: %clang_cc1 -verify %s -std=c++14
 
-template<const int I> struct S {
+template<const int I> struct S { // expected-note {{in default member initializer}}
   decltype(I) n;
-  int &&r = I; // expected-warning 2{{binding reference member 'r' to a temporary value}} expected-note 2{{declared here}}
+  int &&r = I; // expected-error {{reference member 'r' binds to a temporary object}}
 };
-S<5> s; // expected-note {{instantiation}}
+S<5> s; // expected-note {{implicit default constructor}}
 
-template<typename T, T v> struct U {
+template<typename T, T v> struct U { // expected-note {{in default member initializer}}
   decltype(v) n;
-  int &&r = v; // expected-warning {{binding reference member 'r' to a temporary value}} expected-note {{declared here}}
+  int &&r = v; // expected-error {{reference member 'r' binds to a temporary object}}
 };
-U<const int, 6> u; // expected-note {{instantiation}}
+U<const int, 6> u; // expected-note {{implicit default constructor}}
diff --git a/clang/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp b/clang/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
index 3299763..0184a1d 100644
--- a/clang/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
+++ b/clang/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
@@ -236,36 +236,6 @@
   // CHECK: ret void
 }
 
-struct haslist1 {
-  std::initializer_list<int> il;
-  haslist1(int i);
-};
-
-// CHECK-LABEL: define void @_ZN8haslist1C2Ei
-haslist1::haslist1(int i)
-// CHECK: alloca [3 x i32]
-// CHECK: store i32 %
-// CHECK: store i32 2
-// CHECK: store i32 3
-  : il{i, 2, 3}
-{
-  destroyme2 dm2;
-}
-
-struct haslist2 {
-  std::initializer_list<destroyme1> il;
-  haslist2();
-};
-
-// CHECK-LABEL: define void @_ZN8haslist2C2Ev
-haslist2::haslist2()
-  : il{destroyme1(), destroyme1()}
-{
-  destroyme2 dm2;
-  // CHECK: call void @_ZN10destroyme2D1Ev
-  // CHECK: call void @_ZN10destroyme1D1Ev
-}
-
 void fn10(int i) {
   // CHECK-LABEL: define void @_Z4fn10i
   // CHECK: alloca [3 x i32]
diff --git a/clang/test/CodeGenCXX/temporaries.cpp b/clang/test/CodeGenCXX/temporaries.cpp
index bad51ba..21372ef 100644
--- a/clang/test/CodeGenCXX/temporaries.cpp
+++ b/clang/test/CodeGenCXX/temporaries.cpp
@@ -198,20 +198,6 @@
   f();
 }
   
-struct C {
-  C();
-  
-  const B& b;
-};
-
-C::C() 
-  // CHECK: call void @_ZN6PR50771BC1Ev
-  : b(B()) {
-  // CHECK: call void @_ZN6PR50771fEv
-  f();
-  
-  // CHECK: call void @_ZN6PR50771BD1Ev
-}
 }
 
 A f8() {
@@ -816,16 +802,3 @@
   // CHECK: call void @_ZN7PR141301SC1Ei({{.*}} @_ZGRN7PR141301vE_, i32 0)
   // CHECK: store {{.*}} @_ZGRN7PR141301vE_, {{.*}} @_ZN7PR141301vE
 }
-
-namespace Ctor {
-  struct A { A(); ~A(); };
-  void f();
-  struct B {
-    A &&a;
-    B() : a{} { f(); }
-  } b;
-  // CHECK: define {{.*}}void @_ZN4Ctor1BC1Ev(
-  // CHECK: call void @_ZN4Ctor1AC1Ev(
-  // CHECK: call void @_ZN4Ctor1fEv(
-  // CHECK: call void @_ZN4Ctor1AD1Ev(
-}
diff --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp
index 4b4bd43..e921634 100644
--- a/clang/test/SemaCXX/constant-expression-cxx11.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp
@@ -1892,14 +1892,15 @@
   }
 
   constexpr int &get(int &&n) { return n; }
+  constexpr int &&get_rv(int &&n) { return static_cast<int&&>(n); }
   struct S {
-    int &&r; // expected-note 2{{declared here}}
+    int &&r;
     int &s;
     int t;
-    constexpr S() : r(0), s(get(0)), t(r) {} // expected-warning {{temporary}}
-    constexpr S(int) : r(0), s(get(0)), t(s) {} // expected-warning {{temporary}} expected-note {{read of object outside its lifetime}}
+    constexpr S() : r(get_rv(0)), s(get(0)), t(r) {} // expected-note {{read of object outside its lifetime}}
+    constexpr S(int) : r(get_rv(0)), s(get(0)), t(s) {} // expected-note {{read of object outside its lifetime}}
   };
-  constexpr int k1 = S().t; // ok, int is lifetime-extended to end of constructor
+  constexpr int k1 = S().t; // expected-error {{constant expression}} expected-note {{in call}}
   constexpr int k2 = S(0).t; // expected-error {{constant expression}} expected-note {{in call}}
 }
 
diff --git a/clang/test/SemaCXX/constexpr-default-arg.cpp b/clang/test/SemaCXX/constexpr-default-arg.cpp
index 2fc873c..165c31a 100644
--- a/clang/test/SemaCXX/constexpr-default-arg.cpp
+++ b/clang/test/SemaCXX/constexpr-default-arg.cpp
@@ -31,8 +31,8 @@
 }
 
 // Check that multiple CXXDefaultInitExprs don't cause an assertion failure.
-struct A { int &&r = 0; }; // expected-warning {{binding reference member}} // expected-note {{reference member declared here}}
+struct A { int &&r = 0; }; // expected-warning 2{{not supported}}
 struct B { A x, y; };
-B b = {};
+B b = {}; // expected-note 2{{in default member initializer for field 'r' used here}}
 
 }
diff --git a/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp b/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
index 860a4aa..ece014d 100644
--- a/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
+++ b/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
@@ -153,13 +153,14 @@
 }
 
 struct haslist1 {
-  std::initializer_list<int> il = {1, 2, 3}; // expected-warning{{at the end of the constructor}}
-  std::initializer_list<int> jl{1, 2, 3}; // expected-warning{{at the end of the constructor}}
+  std::initializer_list<int> il // expected-note {{declared here}}
+    = {1, 2, 3}; // ok, unused
+  std::initializer_list<int> jl{1, 2, 3}; // expected-error {{backing array for 'std::initializer_list' member 'jl' is a temporary object}}
   haslist1();
 };
 
-haslist1::haslist1()
-: il{1, 2, 3} // expected-warning{{at the end of the constructor}}
+haslist1::haslist1() // expected-note {{used here}}
+: il{1, 2, 3} // expected-error {{backing array for 'std::initializer_list' member 'il' is a temporary object}}
 {}
 
 namespace PR12119 {
diff --git a/clang/test/SemaCXX/eval-crashes.cpp b/clang/test/SemaCXX/eval-crashes.cpp
index 2394684..33bde75 100644
--- a/clang/test/SemaCXX/eval-crashes.cpp
+++ b/clang/test/SemaCXX/eval-crashes.cpp
@@ -26,10 +26,10 @@
 
 namespace pr33140_2 {
   // FIXME: The declaration of 'b' below should lifetime-extend two int
-  // temporaries, invalidating this warning to some extent.
-  struct A { int &&r = 0; }; // expected-warning {{binding reference member 'r' to a temporary}} expected-note {{here}}
+  // temporaries.
+  struct A { int &&r = 0; }; // expected-warning 2{{not supported}}
   struct B { A x, y; };
-  B b = {};
+  B b = {}; // expected-note 2{{used here}}
 }
 
 namespace pr33140_3 {
diff --git a/clang/test/SemaCXX/member-init.cpp b/clang/test/SemaCXX/member-init.cpp
index ad4a8f1..8a13eca 100644
--- a/clang/test/SemaCXX/member-init.cpp
+++ b/clang/test/SemaCXX/member-init.cpp
@@ -86,9 +86,8 @@
   };
   struct thing {};
   struct another {
-    another() : r(thing()) {}
+    another() : r(thing()) {} // expected-error {{binds to a temporary object}}
     // expected-error@-1 {{temporary of type 'PR14838::function' has private destructor}}
-    // expected-warning@-2 {{binding reference member 'r' to a temporary value}}
     const function &r; // expected-note {{reference member declared here}}
   } af;
 }
diff --git a/clang/test/SemaCXX/warn-dangling-field.cpp b/clang/test/SemaCXX/warn-dangling-field.cpp
index eb65bd0..97d4331 100644
--- a/clang/test/SemaCXX/warn-dangling-field.cpp
+++ b/clang/test/SemaCXX/warn-dangling-field.cpp
@@ -20,7 +20,7 @@
 
 struct S2 {
   const X &x; // expected-note {{reference member declared here}}
-  S2(int i) : x(i) {} // expected-warning {{binding reference member 'x' to a temporary}}
+  S2(int i) : x(i) {} // expected-error {{member 'x' binds to a temporary}}
 };
 
 struct S3 {
@@ -43,9 +43,9 @@
 
 struct S6 {
   S5 s5; // expected-note {{here}}
-  S6() : s5 { 0 } {} // expected-warning {{binding reference subobject of member 's5' to a temporary}}
+  S6() : s5 { 0 } {} // expected-error {{reference subobject of member 's5' binds to a temporary}}
 };
 
 struct S7 : S5 {
-  S7() : S5 { 0 } {} // expected-warning {{binding reference member 'x' to a temporary}}
+  S7() : S5 { 0 } {} // expected-error {{reference member 'x' binds to a temporary}}
 };