]> granicus.if.org Git - clang/commitdiff
Consumed analysis: bugfix for operator calls. Also fixes some formatting
authorDeLesley Hutchins <delesley@google.com>
Thu, 16 Jan 2014 23:07:16 +0000 (23:07 +0000)
committerDeLesley Hutchins <delesley@google.com>
Thu, 16 Jan 2014 23:07:16 +0000 (23:07 +0000)
issues, a few testcases, and kills fish.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@199436 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Analysis/Consumed.cpp
test/SemaCXX/warn-consumed-analysis.cpp

index ed22bda16aa75d85f7514df8abf8efef692284bb..cb6f31f0bf6b3527dc96fd5219a229c0b099cd97 100644 (file)
@@ -183,11 +183,8 @@ static bool isKnownState(ConsumedState State) {
   llvm_unreachable("invalid enum");
 }
 
-static bool isRValueRefish(QualType ParamType) {
-  return ParamType->isRValueReferenceType(); /* ||
-        (ParamType->isLValueReferenceType() &&
-         !cast<LValueReferenceType>(
-           ParamType.getCanonicalType())->isSpelledAsLValue()); */
+static bool isRValueRef(QualType ParamType) {
+  return ParamType->isRValueReferenceType();
 }
 
 static bool isTestingFunction(const FunctionDecl *FunDecl) {
@@ -607,8 +604,8 @@ void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo,
 bool ConsumedStmtVisitor::handleCall(const CallExpr *Call, const Expr *ObjArg,
                                      const FunctionDecl *FunD) {
   unsigned Offset = 0;
-  if (isa<CXXMethodDecl>(FunD))
-    Offset = 1;  // First argument to call is 'this' parameter
+  if (isa<CXXOperatorCallExpr>(Call) && isa<CXXMethodDecl>(FunD))
+    Offset = 1;  // first argument is 'this'
 
   // check explicit parameters
   for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) {
@@ -640,15 +637,14 @@ bool ConsumedStmtVisitor::handleCall(const CallExpr *Call, const Expr *ObjArg,
       continue;
 
     // Adjust state on the caller side.
-    if (isRValueRefish(ParamType))
+    if (isRValueRef(ParamType))
       setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Consumed);
     else if (ReturnTypestateAttr *RT = Param->getAttr<ReturnTypestateAttr>())
       setStateForVarOrTmp(StateMap, PInfo, mapReturnTypestateAttrState(RT));
-    else if (isPointerOrRef(ParamType)) {
-      if (!ParamType->getPointeeType().isConstQualified() ||
-          isSetOnReadPtrType(ParamType))
-        setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Unknown);
-    }
+    else if (isPointerOrRef(ParamType) &&
+             (!ParamType->getPointeeType().isConstQualified() ||
+              isSetOnReadPtrType(ParamType)))
+      setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Unknown);
   }
 
   if (!ObjArg)
@@ -885,11 +881,11 @@ void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) {
     ParamState = mapParamTypestateAttrState(PTA);    
   else if (isConsumableType(ParamType))
     ParamState = mapConsumableAttrState(ParamType);    
-  else if (isRValueRefish(ParamType) &&
-             isConsumableType(ParamType->getPointeeType()))    
+  else if (isRValueRef(ParamType) &&
+           isConsumableType(ParamType->getPointeeType()))
     ParamState = mapConsumableAttrState(ParamType->getPointeeType());    
   else if (ParamType->isReferenceType() &&
-             isConsumableType(ParamType->getPointeeType()))
+           isConsumableType(ParamType->getPointeeType()))
     ParamState = consumed::CS_Unknown;
   
   if (ParamState != CS_None)
