Consumed analysis: Add param_typestate attribute, which specifies that
function parameters must be in a particular state. Patch by
chris.wailes@gmail.com. Reviewed by delesley@google.com.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@192934 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Analysis/Consumed.cpp b/lib/Analysis/Consumed.cpp
index 021c26d..a7d747f 100644
--- a/lib/Analysis/Consumed.cpp
+++ b/lib/Analysis/Consumed.cpp
@@ -180,13 +180,14 @@
llvm_unreachable("invalid enum");
}
-static ConsumedState mapSetTypestateAttrState(const SetTypestateAttr *STAttr) {
- switch (STAttr->getNewState()) {
- case SetTypestateAttr::Unknown:
+static ConsumedState
+mapParamTypestateAttrState(const ParamTypestateAttr *PTAttr) {
+ switch (PTAttr->getParamState()) {
+ case ParamTypestateAttr::Unknown:
return CS_Unknown;
- case SetTypestateAttr::Unconsumed:
+ case ParamTypestateAttr::Unconsumed:
return CS_Unconsumed;
- case SetTypestateAttr::Consumed:
+ case ParamTypestateAttr::Consumed:
return CS_Consumed;
}
llvm_unreachable("invalid_enum");
@@ -205,6 +206,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 StringRef stateToString(ConsumedState State) {
switch (State) {
case consumed::CS_None:
@@ -577,12 +590,33 @@
InfoEntry Entry = PropagationMap.find(Call->getArg(Index));
- if (Entry == PropagationMap.end() || !Entry->second.isVar()) {
+ if (Entry == PropagationMap.end() ||
+ !(Entry->second.isState() || Entry->second.isVar()))
continue;
- }
PropagationInfo PInfo = Entry->second;
+ // Check that the parameter is in the correct state.
+
+ if (Param->hasAttr<ParamTypestateAttr>()) {
+ ConsumedState ParamState =
+ PInfo.isState() ? PInfo.getState() :
+ StateMap->getState(PInfo.getVar());
+
+ ConsumedState ExpectedState =
+ mapParamTypestateAttrState(Param->getAttr<ParamTypestateAttr>());
+
+ if (ParamState != ExpectedState)
+ Analyzer.WarningsHandler.warnParamTypestateMismatch(
+ Call->getArg(Index - Offset)->getExprLoc(),
+ stateToString(ExpectedState), stateToString(ParamState));
+ }
+
+ if (!Entry->second.isVar())
+ continue;
+
+ // Adjust state on the caller side.
+
if (ParamType->isRValueReferenceType() ||
(ParamType->isLValueReferenceType() &&
!cast<LValueReferenceType>(*ParamType).isSpelledAsLValue())) {
@@ -812,15 +846,22 @@
void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) {
QualType ParamType = Param->getType();
ConsumedState ParamState = consumed::CS_None;
-
- if (!(ParamType->isPointerType() || ParamType->isReferenceType()) &&
- isConsumableType(ParamType))
+
+ if (Param->hasAttr<ParamTypestateAttr>()) {
+ ParamState =
+ mapParamTypestateAttrState(Param->getAttr<ParamTypestateAttr>());
+
+ } else if (!(ParamType->isPointerType() || ParamType->isReferenceType()) &&
+ isConsumableType(ParamType)) {
+
ParamState = mapConsumableAttrState(ParamType);
- else if (ParamType->isReferenceType() &&
- isConsumableType(ParamType->getPointeeType()))
+
+ } else if (ParamType->isReferenceType() &&
+ isConsumableType(ParamType->getPointeeType())) {
ParamState = consumed::CS_Unknown;
-
- if (ParamState)
+ }
+
+ if (ParamState != CS_None)
StateMap->setState(Param, ParamState);
}