summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
authorDeLesley Hutchins <delesley@google.com>2013-10-17 22:53:04 +0000
committerDeLesley Hutchins <delesley@google.com>2013-10-17 22:53:04 +0000
commit36ea1dd4fc5e193d0eb7f6bf69f15d3779b6da24 (patch)
tree1995fb9ee35a51717ef613dfd7b3280928716ebc /clang/lib
parentc1d547129185cabebc2d0857eea6a03d5bdf8b81 (diff)
downloadbcm5719-llvm-36ea1dd4fc5e193d0eb7f6bf69f15d3779b6da24.tar.gz
bcm5719-llvm-36ea1dd4fc5e193d0eb7f6bf69f15d3779b6da24.zip
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@gmail.com; reviewed by delesley@google.com. llvm-svn: 192932
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Analysis/Consumed.cpp46
-rw-r--r--clang/lib/Sema/AnalysisBasedWarnings.cpp12
-rw-r--r--clang/lib/Sema/SemaDeclAttr.cpp20
3 files changed, 68 insertions, 10 deletions
diff --git a/clang/lib/Analysis/Consumed.cpp b/clang/lib/Analysis/Consumed.cpp
index b06fb155d5b..021c26dff2f 100644
--- a/clang/lib/Analysis/Consumed.cpp
+++ b/clang/lib/Analysis/Consumed.cpp
@@ -87,7 +87,7 @@ static SourceLocation getLastStmtLoc(const CFGBlock *Block) {
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(const CallExpr *Call) {
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(const CallExpr *Call) {
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::VisitParmVarDecl(const ParmVarDecl *Param) {
}
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::VisitReturnStmt(const ReturnStmt *Ret) {
stateToString(RetState));
}
}
+
+ StateMap->checkParamsForReturnTypestate(Ret->getLocStart(),
+ Analyzer.WarningsHandler);
}
void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) {
@@ -1054,6 +1064,31 @@ bool ConsumedBlockInfo::isBackEdgeTarget(const CFGBlock *Block) {
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(AnalysisDeclContext &AC) {
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.
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 737f59a3f97..2d65980ec07 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -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(
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index c08767574ce..c3e6bc4cc34 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -1068,6 +1068,14 @@ static void handleCallableWhenAttr(Sema &S, Decl *D,
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(Sema &S, Decl *D,
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 {
OpenPOWER on IntegriCloud