index 76f4f8d8111ab769536d2abd4596c03ad4eceddb..3923f694395e06de1abe31f47da88d181e85ce01 100644 (file)
@@ -51,7 +51,7 @@ public:
 
 class CONSUMABLE(unconsumed) DestructorTester {
 public:
-  DestructorTester() RETURN_TYPESTATE(unconsumed);
+  DestructorTester();
   DestructorTester(int);
   
   void operator*() CALLABLE_WHEN("unconsumed");
@@ -82,11 +82,21 @@ ConsumableClass<int> returnsUnknown() RETURN_TYPESTATE(unknown);
 void testInitialization() {
   ConsumableClass<int> var0;
   ConsumableClass<int> var1 = ConsumableClass<int>();
-  
-  var0 = ConsumableClass<int>();
-  
+  ConsumableClass<int> var2(42);
+  ConsumableClass<int> var3(var2);  // copy constructor
+  ConsumableClass<int> var4(var0);  // copy consumed value
+
   *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}}
   *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}}
+  *var2;
+  *var3;
+  *var4; // expected-warning {{invalid invocation of method 'operator*' on object 'var4' while it is in the 'consumed' state}}
+
+  var0 = ConsumableClass<int>(42);
+  *var0;
+  
+  var0 = var1;
+  *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}}
   
   if (var0.isValid()) {
     *var0;
@@ -98,19 +108,16 @@ void testInitialization() {
 }
 
 void testDestruction() {
-  DestructorTester D0(42), D1(42);
+  DestructorTester D0(42), D1(42), D2;
   
   *D0;
   *D1;
-  
-  DestructorTester D2;
-  *D2;
+  *D2; // expected-warning {{invalid invocation of method 'operator*' on object 'D2' while it is in the 'consumed' state}}
   
   D0.~DestructorTester(); // expected-warning {{invalid invocation of method '~DestructorTester' on object 'D0' while it is in the 'unconsumed' state}}
   
   return; // expected-warning {{invalid invocation of method '~DestructorTester' on object 'D0' while it is in the 'unconsumed' state}} \
-             expected-warning {{invalid invocation of method '~DestructorTester' on object 'D1' while it is in the 'unconsumed' state}} \
-             expected-warning {{invalid invocation of method '~DestructorTester' on object 'D2' while it is in the 'unconsumed' state}}
+             expected-warning {{invalid invocation of method '~DestructorTester' on object 'D1' while it is in the 'unconsumed' state}}
 }
 
 void testTempValue() {
@@ -427,6 +434,29 @@ void testParamTypestateCaller() {
   testParamTypestateCallee(Var0, Var1); // expected-warning {{argument not in expected state; expected 'consumed', observed 'unconsumed'}}
 }
 
+
+void consumeFunc(ConsumableClass<int> P PARAM_TYPESTATE(unconsumed));
+struct ParamTest {
+  static void consumeFuncStatic(ConsumableClass<int> P PARAM_TYPESTATE(unconsumed));
+  void consumeFuncMeth(ConsumableClass<int> P PARAM_TYPESTATE(unconsumed));
+  void operator<<(ConsumableClass<int> P PARAM_TYPESTATE(unconsumed));
+};
+
+void operator>>(ParamTest& pt, ConsumableClass<int> P PARAM_TYPESTATE(unconsumed));
+
+
+void testFunctionParams() {
+  // Make sure we handle the different kinds of functions.
+  ConsumableClass<int> P;
+
+  consumeFunc(P);                   // expected-warning {{argument not in expected state; expected 'unconsumed', observed 'consumed'}}
+  ParamTest::consumeFuncStatic(P);  // expected-warning {{argument not in expected state; expected 'unconsumed', observed 'consumed'}}
+  ParamTest pt;
+  pt.consumeFuncMeth(P);            // expected-warning {{argument not in expected state; expected 'unconsumed', observed 'consumed'}}
+  pt << P;                          // expected-warning {{argument not in expected state; expected 'unconsumed', observed 'consumed'}}
+  pt >> P;                          // expected-warning {{argument not in expected state; expected 'unconsumed', observed 'consumed'}}
+}
+
 void baf3(ConsumableClass<int> var) {
   *var;
 }