From eb41640fb417e25eb3218c2662a0dd512cdab04a Mon Sep 17 00:00:00 2001
From: Jordan Rose <jordan_rose@apple.com>
Date: Wed, 22 May 2013 18:09:44 +0000
Subject: [PATCH] [analyzer] Don't crash if a block doesn't have a type
 signature.

Currently, blocks instantiated in templates lose their "signature as
written"; it's not clear if this is intentional. Change the analyzer's
use of BlockDecl::getSignatureAsWritten to check whether or not the
signature is actually there.

<rdar://problem/13954714>

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@182497 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/StaticAnalyzer/Core/CallEvent.cpp |  7 +++++--
 lib/StaticAnalyzer/Core/MemRegion.cpp | 15 ++++++++++++---
 test/Analysis/templates.cpp           | 22 ++++++++++++++++++++++
 3 files changed, 39 insertions(+), 5 deletions(-)

diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp
index dfd20b8b332..8ac09ebb2d1 100644
--- a/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -245,10 +245,13 @@ QualType CallEvent::getDeclaredResultType(const Decl *D) {
     // Blocks are difficult because the return type may not be stored in the
     // BlockDecl itself. The AST should probably be enhanced, but for now we
     // just do what we can.
-    QualType Ty = BD->getSignatureAsWritten()->getType();
-    if (const FunctionType *FT = Ty->getAs<FunctionType>())
+    // FIXME: All blocks should have signatures-as-written, even if the return
+    // type is inferred. (That's signified is with a dependent result type.)
+    if (const TypeSourceInfo *TSI = BD->getSignatureAsWritten()) {
+      const FunctionType *FT = TSI->getType()->castAs<FunctionType>();
       if (!FT->getResultType()->isDependentType())
         return FT->getResultType();
+    }
 
     return QualType();
   }
diff --git a/lib/StaticAnalyzer/Core/MemRegion.cpp b/lib/StaticAnalyzer/Core/MemRegion.cpp
index 42073d4841f..31ac86bea66 100644
--- a/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -806,10 +806,19 @@ const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D,
           sReg = getGlobalsRegion(MemRegion::StaticGlobalSpaceRegionKind,
                                   getFunctionTextRegion(cast<NamedDecl>(STCD)));
         else if (const BlockDecl *BD = dyn_cast<BlockDecl>(STCD)) {
+          // FIXME: The fallback type here is totally bogus -- though it should
+          // never be queried, it will prevent uniquing with the real
+          // BlockTextRegion. Ideally we'd fix the AST so that we always had a
+          // signature.
+          QualType T;
+          if (const TypeSourceInfo *TSI = BD->getSignatureAsWritten())
+            T = TSI->getType();
+          else
+            T = getContext().getFunctionNoProtoType(getContext().VoidTy);
+          
           const BlockTextRegion *BTR =
-            getBlockTextRegion(BD,
-                     C.getCanonicalType(BD->getSignatureAsWritten()->getType()),
-                     STC->getAnalysisDeclContext());
+            getBlockTextRegion(BD, C.getCanonicalType(T),
+                               STC->getAnalysisDeclContext());
           sReg = getGlobalsRegion(MemRegion::StaticGlobalSpaceRegionKind,
                                   BTR);
         }
diff --git a/test/Analysis/templates.cpp b/test/Analysis/templates.cpp
index faa5c1a7620..131794a7c93 100644
--- a/test/Analysis/templates.cpp
+++ b/test/Analysis/templates.cpp
@@ -48,3 +48,25 @@ void testNonTypeTemplateInstantiation() {
 #endif
 }
 
+namespace rdar13954714 {
+  template <bool VALUE>
+  bool blockInTemplate() {
+    return (^() {
+      return VALUE;
+    })();
+  }
+
+  // force instantiation
+  template bool blockInTemplate<true>();
+
+  template <bool VALUE>
+  void blockWithStatic() {
+    (void)^() {
+      static int x;
+      return ++x;
+    };
+  }
+
+  // force instantiation
+  template void blockWithStatic<true>();
+}
-- 
GitLab