Consumed analysis: replace the consumes attribute with a set_typestate
attribute.  Patch by chris.wailes@gmail.com; reviewed and edited by delesley.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@192515 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index a07d6ca..70ae9fd 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -1026,20 +1026,6 @@
   return true;
 }
 
-static void handleConsumesAttr(Sema &S, Decl *D, const AttributeList &Attr) {
-  if (!isa<CXXMethodDecl>(D)) {
-    S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) <<
-      Attr.getName() << ExpectedMethod;
-    return;
-  }
-  
-  if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), Attr))
-    return;
-  
-  D->addAttr(::new (S.Context)
-             ConsumesAttr(Attr.getRange(), S.Context,
-                          Attr.getAttributeSpellingListIndex()));
-}
 
 static void handleCallableWhenAttr(Sema &S, Decl *D,
                                    const AttributeList &Attr) {
@@ -1080,44 +1066,6 @@
 }
 
 
-static void handleTestsTypestateAttr(Sema &S, Decl *D,
-                                     const AttributeList &Attr) {
-  if (!checkAttributeNumArgs(S, Attr, 1)) return;
-  
-  if (!isa<CXXMethodDecl>(D)) {
-    S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) <<
-      Attr.getName() << ExpectedMethod;
-    return;
-  }
-  
-  if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), Attr))
-    return;
-  
-  TestsTypestateAttr::ConsumedState TestState;
-  
-  if (Attr.isArgIdent(0)) {
-    StringRef Param = Attr.getArgAsIdent(0)->Ident->getName();
-    
-    if (Param == "consumed") {
-      TestState = TestsTypestateAttr::Consumed;
-    } else if (Param == "unconsumed") {
-      TestState = TestsTypestateAttr::Unconsumed;
-    } else {
-      S.Diag(Attr.getLoc(), diag::warn_invalid_test_typestate) << Param;
-      return;
-    }
-    
-  } else {
-    S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) <<
-      Attr.getName() << AANT_ArgumentIdentifier;
-    return;
-  }
-  
-  D->addAttr(::new (S.Context)
-             TestsTypestateAttr(Attr.getRange(), S.Context, TestState,
-                                Attr.getAttributeSpellingListIndex()));
-}
-
 static void handleReturnTypestateAttr(Sema &S, Decl *D,
                                       const AttributeList &Attr) {
   ReturnTypestateAttr::ConsumedState ReturnState;
@@ -1168,6 +1116,84 @@
                                  Attr.getAttributeSpellingListIndex()));
 }
 
+
+static void handleSetTypestateAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+  if (!checkAttributeNumArgs(S, Attr, 1)) return;
+
+  if (!isa<CXXMethodDecl>(D)) {
+    S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) <<
+      Attr.getName() << ExpectedMethod;
+    return;
+  }
+  
+  if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), Attr))
+    return;
+  
+  SetTypestateAttr::ConsumedState NewState;
+  
+  if (Attr.isArgIdent(0)) {
+    StringRef Param = Attr.getArgAsIdent(0)->Ident->getName();
+    
+    if (Param == "unknown") {
+      NewState = SetTypestateAttr::Unknown;
+    } else if (Param == "consumed") {
+      NewState = SetTypestateAttr::Consumed;
+    } else if (Param == "unconsumed") {
+      NewState = SetTypestateAttr::Unconsumed;
+    } else {
+      S.Diag(Attr.getLoc(), diag::warn_unknown_consumed_state) << Param;
+      return;
+    }
+    
+  } else {
+    S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) <<
+      Attr.getName() << AANT_ArgumentIdentifier;
+    return;
+  }
+  
+  D->addAttr(::new (S.Context)
+             SetTypestateAttr(Attr.getRange(), S.Context, NewState,
+                              Attr.getAttributeSpellingListIndex()));
+}
+
+static void handleTestsTypestateAttr(Sema &S, Decl *D,
+                                        const AttributeList &Attr) {
+  if (!checkAttributeNumArgs(S, Attr, 1)) return;
+  
+  if (!isa<CXXMethodDecl>(D)) {
+    S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) <<
+      Attr.getName() << ExpectedMethod;
+    return;
+  }
+  
+  if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), Attr))
+    return;
+  
+  TestsTypestateAttr::ConsumedState TestState;
+  
+  if (Attr.isArgIdent(0)) {
+    StringRef Param = Attr.getArgAsIdent(0)->Ident->getName();
+    
+    if (Param == "consumed") {
+      TestState = TestsTypestateAttr::Consumed;
+    } else if (Param == "unconsumed") {
+      TestState = TestsTypestateAttr::Unconsumed;
+    } else {
+      S.Diag(Attr.getLoc(), diag::warn_unknown_consumed_state) << Param;
+      return;
+    }
+    
+  } else {
+    S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) <<
+      Attr.getName() << AANT_ArgumentIdentifier;
+    return;
+  }
+  
+  D->addAttr(::new (S.Context)
+             TestsTypestateAttr(Attr.getRange(), S.Context, TestState,
+                                Attr.getAttributeSpellingListIndex()));
+}
+
 static void handleExtVectorTypeAttr(Sema &S, Scope *scope, Decl *D,
                                     const AttributeList &Attr) {
   TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D);
@@ -4793,18 +4819,18 @@
   case AttributeList::AT_Consumable:
     handleConsumableAttr(S, D, Attr);
     break;
-  case AttributeList::AT_Consumes:
-    handleConsumesAttr(S, D, Attr);
-    break;
   case AttributeList::AT_CallableWhen:
     handleCallableWhenAttr(S, D, Attr);
     break;
-  case AttributeList::AT_TestsTypestate:
-    handleTestsTypestateAttr(S, D, Attr);
-    break;
   case AttributeList::AT_ReturnTypestate:
     handleReturnTypestateAttr(S, D, Attr);
     break;
+  case AttributeList::AT_SetTypestate:
+    handleSetTypestateAttr(S, D, Attr);
+    break;
+  case AttributeList::AT_TestsTypestate:
+    handleTestsTypestateAttr(S, D, Attr);
+    break;
 
   // Type safety attributes.
   case AttributeList::AT_ArgumentWithTypeTag: