r192932 - Consumed Analysis: Allow parameters that are passed by non-const reference
DeLesley Hutchins
delesley at google.com
Thu Oct 17 15:53:05 PDT 2013
Author: delesley
Date: Thu Oct 17 17:53:04 2013
New Revision: 192932
URL: http://llvm.org/viewvc/llvm-project?rev=192932&view=rev
Log:
Consumed Analysis: Allow parameters that are passed by non-const reference
to be treated as return values, and marked with the "returned_typestate"
attribute. Patch by chris.wailes at gmail.com; reviewed by delesley at google.com.
Modified:
cfe/trunk/include/clang/Analysis/Analyses/Consumed.h
cfe/trunk/include/clang/Basic/Attr.td
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/Analysis/Consumed.cpp
cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp
cfe/trunk/lib/Sema/SemaDeclAttr.cpp
cfe/trunk/test/SemaCXX/warn-consumed-analysis.cpp
cfe/trunk/test/SemaCXX/warn-consumed-parsing.cpp
Modified: cfe/trunk/include/clang/Analysis/Analyses/Consumed.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/Consumed.h?rev=192932&r1=192931&r2=192932&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/Analyses/Consumed.h (original)
+++ cfe/trunk/include/clang/Analysis/Analyses/Consumed.h Thu Oct 17 17:53:04 2013
@@ -59,6 +59,20 @@ namespace consumed {
virtual void warnLoopStateMismatch(SourceLocation Loc,
StringRef VariableName) {}
+ /// \brief Warn about parameter typestate mismatches upon return.
+ ///
+ /// \param Loc -- The SourceLocation of the return statement.
+ ///
+ /// \param ExpectedState -- The state the return value was expected to be
+ /// in.
+ ///
+ /// \param ObservedState -- The state the return value was observed to be
+ /// in.
+ virtual void warnParamReturnTypestateMismatch(SourceLocation Loc,
+ StringRef VariableName,
+ StringRef ExpectedState,
+ StringRef ObservedState) {};
+
// FIXME: This can be removed when the attr propagation fix for templated
// classes lands.
/// \brief Warn about return typestates set for unconsumable types.
@@ -70,7 +84,14 @@ namespace consumed {
StringRef TypeName) {}
/// \brief Warn about return typestate mismatches.
+ ///
/// \param Loc -- The SourceLocation of the return statement.
+ ///
+ /// \param ExpectedState -- The state the return value was expected to be
+ /// in.
+ ///
+ /// \param ObservedState -- The state the return value was observed to be
+ /// in.
virtual void warnReturnTypestateMismatch(SourceLocation Loc,
StringRef ExpectedState,
StringRef ObservedState) {}
@@ -118,6 +139,11 @@ namespace consumed {
ConsumedStateMap(const ConsumedStateMap &Other)
: Reachable(Other.Reachable), From(Other.From), Map(Other.Map) {}
+ /// \brief Warn if any of the parameters being tracked are not in the state
+ /// they were declared to be in upon return from a function.
+ void checkParamsForReturnTypestate(SourceLocation BlameLoc,
+ ConsumedWarningsHandlerBase &WarningsHandler) const;
+
/// \brief Get the consumed state of a given variable.
ConsumedState getState(const VarDecl *Var) const;
Modified: cfe/trunk/include/clang/Basic/Attr.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=192932&r1=192931&r2=192932&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Thu Oct 17 17:53:04 2013
@@ -969,7 +969,7 @@ def CallableWhen : InheritableAttr {
def ReturnTypestate : InheritableAttr {
let Spellings = [GNU<"return_typestate">];
- let Subjects = [Function];
+ let Subjects = [Function, ParmVar];
let Args = [EnumArgument<"State", "ConsumedState",
["unknown", "consumed", "unconsumed"],
["Unknown", "Consumed", "Unconsumed"]>];
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=192932&r1=192931&r2=192932&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Oct 17 17:53:04 2013
@@ -2222,6 +2222,9 @@ def warn_return_typestate_mismatch : War
def warn_loop_state_mismatch : Warning<
"state of variable '%0' must match at the entry and exit of loop">,
InGroup<Consumed>, DefaultIgnore;
+def warn_param_return_typestate_mismatch : Warning<
+ "parameter '%0' not in expected state when the function returns: expected "
+ "'%1', observed '%2'">, InGroup<Consumed>, DefaultIgnore;
def warn_impcast_vector_scalar : Warning<
"implicit conversion turns vector to scalar: %0 to %1">,
Modified: cfe/trunk/lib/Analysis/Consumed.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/Consumed.cpp?rev=192932&r1=192931&r2=192932&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/Consumed.cpp (original)
+++ cfe/trunk/lib/Analysis/Consumed.cpp Thu Oct 17 17:53:04 2013
@@ -87,7 +87,7 @@ static SourceLocation getLastStmtLoc(con
Loc = getFirstStmtLoc(*Block->succ_begin());
if (Loc.isValid())
return Loc;
-
+
// If we have one predecessor, return the last statement in that block
if (Block->pred_size() == 1 && *Block->pred_begin())
return getLastStmtLoc(*Block->pred_begin());
@@ -572,7 +572,8 @@ void ConsumedStmtVisitor::VisitCallExpr(
unsigned Offset = Call->getNumArgs() - FunDecl->getNumParams();
for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) {
- QualType ParamType = FunDecl->getParamDecl(Index - Offset)->getType();
+ const ParmVarDecl *Param = FunDecl->getParamDecl(Index - Offset);
+ QualType ParamType = Param->getType();
InfoEntry Entry = PropagationMap.find(Call->getArg(Index));
@@ -588,6 +589,10 @@ void ConsumedStmtVisitor::VisitCallExpr(
StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
+ } else if (Param->hasAttr<ReturnTypestateAttr>()) {
+ StateMap->setState(PInfo.getVar(),
+ mapReturnTypestateAttrState(Param->getAttr<ReturnTypestateAttr>()));
+
} else if (!(ParamType.isConstQualified() ||
((ParamType->isReferenceType() ||
ParamType->isPointerType()) &&
@@ -820,7 +825,9 @@ void ConsumedStmtVisitor::VisitParmVarDe
}
void ConsumedStmtVisitor::VisitReturnStmt(const ReturnStmt *Ret) {
- if (ConsumedState ExpectedState = Analyzer.getExpectedReturnState()) {
+ ConsumedState ExpectedState = Analyzer.getExpectedReturnState();
+
+ if (ExpectedState != CS_None) {
InfoEntry Entry = PropagationMap.find(Ret->getRetValue());
if (Entry != PropagationMap.end()) {
@@ -835,6 +842,9 @@ void ConsumedStmtVisitor::VisitReturnStm
stateToString(RetState));
}
}
+
+ StateMap->checkParamsForReturnTypestate(Ret->getLocStart(),
+ Analyzer.WarningsHandler);
}
void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) {
@@ -1054,6 +1064,31 @@ bool ConsumedBlockInfo::isBackEdgeTarget
return false;
}
+void ConsumedStateMap::checkParamsForReturnTypestate(SourceLocation BlameLoc,
+ ConsumedWarningsHandlerBase &WarningsHandler) const {
+
+ ConsumedState ExpectedState;
+
+ for (MapType::const_iterator DMI = Map.begin(), DME = Map.end(); DMI != DME;
+ ++DMI) {
+
+ if (isa<ParmVarDecl>(DMI->first)) {
+ const ParmVarDecl *Param = cast<ParmVarDecl>(DMI->first);
+
+ if (!Param->hasAttr<ReturnTypestateAttr>()) continue;
+
+ ExpectedState =
+ mapReturnTypestateAttrState(Param->getAttr<ReturnTypestateAttr>());
+
+ if (DMI->second != ExpectedState) {
+ WarningsHandler.warnParamReturnTypestateMismatch(BlameLoc,
+ Param->getNameAsString(), stateToString(ExpectedState),
+ stateToString(DMI->second));
+ }
+ }
+ }
+}
+
ConsumedState ConsumedStateMap::getState(const VarDecl *Var) const {
MapType::const_iterator Entry = Map.find(Var);
@@ -1375,6 +1410,11 @@ void ConsumedAnalyzer::run(AnalysisDeclC
CurrStates = NULL;
}
}
+
+ if (CurrBlock == &AC.getCFG()->getExit() &&
+ D->getCallResultType()->isVoidType())
+ CurrStates->checkParamsForReturnTypestate(D->getLocation(),
+ WarningsHandler);
} // End of block iterator.
// Delete the last existing state map.
Modified: cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp?rev=192932&r1=192931&r2=192932&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp (original)
+++ cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp Thu Oct 17 17:53:04 2013
@@ -1484,6 +1484,18 @@ public:
Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
}
+ void warnParamReturnTypestateMismatch(SourceLocation Loc,
+ StringRef VariableName,
+ StringRef ExpectedState,
+ StringRef ObservedState) {
+
+ PartialDiagnosticAt Warning(Loc, S.PDiag(
+ diag::warn_param_return_typestate_mismatch) << VariableName <<
+ ExpectedState << ObservedState);
+
+ Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
+ }
+
void warnReturnTypestateForUnconsumableType(SourceLocation Loc,
StringRef TypeName) {
PartialDiagnosticAt Warning(Loc, S.PDiag(
Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=192932&r1=192931&r2=192932&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Thu Oct 17 17:53:04 2013
@@ -1068,6 +1068,14 @@ static void handleCallableWhenAttr(Sema
static void handleReturnTypestateAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
+ if (!checkAttributeNumArgs(S, Attr, 1)) return;
+
+ if (!(isa<FunctionDecl>(D) || isa<ParmVarDecl>(D))) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) <<
+ Attr.getName() << ExpectedFunctionMethodOrParameter;
+ return;
+ }
+
ReturnTypestateAttr::ConsumedState ReturnState;
if (Attr.isArgIdent(0)) {
@@ -1084,18 +1092,16 @@ static void handleReturnTypestateAttr(Se
return;
}
- if (!isa<FunctionDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) <<
- Attr.getName() << ExpectedFunction;
- return;
- }
-
// FIXME: This check is currently being done in the analysis. It can be
// enabled here only after the parser propagates attributes at
// template specialization definition, not declaration.
//QualType ReturnType;
//
- //if (const CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
+ //if (const ParmVarDecl *Param = dyn_cast<ParmVarDecl>(D)) {
+ // ReturnType = Param->getType();
+ //
+ //} else if (const CXXConstructorDecl *Constructor =
+ // dyn_cast<CXXConstructorDecl>(D)) {
// ReturnType = Constructor->getThisType(S.getASTContext())->getPointeeType();
//
//} else {
Modified: cfe/trunk/test/SemaCXX/warn-consumed-analysis.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-consumed-analysis.cpp?rev=192932&r1=192931&r2=192932&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/warn-consumed-analysis.cpp (original)
+++ cfe/trunk/test/SemaCXX/warn-consumed-analysis.cpp Thu Oct 17 17:53:04 2013
@@ -388,6 +388,24 @@ void testFunctionParam(ConsumableClass<i
*param; // expected-warning {{invocation of method 'operator*' on object 'param' while it is in the 'consumed' state}}
}
+void testParamReturnTypestateCallee(bool cond, ConsumableClass<int> &Param RETURN_TYPESTATE(unconsumed)) { // expected-warning {{parameter 'Param' not in expected state when the function returns: expected 'unconsumed', observed 'consumed'}}
+
+ if (cond) {
+ Param.consume();
+ return; // expected-warning {{parameter 'Param' not in expected state when the function returns: expected 'unconsumed', observed 'consumed'}}
+ }
+
+ Param.consume();
+}
+
+void testParamReturnTypestateCaller() {
+ ConsumableClass<int> var;
+
+ testParamReturnTypestateCallee(true, var);
+
+ *var;
+}
+
void testCallingConventions() {
ConsumableClass<int> var(42);
Modified: cfe/trunk/test/SemaCXX/warn-consumed-parsing.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-consumed-parsing.cpp?rev=192932&r1=192931&r2=192932&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/warn-consumed-parsing.cpp (original)
+++ cfe/trunk/test/SemaCXX/warn-consumed-parsing.cpp Thu Oct 17 17:53:04 2013
@@ -44,6 +44,8 @@ class CONSUMABLE(unknown) AttrTester1 {
AttrTester1 returnTypestateTester0() RETURN_TYPESTATE(not_a_state); // expected-warning {{'return_typestate' attribute argument not supported: 'not_a_state'}}
AttrTester1 returnTypestateTester1() RETURN_TYPESTATE(42); // expected-error {{'return_typestate' attribute requires an identifier}}
+void returnTypestateTester2(AttrTester1 &Param RETURN_TYPESTATE(unconsumed));
+
class AttrTester2 {
void callableWhen() CALLABLE_WHEN("unconsumed"); // expected-warning {{consumed analysis attribute is attached to member of class 'AttrTester2' which isn't marked as consumable}}
void consumes() SET_TYPESTATE(consumed); // expected-warning {{consumed analysis attribute is attached to member of class 'AttrTester2' which isn't marked as consumable}}
More information about the cfe-commits
mailing list