Index: lib/Sema/SemaCast.cpp
===================================================================
--- lib/Sema/SemaCast.cpp	(revision 173715)
+++ lib/Sema/SemaCast.cpp	(working copy)
@@ -19,6 +19,7 @@
 #include "clang/AST/CXXInheritance.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/ExprObjC.h"
+#include "clang/AST/RecordLayout.h"
 #include "clang/Basic/PartialDiagnostic.h"
 #include "clang/Sema/Initialization.h"
 #include "llvm/ADT/SmallVector.h"
@@ -678,6 +679,89 @@
       << SrcExpr.get()->getType() << DestType << OpRange;
 }
 
+/// Check that a reinterpret_cast\<DestType\>(SrcExpr) is not used as upcast
+/// or downcast between respective pointers or references.
+static void DiagnoseReinterpretUpDownCast(Sema &Self, ExprResult &SrcExpr,
+                                          QualType DestType,
+                                          const SourceRange &OpRange) {
+  QualType SrcType = SrcExpr.get()->getType();
+  const Type *SrcUnqualType = SrcType.getTypePtr();
+  const Type *DestUnqualType = DestType.getTypePtr();
+
+  // When casting from pointer or reference, get pointee type; use original 
+  // type otherwise.
+  const CXXRecordDecl *SrcPointeeRD = SrcUnqualType->getPointeeCXXRecordDecl();
+  const CXXRecordDecl *SrcRD =
+    SrcPointeeRD ? SrcPointeeRD : SrcUnqualType->getAsCXXRecordDecl();
+
+  if(!SrcRD || !SrcRD->hasDefinition())
+    return;
+
+  const CXXRecordDecl *DestRD = DestUnqualType->getPointeeCXXRecordDecl();
+
+  if(!DestRD || !DestRD->hasDefinition())
+    return;
+
+  enum {
+    ReinterpretNormalCast = -1,
+    ReinterpretUpcast,
+    ReinterpretDowncast
+  } ReinterpretKind;
+  ReinterpretKind = ReinterpretNormalCast;
+
+  CXXBasePaths SrcBP, DestBP;
+
+  if (SrcRD->isDerivedFrom(DestRD, SrcBP))
+    ReinterpretKind = ReinterpretUpcast;
+  else if (DestRD->isDerivedFrom(SrcRD, DestBP))
+    ReinterpretKind = ReinterpretDowncast;
+  else
+    return;
+
+  const ASTRecordLayout &SrcLayout = Self.Context.getASTRecordLayout(SrcRD);
+  const ASTRecordLayout &DestLayout = Self.Context.getASTRecordLayout(DestRD);
+
+  // TODO: emit fixits. This requires passing operator SourceRange from Parser.
+
+  // Virtual base subobject.
+  if (SrcBP.getDetectedVirtual() || DestBP.getDetectedVirtual()) {
+    Self.Diag(OpRange.getBegin(), diag::warn_reinterpret_wrong_subobject)
+      << ReinterpretKind << SrcType << DestType << OpRange;
+    Self.Diag(OpRange.getBegin(), diag::note_reinterpret_virtual_base)
+      << ReinterpretKind << SrcType << DestType;
+    Self.Diag(OpRange.getBegin(), 
+              diag::note_reinterpret_updowncast_use_static_cast)
+      << ReinterpretKind;
+    return;
+  }
+
+  // Subobject with offset.
+  CharUnits Offset = CharUnits::Zero();
+  if (ReinterpretKind == ReinterpretUpcast)
+    Offset = SrcLayout.getBaseClassOffset(DestRD);
+  else if (ReinterpretKind == ReinterpretDowncast)
+    Offset = DestLayout.getBaseClassOffset(SrcRD);
+  
+  if (!Offset.isZero()) {
+    Self.Diag(OpRange.getBegin(), diag::warn_reinterpret_wrong_subobject)
+      << ReinterpretKind << SrcType << DestType << OpRange;
+    Self.Diag(OpRange.getBegin(), 
+              diag::note_reinterpret_base_offset_inheritance)
+      << ReinterpretKind << SrcType << DestType;
+    Self.Diag(OpRange.getBegin(), 
+              diag::note_reinterpret_updowncast_use_static_cast)
+      << ReinterpretKind;
+    return;
+  }
+
+  // Possibly dangerous case.
+  Self.Diag(OpRange.getBegin(), diag::warn_reinterpret_updowncast)
+    << ReinterpretKind << SrcType << DestType << OpRange;
+  Self.Diag(OpRange.getBegin(),
+            diag::note_reinterpret_updowncast_use_static_cast)
+    << ReinterpretKind;
+}
+
 /// CheckReinterpretCast - Check that a reinterpret_cast\<DestType\>(SrcExpr) is
 /// valid.
 /// Refer to C++ 5.2.10 for details. reinterpret_cast is typically used in code
@@ -691,6 +775,8 @@
   if (SrcExpr.isInvalid()) // if conversion failed, don't report another error
     return;
 
+  DiagnoseReinterpretUpDownCast(Self, SrcExpr, DestType, OpRange);
+
   unsigned msg = diag::err_bad_cxx_cast_generic;
   TryCastResult tcr = 
     TryReinterpretCast(Self, SrcExpr, DestType, 
Index: test/Analysis/inlining/dyn-dispatch-bifurcate.cpp
===================================================================
--- test/Analysis/inlining/dyn-dispatch-bifurcate.cpp	(revision 173715)
+++ test/Analysis/inlining/dyn-dispatch-bifurcate.cpp	(working copy)
@@ -26,6 +26,8 @@
   };
 
   void test(Parent *a) {
+    // expected-warning@+2 {{'reinterpret_cast' is used as a downcast from type 'ReinterpretDisruptsDynamicTypeInfo::Parent *' to its derived type 'ReinterpretDisruptsDynamicTypeInfo::Child *'}}
+    // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
     Child *b = reinterpret_cast<Child *>(a);
     if (!b) return;
     clang_analyzer_eval(b->foo() == 42); // expected-warning{{UNKNOWN}}
Index: test/SemaCXX/warn-reinterpret-updown.cpp
===================================================================
--- test/SemaCXX/warn-reinterpret-updown.cpp	(revision 0)
+++ test/SemaCXX/warn-reinterpret-updown.cpp	(working copy)
@@ -0,0 +1,267 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wreinterpret-updown-zero-adjustment -Wno-unused-volatile-lvalue %s
+
+// PR 13824
+class A {
+};
+class DA : public A {
+};
+class DDA : public DA {
+};
+class DAo : protected A {
+};
+class DAi : private A {
+};
+
+class DVA : public virtual A {
+};
+class DDVA : public virtual DA {
+};
+class DMA : public virtual A, public virtual DA {
+};
+
+class B;
+
+class C {
+};
+
+void reinterpret_not_defined_class(B *b, C *c) {
+  // should not fail if class has no definition
+  (void)*reinterpret_cast<C *>(b);
+  (void)*reinterpret_cast<B *>(c);
+
+  (void)reinterpret_cast<C &>(*b);
+  (void)reinterpret_cast<B &>(*c);
+}
+
+void reinterpret_not_updowncast(A *pa, const A *pca, A &a, const A &ca) {
+  (void)*reinterpret_cast<C *>(pa);
+  (void)*reinterpret_cast<const C *>(pa);
+  (void)*reinterpret_cast<volatile C *>(pa);
+  (void)*reinterpret_cast<const volatile C *>(pa);
+
+  (void)*reinterpret_cast<const C *>(pca);
+  (void)*reinterpret_cast<const volatile C *>(pca);
+
+  (void)reinterpret_cast<C &>(a);
+  (void)reinterpret_cast<const C &>(a);
+  (void)reinterpret_cast<volatile C &>(a);
+  (void)reinterpret_cast<const volatile C &>(a);
+
+  (void)reinterpret_cast<const C &>(ca);
+  (void)reinterpret_cast<const volatile C &>(ca);
+}
+
+void reinterpret_pointer_downcast(A *a, const A *ca) {
+
+  // expected-warning@+2 {{'reinterpret_cast' is used as a downcast from type 'A *' to its derived type 'DA *'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+  (void)*reinterpret_cast<DA *>(a); 
+  // expected-warning@+2 {{'reinterpret_cast' is used as a downcast from type 'A *' to its derived type 'const DA *'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+  (void)*reinterpret_cast<const DA *>(a); 
+  // expected-warning@+2 {{'reinterpret_cast' is used as a downcast from type 'A *' to its derived type 'volatile DA *'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+  (void)*reinterpret_cast<volatile DA *>(a); 
+  // expected-warning@+2 {{'reinterpret_cast' is used as a downcast from type 'A *' to its derived type 'const volatile DA *'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+  (void)*reinterpret_cast<const volatile DA *>(a); 
+
+  // expected-warning@+2 {{'reinterpret_cast' is used as a downcast from type 'const A *' to its derived type 'const DA *'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+  (void)*reinterpret_cast<const DA *>(ca); 
+  // expected-warning@+2 {{'reinterpret_cast' is used as a downcast from type 'const A *' to its derived type 'const volatile DA *'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+  (void)*reinterpret_cast<const volatile DA *>(ca); 
+
+  // expected-warning@+2 {{'reinterpret_cast' is used as a downcast from type 'A *' to its derived type 'DDA *'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+  (void)*reinterpret_cast<DDA *>(a); 
+  // expected-warning@+2 {{'reinterpret_cast' is used as a downcast from type 'A *' to its derived type 'DAo *'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+  (void)*reinterpret_cast<DAo *>(a); 
+  // expected-warning@+2 {{'reinterpret_cast' is used as a downcast from type 'A *' to its derived type 'DAi *'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+  (void)*reinterpret_cast<DAi *>(a); 
+  // expected-warning@+3 {{'reinterpret_cast' might return a pointer to wrong subobject}}
+  // expected-note@+2 {{casting from virtual base type 'A *' to its derived type 'DVA *'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+  (void)*reinterpret_cast<DVA *>(a); 
+  // expected-warning@+3 {{'reinterpret_cast' might return a pointer to wrong subobject}}
+  // expected-note@+2 {{casting from virtual base type 'A *' to its derived type 'DDVA *'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+  (void)*reinterpret_cast<DDVA *>(a); 
+  // expected-warning@+3 {{'reinterpret_cast' might return a pointer to wrong subobject}}
+  // expected-note@+2 {{casting from virtual base type 'A *' to its derived type 'DMA *'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+  (void)*reinterpret_cast<DMA *>(a); 
+}
+
+void reinterpret_reference_downcast(A a, A &ra, const A &cra) {
+  // expected-warning@+2 {{'reinterpret_cast' is used as a downcast from type 'A' to its derived type 'DA &'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+  (void)reinterpret_cast<DA &>(a); 
+  // expected-warning@+2 {{'reinterpret_cast' is used as a downcast from type 'A' to its derived type 'const DA &'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+  (void)reinterpret_cast<const DA &>(a); 
+  // expected-warning@+2 {{'reinterpret_cast' is used as a downcast from type 'A' to its derived type 'volatile DA &'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+  (void)reinterpret_cast<volatile DA &>(a); 
+  // expected-warning@+2 {{'reinterpret_cast' is used as a downcast from type 'A' to its derived type 'const volatile DA &'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+  (void)reinterpret_cast<const volatile DA &>(a); 
+
+  // expected-warning@+2 {{'reinterpret_cast' is used as a downcast from type 'A' to its derived type 'DA &'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+  (void)reinterpret_cast<DA &>(ra); 
+  // expected-warning@+2 {{'reinterpret_cast' is used as a downcast from type 'A' to its derived type 'const DA &'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+  (void)reinterpret_cast<const DA &>(ra); 
+  // expected-warning@+2 {{'reinterpret_cast' is used as a downcast from type 'A' to its derived type 'volatile DA &'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+  (void)reinterpret_cast<volatile DA &>(ra); 
+  // expected-warning@+2 {{'reinterpret_cast' is used as a downcast from type 'A' to its derived type 'const volatile DA &'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+  (void)reinterpret_cast<const volatile DA &>(ra); 
+
+  // expected-warning@+2 {{'reinterpret_cast' is used as a downcast from type 'const A' to its derived type 'const DA &'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+  (void)reinterpret_cast<const DA &>(cra); 
+  // expected-warning@+2 {{'reinterpret_cast' is used as a downcast from type 'const A' to its derived type 'const volatile DA &'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+  (void)reinterpret_cast<const volatile DA &>(cra); 
+
+  // expected-warning@+2 {{'reinterpret_cast' is used as a downcast from type 'A' to its derived type 'DDA &'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+  (void)reinterpret_cast<DDA &>(a); 
+  // expected-warning@+2 {{'reinterpret_cast' is used as a downcast from type 'A' to its derived type 'DAo &'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+  (void)reinterpret_cast<DAo &>(a); 
+  // expected-warning@+2 {{'reinterpret_cast' is used as a downcast from type 'A' to its derived type 'DAi &'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+  (void)reinterpret_cast<DAi &>(a); 
+  // expected-warning@+3 {{'reinterpret_cast' might return a pointer to wrong subobject}}
+  // expected-note@+2 {{casting from virtual base type 'A' to its derived type 'DVA &'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+  (void)reinterpret_cast<DVA &>(a); 
+  // expected-warning@+3 {{'reinterpret_cast' might return a pointer to wrong subobject}}
+  // expected-note@+2 {{casting from virtual base type 'A' to its derived type 'DDVA &'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+  (void)reinterpret_cast<DDVA &>(a); 
+  // expected-warning@+3 {{'reinterpret_cast' might return a pointer to wrong subobject}}
+  // expected-note@+2 {{casting from virtual base type 'A' to its derived type 'DMA &'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+  (void)reinterpret_cast<DMA &>(a); 
+}
+
+void reinterpret_pointer_upcast(DA *da, const DA *cda, DDA *dda, DAo *dao, 
+                                DAi *dai, DVA *dva, DDVA *ddva, DMA *dma) {
+  // expected-warning@+2 {{'reinterpret_cast' is used as an upcast from type 'DA *' to its base type 'A *'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+  (void)*reinterpret_cast<A *>(da); 
+  // expected-warning@+2 {{'reinterpret_cast' is used as an upcast from type 'DA *' to its base type 'const A *'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+  (void)*reinterpret_cast<const A *>(da); 
+  // expected-warning@+2 {{'reinterpret_cast' is used as an upcast from type 'DA *' to its base type 'volatile A *'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+  (void)*reinterpret_cast<volatile A *>(da); 
+  // expected-warning@+2 {{'reinterpret_cast' is used as an upcast from type 'DA *' to its base type 'const volatile A *'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+  (void)*reinterpret_cast<const volatile A *>(da); 
+
+  // expected-warning@+2 {{'reinterpret_cast' is used as an upcast from type 'const DA *' to its base type 'const A *'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+  (void)*reinterpret_cast<const A *>(cda); 
+  // expected-warning@+2 {{'reinterpret_cast' is used as an upcast from type 'const DA *' to its base type 'const volatile A *'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+  (void)*reinterpret_cast<const volatile A *>(cda); 
+
+  // expected-warning@+2 {{'reinterpret_cast' is used as an upcast from type 'DDA *' to its base type 'A *'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+  (void)*reinterpret_cast<A *>(dda); 
+  // expected-warning@+2 {{'reinterpret_cast' is used as an upcast from type 'DDA *' to its base type 'DA *'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+  (void)*reinterpret_cast<DA *>(dda); 
+  // expected-warning@+2 {{'reinterpret_cast' is used as an upcast from type 'DAo *' to its base type 'A *'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+  (void)*reinterpret_cast<A *>(dao); 
+  // expected-warning@+2 {{'reinterpret_cast' is used as an upcast from type 'DAi *' to its base type 'A *'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+  (void)*reinterpret_cast<A *>(dai); 
+  // expected-warning@+3 {{'reinterpret_cast' might return a pointer to wrong subobject}}
+  // expected-note@+2 {{casting to virtual base type 'DVA *' from its derived type 'A *'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+  (void)*reinterpret_cast<A *>(dva); 
+  // expected-warning@+3 {{'reinterpret_cast' might return a pointer to wrong subobject}}
+  // expected-note@+2 {{casting to virtual base type 'DDVA *' from its derived type 'A *'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+  (void)*reinterpret_cast<A *>(ddva); 
+  // expected-warning@+3 {{'reinterpret_cast' might return a pointer to wrong subobject}}
+  // expected-note@+2 {{casting to virtual base type 'DDVA *' from its derived type 'DA *'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+  (void)*reinterpret_cast<DA *>(ddva); 
+  // expected-warning@+3 {{'reinterpret_cast' might return a pointer to wrong subobject}}
+  // expected-note@+2 {{casting to virtual base type 'DMA *' from its derived type 'A *'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+  (void)*reinterpret_cast<A *>(dma); 
+  // expected-warning@+3 {{'reinterpret_cast' might return a pointer to wrong subobject}}
+  // expected-note@+2 {{casting to virtual base type 'DMA *' from its derived type 'DA *'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+  (void)*reinterpret_cast<DA *>(dma); 
+}
+
+void reinterpret_reference_upcast(DA &da, const DA &cda, DDA &dda, DAo &dao,
+                                  DAi &dai, DVA &dva, DDVA &ddva, DMA &dma) {
+  // expected-warning@+2 {{'reinterpret_cast' is used as an upcast from type 'DA' to its base type 'A &'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+  (void)reinterpret_cast<A &>(da); 
+  // expected-warning@+2 {{'reinterpret_cast' is used as an upcast from type 'DA' to its base type 'const A &'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+  (void)reinterpret_cast<const A &>(da); 
+  // expected-warning@+2 {{'reinterpret_cast' is used as an upcast from type 'DA' to its base type 'volatile A &'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+  (void)reinterpret_cast<volatile A &>(da); 
+  // expected-warning@+2 {{'reinterpret_cast' is used as an upcast from type 'DA' to its base type 'const volatile A &'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+  (void)reinterpret_cast<const volatile A &>(da); 
+
+  // expected-warning@+2 {{'reinterpret_cast' is used as an upcast from type 'const DA' to its base type 'const A &'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+  (void)reinterpret_cast<const A &>(cda); 
+  // expected-warning@+2 {{'reinterpret_cast' is used as an upcast from type 'const DA' to its base type 'const volatile A &'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+  (void)reinterpret_cast<const volatile A &>(cda); 
+
+  // expected-warning@+2 {{'reinterpret_cast' is used as an upcast from type 'DDA' to its base type 'A &'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+  (void)reinterpret_cast<A &>(dda); 
+  // expected-warning@+2 {{'reinterpret_cast' is used as an upcast from type 'DDA' to its base type 'DA &'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+  (void)reinterpret_cast<DA &>(dda); 
+  // expected-warning@+2 {{'reinterpret_cast' is used as an upcast from type 'DAo' to its base type 'A &'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+  (void)reinterpret_cast<A &>(dao); 
+  // expected-warning@+2 {{'reinterpret_cast' is used as an upcast from type 'DAi' to its base type 'A &'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+  (void)reinterpret_cast<A &>(dai); 
+  // expected-warning@+3 {{'reinterpret_cast' might return a pointer to wrong subobject}}
+  // expected-note@+2 {{casting to virtual base type 'DVA' from its derived type 'A &'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+  (void)reinterpret_cast<A &>(dva); 
+  // expected-warning@+3 {{'reinterpret_cast' might return a pointer to wrong subobject}}
+  // expected-note@+2 {{casting to virtual base type 'DDVA' from its derived type 'A &'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+  (void)reinterpret_cast<A &>(ddva); 
+  // expected-warning@+3 {{'reinterpret_cast' might return a pointer to wrong subobject}}
+  // expected-note@+2 {{casting to virtual base type 'DDVA' from its derived type 'DA &'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+  (void)reinterpret_cast<DA &>(ddva); 
+  // expected-warning@+3 {{'reinterpret_cast' might return a pointer to wrong subobject}}
+  // expected-note@+2 {{casting to virtual base type 'DMA' from its derived type 'A &'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+  (void)reinterpret_cast<A &>(dma); 
+  // expected-warning@+3 {{'reinterpret_cast' might return a pointer to wrong subobject}}
+  // expected-note@+2 {{casting to virtual base type 'DMA' from its derived type 'DA &'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+  (void)reinterpret_cast<DA &>(dma); 
+}
+
Index: test/SemaCXX/reinterpret-cast.cpp
===================================================================
--- test/SemaCXX/reinterpret-cast.cpp	(revision 173715)
+++ test/SemaCXX/reinterpret-cast.cpp	(working copy)
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -ffreestanding -Wundefined-reinterpret-cast -Wno-unused-volatile-lvalue %s
+// RUN: %clang_cc1 -fsyntax-only -verify -ffreestanding -Wundefined-reinterpret-cast -Wreinterpret-updown -Wno-reinterpret-updown-zero-adjustment -Wno-unused-volatile-lvalue %s
 
 #include <stdint.h>
 
@@ -276,10 +276,6 @@
   // contained union)
   // TODO: checking is not implemented for tag types
 
-  // a type that is a (possible cv-qualified) base class type of the dynamic
-  // type of the object
-  // TODO: checking is not implemented for tag types
-
   // a char or unsigned char type
   (void)reinterpret_cast<char&>(a);
   (void)*reinterpret_cast<char*>(&a);
@@ -290,3 +286,59 @@
   (void)reinterpret_cast<unsigned char&>(b);
   (void)*reinterpret_cast<unsigned char*>(&b);
 }
+
+namespace PR13824 {
+  // PR13824 (-Wreinterpret-updown) not pedantic
+struct A {
+};
+
+struct B : public A {
+};
+
+struct C {
+  int x;
+};
+
+struct D : public C {
+  virtual void foo();
+};
+
+struct E {
+};
+
+struct F : virtual public E {
+};
+
+struct G {
+};
+
+struct H : public G {
+  virtual void foo();
+};
+
+void foo(A *a, C *c, E *e, G *g) {
+  B *b = reinterpret_cast<B *>(a);  // simple downcast
+  A *aa = reinterpret_cast<A *>(b);  // simple upcast
+
+  // expected-warning@+3 {{'reinterpret_cast' might return a pointer to wrong subobject}}
+  // expected-note@+2 {{casting from type 'PR13824::C *' to its derived type 'PR13824::D *'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+  D *d = reinterpret_cast<D *>(c);  // different offset downcast
+  // expected-warning@+3 {{'reinterpret_cast' might return a pointer to wrong subobject}}
+  // expected-note@+2 {{casting from type 'PR13824::D *' to its base type 'PR13824::C *'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+  C *cc = reinterpret_cast<C *>(d);  // different offset upcast
+  // expected-warning@+3 {{'reinterpret_cast' might return a pointer to wrong subobject}}
+  // expected-note@+2 {{casting from virtual base type 'PR13824::E *' to its derived type 'PR13824::F *'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+  F *f = reinterpret_cast<F *>(e);  // virtual base downcast
+  // expected-warning@+3 {{'reinterpret_cast' might return a pointer to wrong subobject}}
+  // expected-note@+2 {{casting to virtual base type 'PR13824::F *' from its derived type 'PR13824::E *'}}
+  // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+  E *ee = reinterpret_cast<E *>(f); // virtual base upcast
+
+  H *h = reinterpret_cast<H *>(g);  // empty base -- no offset
+  G *gg = reinterpret_cast<G *>(h);
+}
+
+} // end namespace PR13824
Index: test/SemaCXX/address-space-conversion.cpp
===================================================================
--- test/SemaCXX/address-space-conversion.cpp	(revision 173715)
+++ test/SemaCXX/address-space-conversion.cpp	(working copy)
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-reinterpret-updown-zero-adjustment -verify %s
 
 // This test checks for the various conversions and casting operations
 // with address-space-qualified pointers.
