diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp
index ab786c6..22d2fa2 100644
--- a/lib/Sema/JumpDiagnostics.cpp
+++ b/lib/Sema/JumpDiagnostics.cpp
@@ -18,6 +18,7 @@
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/StmtObjC.h"
 #include "clang/AST/StmtCXX.h"
+#include "clang/AST/RecursiveASTVisitor.h"
 #include "llvm/ADT/BitVector.h"
 using namespace clang;
 
@@ -119,11 +120,38 @@ unsigned JumpScopeChecker::GetDeepestCommonScope(unsigned A, unsigned B) {
 
 typedef std::pair<unsigned,unsigned> ScopePair;
 
+namespace {
+  struct LiveCXXConstructExprVisitor :
+    public RecursiveASTVisitor<LiveCXXConstructExprVisitor> {
+    const CXXConstructExpr *Constructor;
+    LiveCXXConstructExprVisitor() : Constructor(0) { }
+    bool VisitCXXConstructExpr(const CXXConstructExpr *E) {
+      Constructor = E;
+      return false;
+    }
+    // Stop at a member call. If there is a call the lifetime of the temporary
+    // is not extended and we don't need to worry about it.
+    // FIXME: Is this the only Expr we need to special case?
+    bool TraverseCXXMemberCallExpr(const CXXMemberCallExpr *E) {
+      return true;
+    }
+  };
+}
+
+// hasLiveCXXConstructExpr - Finds if this expresions causes a object
+// to constructed but not destructed. That is, a destructor will be called at
+// later time.
+static const CXXConstructExpr *hasLiveCXXConstructExpr(const Expr* E) {
+  LiveCXXConstructExprVisitor Visitor;
+  Visitor.TraverseStmt(const_cast<Expr*>(E));
+  return Visitor.Constructor;
+}
+
 /// GetDiagForGotoScopeDecl - If this decl induces a new goto scope, return a
 /// diagnostic that should be emitted if control goes over it. If not, return 0.
 static ScopePair GetDiagForGotoScopeDecl(ASTContext &Context, const Decl *D) {
   if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
-    unsigned InDiag = 0, OutDiag = 0;
+    unsigned InDiag = 0;
     if (VD->getType()->isVariablyModifiedType())
       InDiag = diag::note_protected_by_vla;
 
@@ -164,43 +192,40 @@ static ScopePair GetDiagForGotoScopeDecl(ASTContext &Context, const Decl *D) {
       //   where it is in scope is ill-formed unless the variable has
       //   POD type and is declared without an initializer.
 
-      if (const Expr *init = VD->getInit()) {
-        // We actually give variables of record type (or array thereof)
-        // an initializer even if that initializer only calls a trivial
-        // ctor.  Detect that case.
-        // FIXME: With generalized initializer lists, this may
-        // classify "X x{};" as having no initializer.
-        unsigned inDiagToUse = diag::note_protected_by_variable_init;
-
-        const CXXRecordDecl *record = 0;
-
-        if (const CXXConstructExpr *cce = dyn_cast<CXXConstructExpr>(init)) {
-          const CXXConstructorDecl *ctor = cce->getConstructor();
-          record = ctor->getParent();
-
-          if (ctor->isTrivial() && ctor->isDefaultConstructor()) {
-            if (!record->hasTrivialDestructor())
-              inDiagToUse = diag::note_protected_by_variable_nontriv_destructor;
-            else if (!record->isPOD())
-              inDiagToUse = diag::note_protected_by_variable_non_pod;
-            else
-              inDiagToUse = 0;
-          }
-        } else if (VD->getType()->isArrayType()) {
-          record = VD->getType()->getBaseElementTypeUnsafe()
-                                ->getAsCXXRecordDecl();
+      const Expr *Init = VD->getInit();
+      if (!Init)
+        return ScopePair(InDiag, 0);
+
+      const CXXConstructExpr *CE = hasLiveCXXConstructExpr(Init);
+      if (!CE)
+        return ScopePair(diag::note_protected_by_variable_init, 0);
+
+      const Type *T = CE->getType().getTypePtr();
+      if (T->isArrayType())
+        T = T->getBaseElementTypeUnsafe();
+      const CXXRecordDecl *Record = T->getAsCXXRecordDecl();
+
+      // If we need to call a non trivial destructor for this variable,
+      // record an out diagnostic.
+      unsigned OutDiag = 0;
+      if (!Record->hasTrivialDestructor())
+        OutDiag = diag::note_exits_dtor;
+
+      if (const CXXConstructExpr *cce = dyn_cast<CXXConstructExpr>(Init)) {
+        const CXXConstructorDecl *ctor = cce->getConstructor();
+        if (ctor->isTrivial() && ctor->isDefaultConstructor()) {
+          if (OutDiag)
+            InDiag = diag::note_protected_by_variable_nontriv_destructor;
+          else if (!Record->isPOD())
+            InDiag = diag::note_protected_by_variable_non_pod;
+          return ScopePair(InDiag, OutDiag);
         }
-
-        if (inDiagToUse)
-          InDiag = inDiagToUse;
-
-        // Also object to indirect jumps which leave scopes with dtors.
-        if (record && !record->hasTrivialDestructor())
-          OutDiag = diag::note_exits_dtor;
       }
+
+      return ScopePair(diag::note_protected_by_variable_init, OutDiag);
     }
-    
-    return ScopePair(InDiag, OutDiag);    
+
+    return ScopePair(InDiag, 0);
   }
 
   if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
diff --git a/test/SemaCXX/scope-check.cpp b/test/SemaCXX/scope-check.cpp
index 86d1bd8..78228c0 100644
--- a/test/SemaCXX/scope-check.cpp
+++ b/test/SemaCXX/scope-check.cpp
@@ -202,3 +202,61 @@ namespace test10 {
     return 0;
   }
 }
+
+// pr13812
+namespace test11 {
+  struct C {
+    C(int x);
+    ~C();
+  };
+  void f(void **ip) {
+    static void *ips[] = { &&l0 };
+  l0:  // expected-note {{possible target of indirect goto}}
+    C c0 = 42; // expected-note {{jump exits scope of variable with non-trivial destructor}}
+    goto *ip; // expected-error {{indirect goto might cross protected scopes}}
+  }
+}
+
+namespace test12 {
+  struct C {
+    C(int x);
+    ~C();
+  };
+  void f(void **ip) {
+    static void *ips[] = { &&l0 };
+    const C c0 = 17;
+  l0: // expected-note {{possible target of indirect goto}}
+    const C &c1 = 42; // expected-note {{jump exits scope of variable with non-trivial destructor}}
+    const C &c2 = c0;
+    goto *ip; // expected-error {{indirect goto might cross protected scopes}}
+  }
+}
+
+namespace test13 {
+  struct C {
+    C(int x);
+    ~C();
+    int i;
+  };
+  void f(void **ip) {
+    static void *ips[] = { &&l0 };
+  l0: // expected-note {{possible target of indirect goto}}
+    const int &c1 = C(1).i; // expected-note {{jump exits scope of variable with non-trivial destructor}}
+    goto *ip;  // expected-error {{indirect goto might cross protected scopes}}
+  }
+}
+
+namespace test14 {
+  struct C {
+    C(int x);
+    ~C();
+    operator int&() const;
+  };
+  void f(void **ip) {
+    static void *ips[] = { &&l0 };
+  l0:
+    // no warning since the C temporary is destructed before the goto.
+    const int &c1 = C(1);
+    goto *ip;
+  }
+}
