Consumed analysis: add two new attributes which fine-tune the behavior of
consumable objects.  These are useful for implementing error codes that
must be checked.  Patch also includes some significant refactoring, which was
necesary to implement the new behavior.

llvm-svn: 199169
diff --git a/clang/test/SemaCXX/warn-consumed-analysis.cpp b/clang/test/SemaCXX/warn-consumed-analysis.cpp
index 2c372c7..76f4f8d 100644
--- a/clang/test/SemaCXX/warn-consumed-analysis.cpp
+++ b/clang/test/SemaCXX/warn-consumed-analysis.cpp
@@ -645,9 +645,12 @@
 } // end namespace ContinueICETest
 
 
-namespace InitializerAssertionFailTest {
+namespace StatusUseCaseTests {
 
-class CONSUMABLE(unconsumed) Status {
+class CONSUMABLE(unconsumed)
+      __attribute__((consumable_auto_cast_state))
+      __attribute__((consumable_set_state_on_read))
+    Status {
   int code;
 
 public:
@@ -673,7 +676,9 @@
 bool   cond();
 Status doSomething();
 void   handleStatus(const Status& s RETURN_TYPESTATE(consumed));
-void   handleStatusPtr(const Status* s);
+void   handleStatusRef(Status& s);
+void   handleStatusPtr(Status* s);
+void   handleStatusUnmarked(const Status& s);
 
 void testSimpleTemporaries0() {
   doSomething(); // expected-warning {{invalid invocation of method '~Status' on a temporary object while it is in the 'unconsumed' state}}
@@ -691,6 +696,15 @@
   Status s = doSomething();
 }  // expected-warning {{invalid invocation of method '~Status' on object 's' while it is in the 'unconsumed' state}}
 
+Status testSimpleTemporariesReturn0() {
+  return doSomething();
+}
+
+Status testSimpleTemporariesReturn1() {
+  Status s = doSomething();
+  return s;
+}
+
 void testSimpleTemporaries4() {
   Status s = doSomething();
   s.check();
@@ -702,8 +716,17 @@
 }
 
 void testSimpleTemporaries6() {
-  Status s = doSomething();
-  handleStatus(s);
+  Status s1 = doSomething();
+  handleStatus(s1);
+
+  Status s2 = doSomething();
+  handleStatusRef(s2);
+
+  Status s3 = doSomething();
+  handleStatusPtr(&s3);
+
+  Status s4 = doSomething();
+  handleStatusUnmarked(s4);
 }
 
 void testSimpleTemporaries7() {
@@ -745,38 +768,58 @@
 }
 
 void testTemporariesAndConstructors0() {
-  Status s(doSomething());
+  Status s(doSomething());    // Test the copy constructor.
   s.check();
 }
 
-void testTemporariesAndConstructors1() {
-  // Test the copy constructor.
-  
-  Status s1 = doSomething();
-  Status s2(s1);
-  s2.check();
-}  // expected-warning {{invalid invocation of method '~Status' on object 's1' while it is in the 'unconsumed' state}}
+void testTemporariesAndConstructors1F() {
+  Status s1 = doSomething();  // Test the copy constructor.
+  Status s2 = s1;
+} // expected-warning {{invalid invocation of method '~Status' on object 's2' while it is in the 'unconsumed' state}}
 
-void testTemporariesAndConstructors2() {
-  // Test the move constructor.
-  
-  Status s1 = doSomething();
-  Status s2(static_cast<Status&&>(s1));
+void testTemporariesAndConstructors1S() {
+  Status s1 = doSomething();  // Test the copy constructor.
+  Status s2(s1);
   s2.check();
 }
 
-void testTemporariesAndOperators0() {
+void testTemporariesAndConstructors2F() {
+  // Test the move constructor.
+  Status s1 = doSomething();
+  Status s2 = static_cast<Status&&>(s1);
+} // expected-warning {{invalid invocation of method '~Status' on object 's2' while it is in the 'unconsumed' state}}
+
+void testTemporariesAndConstructors2S() {
+  // Test the move constructor.
+  Status s1 = doSomething();
+  Status s2 = static_cast<Status&&>(s1);
+  s2.check();
+}
+
+void testTemporariesAndOperators0F() {
   // Test the assignment operator.
-  
+  Status s1 = doSomething();
+  Status s2;
+  s2 = s1;
+} // expected-warning {{invalid invocation of method '~Status' on object 's2' while it is in the 'unconsumed' state}}
+
+void testTemporariesAndOperators0S() {
+  // Test the assignment operator.
   Status s1 = doSomething();
   Status s2;
   s2 = s1;
   s2.check();
-} // expected-warning {{invalid invocation of method '~Status' on object 's1' while it is in the 'unconsumed' state}}
+}
 
-void testTemporariesAndOperators1() {
+void testTemporariesAndOperators1F() {
   // Test the move assignment operator.
-  
+  Status s1 = doSomething();
+  Status s2;
+  s2 = static_cast<Status&&>(s1);
+} // expected-warning {{invalid invocation of method '~Status' on object 's2' while it is in the 'unconsumed' state}}
+
+void testTemporariesAndOperators1S() {
+  // Test the move assignment operator.
   Status s1 = doSomething();
   Status s2;
   s2 = static_cast<Status&&>(s1);
@@ -791,6 +834,12 @@
   s2.check();
 }
 
+Status testReturnAutocast() {
+  Status s = doSomething();
+  s.check();  // consume s
+  return s;   // should autocast back to unconsumed
+}
+
 } // end namespace InitializerAssertionFailTest
 
 
diff --git a/clang/test/SemaCXX/warn-consumed-parsing.cpp b/clang/test/SemaCXX/warn-consumed-parsing.cpp
index cfd3d3b..5c0a04f 100644
--- a/clang/test/SemaCXX/warn-consumed-parsing.cpp
+++ b/clang/test/SemaCXX/warn-consumed-parsing.cpp
@@ -53,3 +53,13 @@
 };
 
 class CONSUMABLE(42) AttrTester3; // expected-error {{'consumable' attribute requires an identifier}}
+
+
+class CONSUMABLE(unconsumed)
+      __attribute__((consumable_auto_cast_state))
+      __attribute__((consumable_set_state_on_read))
+      Status {
+};
+
+
+