Index: include/clang/Basic/DiagnosticGroups.td
===================================================================
--- include/clang/Basic/DiagnosticGroups.td	(revision 173715)
+++ include/clang/Basic/DiagnosticGroups.td	(working copy)
@@ -262,6 +262,10 @@
 
 def : DiagGroup<"type-limits">;
 def UndefinedReinterpretCast : DiagGroup<"undefined-reinterpret-cast">;
+def ReinterpretUpDownCastZeroAdjustment :
+  DiagGroup<"reinterpret-updown-zero-adjustment">;
+def ReinterpretUpDownCast : DiagGroup<"reinterpret-updown",
+                                      [ReinterpretUpDownCastZeroAdjustment]>;
 def Unicode  : DiagGroup<"unicode">;
 def UninitializedMaybe : DiagGroup<"conditional-uninitialized">;
 def UninitializedSometimes : DiagGroup<"sometimes-uninitialized">;
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td	(revision 173715)
+++ include/clang/Basic/DiagnosticSemaKinds.td	(working copy)
@@ -4431,6 +4431,22 @@
 def err_bad_reinterpret_cast_overload : Error<
   "reinterpret_cast cannot resolve overloaded function %0 to type %1">;
 
+def warn_reinterpret_updowncast : Warning<
+  "'reinterpret_cast' is used as %select{an upcast|a downcast}0 from type %1 "
+  "to its %select{base|derived}0 type %2">,
+  InGroup<ReinterpretUpDownCastZeroAdjustment>;
+def warn_reinterpret_wrong_subobject : Warning<
+  "'reinterpret_cast' might return a pointer to wrong subobject">,
+  InGroup<ReinterpretUpDownCast>;
+def note_reinterpret_virtual_base : Note<
+  "casting %select{to|from}0 virtual base type %1 %select{from|to}0 "
+  "its derived type %2">;
+def note_reinterpret_base_offset_inheritance : Note<
+  "casting from type %1 to its %select{base|derived}0 type %2">;
+def note_reinterpret_updowncast_use_static_cast : Note<
+  "use 'static_cast' to adjust the pointer correctly while "
+  "%select{upcasting|downcasting}0">;
+
 def err_bad_static_cast_overload : Error<
   "address of overloaded function %0 cannot be static_cast to type %1">;
 
