Index: test/Sema/cxx-casting.cpp
===================================================================
--- test/Sema/cxx-casting.cpp	(revision 0)
+++ test/Sema/cxx-casting.cpp	(revision 0)
@@ -0,0 +1,41 @@
+// RUN: clang %s -fsyntax-only -verify
+
+void reinterpret_cast_check() {
+  short s;
+  double *d;
+  float *f;
+  const double * const ccd;     // FIXME: Should error about uninitialized const.
+  const double *cd;
+  int const * volatile * vci;
+  double * const * volatile * *vcd;
+
+  // No errors:
+  f = reinterpret_cast<float*>(d);
+  cd = reinterpret_cast<const double *>(ccd);
+
+  // Expected errors:
+  f = reinterpret_cast<float*>(cd); // expected-error {{reinterpret_cast cannot cast away const}}
+  s = reinterpret_cast<short>(f);   // expected-error {{loss of precision}}
+  vcd = reinterpret_cast<double*const*volatile**>(vci); // expected-error {{reinterpret_cast cannot cast away const}}
+}
+
+void const_cast_check() {
+  int const *ci;
+  int *i;
+  char *c;
+
+  i = const_cast<int*>(ci);
+  c = const_cast<char*>(ci); // expected-error {{invalid const_cast from type}}
+}
+
+void static_cast_check() {
+  float *f;
+  const double *cd;
+  f = static_cast<float*>(cd); // expected-error {{static_cast cannot cast away const}}
+}
+
+void dynamic_cast_check() {
+  float *f;
+  const double *cd;
+  f = dynamic_cast<float*>(cd); // expected-error {{dynamic_cast cannot cast away const}}
+}
Index: include/clang/Basic/DiagnosticKinds.def
===================================================================
--- include/clang/Basic/DiagnosticKinds.def	(revision 48937)
+++ include/clang/Basic/DiagnosticKinds.def	(working copy)
@@ -882,6 +882,12 @@
      "no matching overload found for arguments of type '%0'")
 DIAG(err_overload_multiple_match, ERROR,
      "more than one matching function found in __builtin_overload")
