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/Analysis/Consumed.cpp b/lib/Analysis/Consumed.cpp
index d1c03d0..c51c023 100644
--- a/lib/Analysis/Consumed.cpp
+++ b/lib/Analysis/Consumed.cpp
@@ -157,6 +157,18 @@
llvm_unreachable("invalid enum");
}
+static ConsumedState mapSetTypestateAttrState(const SetTypestateAttr *STAttr) {
+ switch (STAttr->getNewState()) {
+ case SetTypestateAttr::Unknown:
+ return CS_Unknown;
+ case SetTypestateAttr::Unconsumed:
+ return CS_Unconsumed;
+ case SetTypestateAttr::Consumed:
+ return CS_Consumed;
+ }
+ llvm_unreachable("invalid_enum");
+}
+
static ConsumedState
mapReturnTypestateAttrState(const ReturnTypestateAttr *RTSAttr) {
switch (RTSAttr->getState()) {
@@ -639,8 +651,9 @@
if (isTestingFunction(MethodDecl))
PropagationMap.insert(PairType(Call,
PropagationInfo(PInfo.getVar(), testsFor(MethodDecl))));
- else if (MethodDecl->hasAttr<ConsumesAttr>())
- StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
+ else if (MethodDecl->hasAttr<SetTypestateAttr>())
+ StateMap->setState(PInfo.getVar(),
+ mapSetTypestateAttrState(MethodDecl->getAttr<SetTypestateAttr>()));
}
}
}
@@ -728,8 +741,9 @@
if (isTestingFunction(FunDecl))
PropagationMap.insert(PairType(Call,
PropagationInfo(PInfo.getVar(), testsFor(FunDecl))));
- else if (FunDecl->hasAttr<ConsumesAttr>())
- StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
+ else if (FunDecl->hasAttr<SetTypestateAttr>())
+ StateMap->setState(PInfo.getVar(),
+ mapSetTypestateAttrState(FunDecl->getAttr<SetTypestateAttr>()));
}
}
}
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: