[analyzer] Handle inlined constructors for rvalue temporaries correctly.
authorJordan Rose <jordan_rose@apple.com>
Fri, 28 Sep 2012 17:15:25 +0000 (17:15 +0000)
committerJordan Rose <jordan_rose@apple.com>
Fri, 28 Sep 2012 17:15:25 +0000 (17:15 +0000)
Previously the analyzer treated all inlined constructors like lvalues,
setting the value of the CXXConstructExpr to the newly-constructed
region. However, some CXXConstructExprs behave like rvalues -- in
particular, the implicit copy constructor into a pass-by-value argument.
In this case, we want only the /contents/ of a temporary object to be
passed, so that we can use the same "copy each argument into the
parameter region" algorithm that we use for scalar arguments.

This may change when we start modeling destructors of temporaries,
but for now this is the last part of <rdar://problem/12137950>.

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

lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
test/Analysis/array-struct-region.cpp
test/Analysis/ctor-inlining.mm

index eb5395e93c7785fad3f33fb1cefdc70cdab2b04f..2e460b79e7dca8b44b8739cdb1957f04eca99900 100644 (file)
@@ -160,7 +160,14 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
         svalBuilder.getCXXThis(CCE->getConstructor()->getParent(), calleeCtx);
       SVal ThisV = state->getSVal(This);
 
-      // Always bind the region to the CXXConstructExpr.
+      // If the constructed object is a prvalue, get its bindings.
+      // Note that we have to be careful here because constructors embedded
+      // in DeclStmts are not marked as lvalues.
+      if (!CCE->isGLValue())
+        if (const MemRegion *MR = ThisV.getAsRegion())
+          if (isa<CXXTempObjectRegion>(MR))
+            ThisV = state->getSVal(cast<Loc>(ThisV));
+
       state = state->BindExpr(CCE, callerCtx, ThisV);
     }
   }
index 22fbf2ff33b185682c8742037e1cecb4db802e0a..e7fbe4d9870ef32c2dd04c20953a46a9b2ce761c 100644 (file)
@@ -61,12 +61,6 @@ int getAssignedField(struct S s) {
 
 void testArgument() {
   clang_analyzer_eval(getConstrainedField(getS()) == 42); // expected-warning{{TRUE}}
-#if __cplusplus
-  // FIXME: Passing the struct by value seems to be confusing C++.
-  // Possibly related to <rdar://problem/12137950>.
-  // expected-warning@-4{{UNKNOWN}}
-#endif
-
   clang_analyzer_eval(getAssignedField(getS()) == 42); // expected-warning{{TRUE}}
 }
 
index 918de0a4563ad663cf4d17810ca384d301ef7d8f..ac963e5d9b0992e2118a06f3d2bd3b857159c1f8 100644 (file)
@@ -103,3 +103,17 @@ namespace TemporaryConstructor {
       return;
   }
 }
+
+
+namespace ConstructorUsedAsRValue {
+  using TemporaryConstructor::BoolWrapper;
+
+  bool extractValue(BoolWrapper b) {
+    return b.value;
+  }
+
+  void test() {
+    bool result = extractValue(BoolWrapper());
+    clang_analyzer_eval(result); // expected-warning{{TRUE}}
+  }
+}