+DIAG(err_cannot_cast_ptr_to_smaller_integral, ERROR,
+     "reinterpret_cast cannot convert '%0' to '%1' because of loss of precision")
+DIAG(err_cannot_cast_away_constness, ERROR,
+     "%0 cannot cast away const or other type qualifiers from type '%1'")
+DIAG(err_invalid_cast, ERROR,
+     "invalid %0 from type '%1' to type '%2'")
 
 // CHECK: printf format string errors
 DIAG(warn_printf_not_string_constant, WARNING,
Index: include/clang/Parse/Action.h
===================================================================
--- include/clang/Parse/Action.h	(revision 48937)
+++ include/clang/Parse/Action.h	(working copy)
@@ -508,7 +508,8 @@
   
   /// ActOnCXXCasts - Parse {dynamic,static,reinterpret,const}_cast's.
   virtual ExprResult ActOnCXXCasts(SourceLocation OpLoc, tok::TokenKind Kind,
-                                   SourceLocation LAngleBracketLoc, TypeTy *Ty,
+                                   SourceLocation LAngleBracketLoc,
+                                   SourceLocation TypeLoc, TypeTy *Ty,
                                    SourceLocation RAngleBracketLoc,
                                    SourceLocation LParenLoc, ExprTy *Op,
                                    SourceLocation RParenLoc) {
Index: lib/Sema/SemaExprCXX.cpp
===================================================================
--- lib/Sema/SemaExprCXX.cpp	(revision 48937)
+++ lib/Sema/SemaExprCXX.cpp	(working copy)
@@ -14,26 +14,395 @@
 #include "Sema.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/ASTContext.h"
+#include "clang/Basic/Diagnostic.h"
+#include <algorithm>
 using namespace clang;
 
-/// ActOnCXXCasts - Parse {dynamic,static,reinterpret,const}_cast's.
+// FIXME: Need to check that a type can be explicitly converted to another type.
+
+/// BuildSubType - As part of the concept of "casting away constness", we
+/// sometimes need to create a 'subtype' of a type. For example, if we have two
+/// types:
+///
+///    int const * volatile *
+///    double * const * volatile *  *
+///
+/// we want the subtypes:
+///
+///    T const * volatile *
+///    T volatile * *
+///
+/// Notice that the pointer "depth" is the same.
+static QualType BuildSubType(QualType Ty, unsigned Depth, ASTContext &Ctx) {
+  if (Depth == 0) {
+    QualType QT = Ctx.CharTy;
+
+    if (Ty.isConstQualified())    QT.addConst();
+    if (Ty.isVolatileQualified()) QT.addVolatile();
+    if (Ty.isRestrictQualified()) QT.addRestrict();
+
+    return QT;
+  }
+
+  assert(isa<PointerType>(Ty) && "This should be a pointer type!");
+
+  QualType Base = cast<PointerType>(Ty)->getPointeeType();
+  QualType QT = BuildSubType(Base, --Depth, Ctx);
+
+  if (Base.isConstQualified())    QT.addConst();
+  if (Base.isVolatileQualified()) QT.addVolatile();
+  if (Base.isRestrictQualified()) QT.addRestrict();
+
+  return Ctx.getPointerType(QT);
+}
+
+/// C++ [expr.const.cast] p8-11:
+/// CastsAwayConstnessFromPointers - Check to see if the cast is
+/// trying to cast away constness from pointers.
+bool Sema::CastsAwayConstnessFromPointers(QualType From, QualType To) {
+  if (To == From) return false;
+
+  // Get the "pointed to" type (ignoring qualifiers at the top level).
+  To = To->getAsPointerType()->getPointeeType();
+  From = From->getAsPointerType()->getPointeeType();
+
+  // Make sure we operate on the canonical type.
+  To = To.getCanonicalType();
+  From = From.getCanonicalType();
+
+  // From C++ [conv.qual]:
+  //
+  //   A conversion can add cv-qualifiers at levels other than the first in
+  //   multi-level pointers, subject to the following rules:
+  //
+  //     Two pointer types T1 and T2 are "similar" if there exists a type T
+  //     and integer n > 0 such that:
+  //
+  //       T1 is cv1,0 ptr to cv1,1 ptr to ... cv1,n-1 ptr to cv1,n T
+  //
+  //     and
+  //
+  //       T1 is cv2,0 ptr to cv2,1 ptr to ... cv2,n-1 ptr to cv2,n T
+  //
+  //     where each cvi,j is const, volatile, const volatile, or nothing.  The
+  //     n-tuple of cv-qualifiers after the first in a pointer type, e.g.,
+  //     cv1,1, cv1,2, ..., cv1,n in the pointer type T1, is called the
+  //     cv-qualification signature of the pointer type. An expression of type
+  //     T1 can be converted to type T2 if and only if the following
+  //     conditions are satisfied:
+  //
+  //       - the pointer types are similar
+  //       - for every j > 0, if const is in cv1,j then const is in cv2,j,
+  //         and similarly for volatile.
+  //       - if the cv1,j and cv2,j are different, then const is in every
+  //         cv2,k for 0 < k < j.
+  bool ConstInToPtrs = true;
+
+  for (;;) {
+    if (!To.isConstQualified()) ConstInToPtrs = false;
+
+    if ((To.getCVRQualifiers() & From.getCVRQualifiers()) != 
+        From.getCVRQualifiers())
+      return From.getCVRQualifiers() ? true : !ConstInToPtrs;
+
+    if (!isa<PointerType>(To)) break;
+
+    To = cast<PointerType>(To)->getPointeeType();
+    From = cast<PointerType>(From)->getPointeeType();
+  }
+
+  return false;
+}
+
+/// CastsAwayConstness - Checks whether a cast "casts away constness" as
+/// described in C++ [conv.qual].
+bool Sema::CastsAwayConstness(QualType CastFrom, QualType CastTo) {
+  if (CastTo == CastFrom) return false;
+
+  if (CastTo->isPointerType() && CastFrom->isPointerType()) {
+    // C++ [conv.qual]:
+    //
+    // Tn and Xn represent types. For two pointer types:
+    // 
+    //   X1 -> T1 cv1,1 * cv1,2 * cv1,3 * cv1,N=4 * ;
+    //   X2 -> T2 cv2,1 * cv2,2 * cv2,3 * cv2,4 * cv2,5 * cv2,6 * cv2,M=7 * ;
+    //
+    //   K = min(N, M);
+    //
+    // casting from X1 to X2 casts away constness if for a non-pointer type T
+    // there does not exist an implicit conversion (clause 4) from:
+    // 
+    //   T cv1,1 * cv1,2 * cv1,3 * cv1,4 * ;
+    //
+    // to
+    // 
+    //   T cv2,4 * cv2,5 * cv2,6 * cv2,7 * ;
+    unsigned DepthCastTo = 0, DepthCastFrom = 0;
+
+    for (QualType QT = CastFrom; QT->isPointerType(); ++DepthCastFrom)
+      QT = cast<PointerType>(QT)->getPointeeType();
+
+    for (QualType QT = CastTo; QT->isPointerType(); ++DepthCastTo)
+      QT = cast<PointerType>(QT)->getPointeeType();
+
+    unsigned K = std::min(DepthCastTo, DepthCastFrom);
+
+    QualType From = BuildSubType(CastFrom, K, Context);
+    QualType To = BuildSubType(CastTo, K, Context);
+
+    return CastsAwayConstnessFromPointers(From, To);
+  }
+
+  // C++ [conv.qual]:
+  //
+  // Casting from an lvalue of type T1 to an lvalue of type T2 using a reference
+  // cast casts away constness if a cast from an rvalue of type "pointer to T1"
+  // to the type "pointer to T2" casts away constness.
+  if (CastTo->isReferenceType() && CastFrom->isReferenceType()) {
+    QualType From = cast<ReferenceType>(CastFrom)->getReferenceeType();
+    QualType To = cast<ReferenceType>(CastTo)->getReferenceeType();
+    return CastsAwayConstness(Context.getPointerType(From),
+                              Context.getPointerType(To));
+  }
+
+  return false;
+}
+
+/// C++ [expr.const.cast] p3:
+/// CastsCVFromPointerType - For two pointer types T1 and T2 where
+///
+///   T1 is cv1,0 pointer to cv1,1 pointer to ... pointer to cv1,n T
+///
+/// and
+///
+///   T2 is cv2,0 pointer to cv2,1 pointer to ... pointer to cv2,n T
+///
+/// where T is any object type or the void type and where cv1,k and
+/// cv2,k may be different cv-qualifications, an rvalue of type T1 may
+/// be explicitly converted to the type T2 using the const_cast.
+/// 
+bool Sema::CastsCVFromPointerType(QualType CastTy, QualType ExprTy) {
+  if (!CastTy->isPointerType() || !ExprTy->isPointerType())
+    return false;
+
+  QualType CastTyBase = CastTy;
+  QualType ExprTyBase = ExprTy;
+
+  while (CastTyBase->isPointerType() && ExprTyBase->isPointerType()) {
+    CastTyBase =
+      cast<PointerType>(CastTyBase)->getPointeeType();
+    ExprTyBase =
+      cast<PointerType>(ExprTyBase)->getPointeeType();
+  }
+
+  if (CastTyBase.getTypePtr() == ExprTyBase.getTypePtr())
+    return true;
+
+  return false;
+}
+
+/// C++ [expr.const.cast] p6:
+/// CastsNullPointer - A null pointer value is converted to the null
+/// pointer value of the destination type. The null member pointer
+/// value is converted to the null member pointer value of the
+/// destination type.
+bool Sema::CastsNullPointer(const Expr *Exp) {
+  return Exp->isNullPointerConstant(Context);
+}
+
+/// C++ [expr.const.cast]:
+/// CheckConstCastOperator - Check that the const_cast operator can
+/// convert to the specified type.
+QualType Sema::CheckConstCastOperator(SourceLocation OpLoc,
+				      SourceLocation LAngleBracketLoc,
+				      SourceLocation TypeLoc,
+				      QualType To,
+				      SourceLocation RAngleBracketLoc,
+				      SourceLocation LParenLoc,
+				      const Expr *E,
+				      SourceLocation RParenLoc) {
+  QualType From = E->getType();
+
+  if (To == From) // {C++ [expr.const.cast] p2} Casting to same type.
+    return To;
+
+  if (CastsCVFromPointerType(To, From))
+    return To;
+
+  if (CastsNullPointer(E)) // {C++ [expr.const.cast] p6} Casts a null pointer.
+    return To;
+
+  // C++ [expr.const.cast] p4: An lvalue of type T1 can be explicitly
+  // converted to an lvalue of type T2 using the cast const_cast<T2&>
+  // (where T1 and T2 are object types) if a pointer to T1 can be
+  // explicitly converted to the type pointer to T2 using a
+  // const_cast.
+  if (E->isLvalue() && From->isObjectType() &&
+      To->isObjectType() && To->isReferenceType()) {
+    ReferenceType *CastRef = cast<ReferenceType>(To.getTypePtr());
+    QualType CT = CastRef->getReferenceeType();
+    QualType ET = From;
+
+    if (From.getTypePtr()->isReferenceType())
+      ET = cast<ReferenceType>(ET.getTypePtr())->getReferenceeType();
+
+    QualType QT =
+      CheckConstCastOperator(OpLoc, LAngleBracketLoc, TypeLoc,
+			     Context.getPointerType(CT),
+			     RAngleBracketLoc, LParenLoc,
+                             E, OpLoc);
+
+    if (!QT.isNull())
+      return To;
+  }
+
+  // C++ [expr.const.cast] p5: For a const_cast involving pointers to
+  // data memebers, multi-level pointers to data members and
+  // multi-level mixed pointers and pointers to data members (4.4),
+  // the rules for const_cast are the same as those used for pointers;
+  // the "member" aspect of a pointer to member is ignored when
+  // determining where the cv-qualifiers are added or removed by the
+  // const_cast. The result of a pointer to data member const_cast
+  // refers to the same member as the original (uncast) pointer to
+  // data member).
+
+  Diag(OpLoc, diag::err_invalid_cast, "const_cast",
+       From.getAsString(), To.getAsString(), SourceRange(OpLoc));
+
+  return QualType();
+}
+
+/// CheckDynamicCastOperator - Check to make sure that the dynamic_cast
+/// expression is legal.
+QualType Sema::CheckDynamicCastOperator(SourceLocation OpLoc,
+                                        SourceLocation LAngleBracketLoc,
+                                        SourceLocation TypeLoc,
+                                        QualType To,
+                                        SourceLocation RAngleBracketLoc,
+                                        SourceLocation LParenLoc,
+                                        const Expr *E,
+                                        SourceLocation RParenLoc) {
+  // C++ [expr.dynamic.cast]
+  QualType From = E->getType();
+
+  if (CastsAwayConstness(From, To)) {
+    // Cannot cast away constness.
+    Diag(OpLoc, diag::err_cannot_cast_away_constness, "dynamic_cast",
+         From.getAsString(), SourceRange(OpLoc));
+    return QualType();
+  }
+
+  // TODO: Finish once dynamic_casts are supported.
+
+  return To;
+}
+
+/// CheckReinterpretCastOperator - Check to make sure that the reinterpret_cast
+/// expression is legal.
+QualType Sema::CheckReinterpretCastOperator(SourceLocation OpLoc,
+                                            SourceLocation LAngleBracketLoc,
+                                            SourceLocation TypeLoc,
+                                            QualType To,
+                                            SourceLocation RAngleBracketLoc,
+                                            SourceLocation LParenLoc,
+                                            const Expr *E,
+                                            SourceLocation RParenLoc) {
+  // C++ [expr.reinterpret.cast]
+  QualType From = E->getType();
+
+  if (CastsAwayConstness(From, To)) {
+    // Cannot cast away constness.
+    Diag(OpLoc, diag::err_cannot_cast_away_constness, "reinterpret_cast",
+         From.getAsString(), SourceRange(OpLoc));
+    return QualType();
+  }
+
+  if (From->isPointerType() && To->isIntegerType()) {
+    // Cannot convert pointer to an integral type that isn't large enough to
+    // hold it.
+    if (Context.getTypeSize(From) > Context.getTypeSize(To)) {
+      Diag(OpLoc, diag::err_cannot_cast_ptr_to_smaller_integral,
+           From.getAsString(), To.getAsString(), SourceRange(OpLoc));
+      return QualType();
+    }
+  }
+
+  return To;
+}
+
+/// CheckStaticCastOperator - Check to make sure that the static_cast expression
+/// is legal.
+QualType Sema::CheckStaticCastOperator(SourceLocation OpLoc,
+                                       SourceLocation LAngleBracketLoc,
+                                       SourceLocation TypeLoc,
+                                       QualType To,
+                                       SourceLocation RAngleBracketLoc,
+                                       SourceLocation LParenLoc,
+                                       const Expr *E,
+                                       SourceLocation RParenLoc) {
+  // C++ [expr.static.cast]
+  QualType From = E->getType();
+
+  if (CastsAwayConstness(From, To)) {
+    // Cannot cast away constness.
+    Diag(OpLoc, diag::err_cannot_cast_away_constness, "static_cast",
+         From.getAsString(), SourceRange(OpLoc));
+    return QualType();
+  }
+
+  // TODO: Finish.
+
+  return To;
+}
+
+/// ActOnCXXCasts - Parse {dynamic,static,reinterpret,const}_casts.
 Action::ExprResult
 Sema::ActOnCXXCasts(SourceLocation OpLoc, tok::TokenKind Kind,
-                    SourceLocation LAngleBracketLoc, TypeTy *Ty,
+                    SourceLocation LAngleBracketLoc,
+                    SourceLocation TypeLoc, TypeTy *Ty,
                     SourceLocation RAngleBracketLoc,
                     SourceLocation LParenLoc, ExprTy *E,
                     SourceLocation RParenLoc) {
   CXXCastExpr::Opcode Op;
+  Expr *Exp = (Expr*)E;
+  QualType ResultTy;
 
   switch (Kind) {
   default: assert(0 && "Unknown C++ cast!");
-  case tok::kw_const_cast:       Op = CXXCastExpr::ConstCast;       break;
-  case tok::kw_dynamic_cast:     Op = CXXCastExpr::DynamicCast;     break;
-  case tok::kw_reinterpret_cast: Op = CXXCastExpr::ReinterpretCast; break;
-  case tok::kw_static_cast:      Op = CXXCastExpr::StaticCast;      break;
+  case tok::kw_const_cast:
+    Op = CXXCastExpr::ConstCast;
+    ResultTy = CheckConstCastOperator(OpLoc, LAngleBracketLoc, TypeLoc,
+				      QualType::getFromOpaquePtr(Ty),
+				      RAngleBracketLoc, LParenLoc,
+				      Exp, RParenLoc);
+    break;
+  case tok::kw_dynamic_cast:
+    Op = CXXCastExpr::DynamicCast;
+    ResultTy = CheckDynamicCastOperator(OpLoc, LAngleBracketLoc, TypeLoc,
+					QualType::getFromOpaquePtr(Ty),
+					RAngleBracketLoc, LParenLoc,
+					Exp, RParenLoc);
+    break;
+  case tok::kw_reinterpret_cast:
+    Op = CXXCastExpr::ReinterpretCast;
+    ResultTy = CheckReinterpretCastOperator(OpLoc, LAngleBracketLoc, TypeLoc,
+					    QualType::getFromOpaquePtr(Ty),
+					    RAngleBracketLoc, LParenLoc,
+					    Exp, RParenLoc);
+    break;
+  case tok::kw_static_cast:
+    Op = CXXCastExpr::StaticCast;
+    ResultTy = CheckStaticCastOperator(OpLoc, LAngleBracketLoc, TypeLoc,
+				       QualType::getFromOpaquePtr(Ty),
+				       RAngleBracketLoc, LParenLoc,
+				       Exp, RParenLoc);
+    break;
   }
-  
-  return new CXXCastExpr(Op, QualType::getFromOpaquePtr(Ty), (Expr*)E, OpLoc);
+
+  if (ResultTy.isNull())
+    return true;
+
+  return new CXXCastExpr(Op, ResultTy, Exp, OpLoc);
 }
 
 /// ActOnCXXBoolLiteral - Parse {true,false} literals.
Index: lib/Sema/Sema.h
===================================================================
--- lib/Sema/Sema.h	(revision 48937)
+++ lib/Sema/Sema.h	(working copy)
@@ -512,7 +512,8 @@
   
   /// ActOnCXXCasts - Parse {dynamic,static,reinterpret,const}_cast's.
   virtual ExprResult ActOnCXXCasts(SourceLocation OpLoc, tok::TokenKind Kind,
-                                   SourceLocation LAngleBracketLoc, TypeTy *Ty,
+                                   SourceLocation LAngleBracketLoc,
+                                   SourceLocation TypeLoc, TypeTy *Ty,
                                    SourceLocation RAngleBracketLoc,
                                    SourceLocation LParenLoc, ExprTy *E,
                                    SourceLocation RParenLoc);
@@ -815,6 +816,53 @@
   void CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
                             SourceLocation ReturnLoc);
   void CheckFloatComparison(SourceLocation loc, Expr* lex, Expr* rex);
+
+  // CastsCVFromPointerType - [C++ 5.2.11p3] This casting operator is trying to
+  // cast away CV qualifiers from pointer types.
+  bool CastsCVFromPointerType(QualType CastTy, QualType ExprTy);
+  bool CastsNullPointer(const Expr *Exp);
+  bool CastsAwayConstness(QualType CastFrom, QualType CastTo);
+  bool CastsAwayConstnessFromPointers(QualType From, QualType To);
+
+  // Type checking for C++ casting operators.
+  QualType CheckConstCastOperator(SourceLocation OpLoc,
+				  SourceLocation LAngleBracketLoc,
+				  SourceLocation TypeLoc,
+				  QualType To,
+				  SourceLocation RAngleBracketLoc,
+				  SourceLocation LParenLoc,
+				  const Expr *E,
+				  SourceLocation RParenLoc);
+  QualType CheckDynamicCastOperator(SourceLocation OpLoc,
+                                    SourceLocation LAngleBracketLoc,
+                                    SourceLocation TypeLoc,
+                                    QualType Ty,
+                                    SourceLocation RAngleBracketLoc,
+                                    SourceLocation LParenLoc,
+                                    const Expr *E,
+                                    SourceLocation RParenLoc);
+  QualType CheckReinterpretCastOperator(SourceLocation OpLoc,
+                                        SourceLocation LAngleBracketLoc,
+                                        SourceLocation TypeLoc,
+                                        QualType Ty,
+                                        SourceLocation RAngleBracketLoc,
+                                        SourceLocation LParenLoc,
+                                        const Expr *E,
+                                        SourceLocation RParenLoc);
+  QualType CheckStaticCastOperator(SourceLocation OpLoc,
+                                   SourceLocation LAngleBracketLoc,
+                                   SourceLocation TypeLoc,
+                                   QualType To,
+                                   SourceLocation RAngleBracketLoc,
+                                   SourceLocation LParenLoc,
+                                   const Expr *E,
+                                   SourceLocation RParenLoc);
+    
+  /// C99: 6.7.5p3: Used by ParseDeclarator/ParseField to make sure we have a
+  /// constant expression of type int with a value greater than zero.  If the
+  /// array has an incomplete type or a valid constant size, return false,
+  /// otherwise emit a diagnostic and return true.
+  bool VerifyConstantArrayType(const ArrayType *ary, SourceLocation loc);
 };
 
 
Index: lib/Parse/ParseExprCXX.cpp
===================================================================
--- lib/Parse/ParseExprCXX.cpp	(revision 48937)
+++ lib/Parse/ParseExprCXX.cpp	(working copy)
@@ -42,6 +42,7 @@
   if (ExpectAndConsume(tok::less, diag::err_expected_less_after, CastName))
     return ExprResult(true);
 
+  SourceLocation TypeLoc = Tok.getLocation();
   TypeTy *CastTy = ParseTypeName();
   SourceLocation RAngleBracketLoc = Tok.getLocation();
 
@@ -61,8 +62,9 @@
 
   if (!Result.isInvalid)
     Result = Actions.ActOnCXXCasts(OpLoc, Kind,
-                                   LAngleBracketLoc, CastTy, RAngleBracketLoc,
-                                   LParenLoc, Result.Val, RParenLoc);
+                                   LAngleBracketLoc, TypeLoc, CastTy,
+                                   RAngleBracketLoc, LParenLoc,
+                                   Result.Val, RParenLoc);
 
   return Result;
 }
