Index: test/SemaCXX/pod.cpp
===================================================================
--- test/SemaCXX/pod.cpp	(revision 0)
+++ test/SemaCXX/pod.cpp	(revision 0)
@@ -0,0 +1,43 @@
+// RUN: clang -fsyntax-only -verify %s 
+#define T(b) (b) ? 1 : -1
+#define F(b) (b) ? -1 : 1
+
+struct NonPOD { NonPOD(int); };
+
+// PODs
+enum Enum { EV };
+struct POD { Enum e; int i; float f; NonPOD* p; };
+typedef int Int;
+typedef Int IntAr[10];
+class Statics { static int priv; static NonPOD np; };
+
+// Not PODs
+struct Derives : POD {};
+struct HasCons { HasCons(int); };
+struct HasAssign { HasAssign operator =(const HasAssign&); };
+struct HasDest { ~HasDest(); };
+class  HasPriv { int priv; };
+class  HasProt { protected: int prot; };
+struct HasRef { int i; int& ref; HasRef() : i(0), ref(i) {} };
+struct HasNonPOD { NonPOD np; };
+struct HasVirt { virtual void Virt() {}; };
+
+void f()
+{
+  int t01[T(__is_pod(int))];
+  int t02[T(__is_pod(Enum))];
+  int t03[T(__is_pod(POD))];
+  int t04[T(__is_pod(Int))];
+  int t05[T(__is_pod(IntAr))];
+  int t06[T(__is_pod(Statics))];
+
+  int t20[F(__is_pod(Derives))];
+  int t21[F(__is_pod(HasCons))];
+  int t22[F(__is_pod(HasAssign))];
+  int t23[F(__is_pod(HasDest))];
+  int t24[F(__is_pod(HasPriv))];
+  int t25[F(__is_pod(HasProt))];
+  int t26[F(__is_pod(HasRef))];
+  int t27[F(__is_pod(HasNonPOD))];
+  int t28[F(__is_pod(HasVirt))];
+}
Index: include/clang/Basic/TokenKinds.def
===================================================================
--- include/clang/Basic/TokenKinds.def	(revision 61541)
+++ include/clang/Basic/TokenKinds.def	(working copy)
@@ -304,6 +304,25 @@
 KEYWORD(__real                      , EXTC90|EXTC99|EXTCPP|EXTCPP0x)
 KEYWORD(__thread                    , EXTC90|EXTC99|EXTCPP|EXTCPP0x)
 
+// GNU and MS Type Traits
+KEYWORD(__has_nothrow_assign        , NOTC90|NOTC99)
+KEYWORD(__has_nothrow_copy          , NOTC90|NOTC99)
+KEYWORD(__has_nothrow_constructor   , NOTC90|NOTC99)
+KEYWORD(__has_trivial_assign        , NOTC90|NOTC99)
+KEYWORD(__has_trivial_copy          , NOTC90|NOTC99)
+KEYWORD(__has_trivial_constructor   , NOTC90|NOTC99)
+KEYWORD(__has_trivial_destructor    , NOTC90|NOTC99)
+KEYWORD(__has_virtual_destructor    , NOTC90|NOTC99)
+KEYWORD(__is_abstract               , NOTC90|NOTC99)
+KEYWORD(__is_base_of                , NOTC90|NOTC99)
+KEYWORD(__is_class                  , NOTC90|NOTC99)
+KEYWORD(__is_empty                  , NOTC90|NOTC99)
+KEYWORD(__is_enum                   , NOTC90|NOTC99)
+KEYWORD(__is_pod                    , NOTC90|NOTC99)
+KEYWORD(__is_polymorphic            , NOTC90|NOTC99)
+KEYWORD(__is_union                  , NOTC90|NOTC99)
+// FIXME: Add MS's traits, too.
+
 // Apple Extension.
 KEYWORD(__private_extern__          , EXTC90|EXTC99|NOTCPP)
 
Index: include/clang/Basic/TypeTraits.h
===================================================================
--- include/clang/Basic/TypeTraits.h	(revision 0)
+++ include/clang/Basic/TypeTraits.h	(revision 0)
@@ -0,0 +1,40 @@
+//===--- TypeTraits.h - C++ Type Traits Support Enumerations ----*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file defines enumerations for the type traits support.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TYPETRAITS_H
+#define LLVM_CLANG_TYPETRAITS_H
+
+namespace clang {
+
+  /// UnaryTypeTrait - Names for the unary type traits.
+  enum UnaryTypeTrait {
+    UTT_HasNothrowAssign,
+    UTT_HasNothrowCopy,
+    UTT_HasNothrowConstructor,
+    UTT_HasTrivialAssign,
+    UTT_HasTrivialCopy,
+    UTT_HasTrivialConstructor,
+    UTT_HasTrivialDestructor,
+    UTT_HasVirtualDestructor,
+    UTT_IsAbstract,
+    UTT_IsClass,
+    UTT_IsEmpty,
+    UTT_IsEnum,
+    UTT_IsPOD,
+    UTT_IsPolymorphic,
+    UTT_IsUnion
+  };
+
+}
+
+#endif
Index: include/clang/AST/StmtNodes.def
===================================================================
--- include/clang/AST/StmtNodes.def	(revision 61541)
+++ include/clang/AST/StmtNodes.def	(working copy)
@@ -113,6 +113,7 @@
 STMT(CXXNewExpr             , Expr)
 STMT(CXXDeleteExpr          , Expr)
 STMT(CXXDependentNameExpr   , Expr)
+STMT(UnaryTypeTraitExpr     , Expr)
 
 // Obj-C Expressions.
 STMT(ObjCStringLiteral    , Expr)
Index: include/clang/AST/DeclCXX.h
===================================================================
--- include/clang/AST/DeclCXX.h	(revision 61541)
+++ include/clang/AST/DeclCXX.h	(working copy)
@@ -22,6 +22,7 @@
 class CXXConstructorDecl;
 class CXXDestructorDecl;
 class CXXConversionDecl;
+class CXXMethodDecl;
 
 /// TemplateTypeParmDecl - Declaration of a template type parameter,
 /// e.g., "T" in
@@ -263,6 +264,10 @@
   /// user-declared copy constructor.
   bool UserDeclaredCopyConstructor : 1;
 
+  /// UserDeclaredCopyAssignment - True when this class has a
+  /// user-declared copy assignment operator.
+  bool UserDeclaredCopyAssignment : 1;
+
   /// UserDeclaredDestructor - True when this class has a
   /// user-declared destructor.
   bool UserDeclaredDestructor : 1;
@@ -270,6 +275,9 @@
   /// Aggregate - True when this class is an aggregate.
   bool Aggregate : 1;
 
+  /// PlainOldData - True when this class is a POD-type.
+  bool PlainOldData : 1;
+
   /// Polymorphic - True when this class is polymorphic, i.e. has at least one
   /// virtual member or derives from a polymorphic class.
   bool Polymorphic : 1;
@@ -321,6 +329,10 @@
   /// copy constructor that accepts a const-qualified argument.
   bool hasConstCopyConstructor(ASTContext &Context) const;
 
+  /// hasConstCopyAssignment - Determines whether this class has a
+  /// copy assignment operator that accepts a const-qualified argument.
+  bool hasConstCopyAssignment(ASTContext &Context) const;
+
   /// addedConstructor - Notify the class that another constructor has
   /// been added. This routine helps maintain information about the
   /// class based on which constructors have been added.
@@ -338,6 +350,18 @@
     return UserDeclaredCopyConstructor;
   }
 
+  /// addedAssignmentOperator - Notify the class that another assignment
+  /// operator has been added. This routine helps maintain information about the
+  /// class based on which operators have been added.
+  void addedAssignmentOperator(ASTContext &Context, CXXMethodDecl *OpDecl);
+
+  /// hasUserDeclaredCopyAssignment - Whether this class has a
+  /// user-declared copy assignment operator. When false, a copy
+  /// assigment operator will be implicitly declared.
+  bool hasUserDeclaredCopyAssignment() const {
+    return UserDeclaredCopyAssignment;
+  }
+
   /// hasUserDeclaredDestructor - Whether this class has a
   /// user-declared destructor. When false, a destructor will be
   /// implicitly declared.
@@ -373,6 +397,15 @@
   /// [dcl.init.aggr]).
   void setAggregate(bool Agg) { Aggregate = Agg; }
 
+  /// isPOD - Whether this class is a POD-type (C++ [class]p4), which is a class
+  /// that is an aggregate that has no non-static non-POD data members, no
+  /// reference data members, no user-defined copy assignment operator and no
+  /// user-defined destructor.
+  bool isPOD() const { return PlainOldData; }
+
+  /// setPOD - Set whether this class is a POD-type (C++ [class]p4).
+  void setPOD(bool POD) { PlainOldData = POD; }
+
   /// isPolymorphic - Whether this class is polymorphic (C++ [class.virtual]),
   /// which means that the class contains or inherits a virtual function.
   bool isPolymorphic() const { return Polymorphic; }
Index: include/clang/AST/ExprCXX.h
===================================================================
--- include/clang/AST/ExprCXX.h	(revision 61541)
+++ include/clang/AST/ExprCXX.h	(working copy)
@@ -14,6 +14,7 @@
 #ifndef LLVM_CLANG_AST_EXPRCXX_H
 #define LLVM_CLANG_AST_EXPRCXX_H
 
+#include "clang/Basic/TypeTraits.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/Decl.h"
 
@@ -701,6 +702,48 @@
   static CXXDependentNameExpr *CreateImpl(llvm::Deserializer& D, ASTContext& C);
 };
 
+/// UnaryTypeTraitExpr - A GCC or MS unary type trait, as used in the
+/// implementation of TR1/C++0x type trait templates.
+class UnaryTypeTraitExpr : public Expr {
+  /// UTT - The trait.
+  UnaryTypeTrait UTT;
+
+  /// Loc - The location of the type trait keyword.
+  SourceLocation Loc;
+
+  /// RParen - The location of the closing paren.
+  SourceLocation RParen;
+
+  /// QueriedType - The type we're testing.
+  QualType QueriedType;
+
+public:
+  UnaryTypeTraitExpr(SourceLocation loc, UnaryTypeTrait utt, QualType queried,
+                     SourceLocation rparen, QualType ty)
+    : Expr(UnaryTypeTraitExprClass, ty, false, queried->isDependentType()),
+      UTT(utt), Loc(loc), RParen(rparen), QueriedType(queried) { }
+
+  virtual SourceRange getSourceRange() const { return SourceRange(Loc, RParen);}
+
+  UnaryTypeTrait getTrait() const { return UTT; }
+
+  QualType getQueriedType() const { return QueriedType; }
+
+  bool Evaluate() const;
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == UnaryTypeTraitExprClass;
+  }
+  static bool classof(const UnaryTypeTraitExpr *) { return true; }
+
+  // Iterators
+  virtual child_iterator child_begin();
+  virtual child_iterator child_end();
+
+  virtual void EmitImpl(llvm::Serializer& S) const;
+  static UnaryTypeTraitExpr *CreateImpl(llvm::Deserializer& D, ASTContext& C);
+};
+
 }  // end namespace clang
 
 #endif
Index: include/clang/AST/Type.h
===================================================================
--- include/clang/AST/Type.h	(revision 61541)
+++ include/clang/AST/Type.h	(working copy)
@@ -295,7 +295,10 @@
   bool isIncompleteOrObjectType() const {
     return !isFunctionType();
   }
-  
+
+  /// isPODType - Return true if this is a plain-old-data type (C++ 3.9p10).
+  bool isPODType() const;
+
   /// isVariablyModifiedType (C99 6.7.5.2p2) - Return true for variable array
   /// types that have a non-constant expression. This does not include "[]".
   bool isVariablyModifiedType() const;
Index: include/clang/Parse/Parser.h
===================================================================
--- include/clang/Parse/Parser.h	(revision 61541)
+++ include/clang/Parse/Parser.h	(working copy)
@@ -978,7 +978,10 @@
   void AnnotateTemplateIdToken(DeclTy *Template, const CXXScopeSpec *SS = 0);
   bool ParseTemplateArgumentList(TemplateArgList &TemplateArgs);
   OwningTemplateArgResult ParseTemplateArgument();
-  
+
+  //===--------------------------------------------------------------------===//
+  // GNU G++: Type Traits [Type-Traits.html in the GCC manual]
+  OwningExprResult ParseUnaryTypeTrait();
 };
 
 }  // end namespace clang
Index: include/clang/Parse/Action.h
===================================================================
--- include/clang/Parse/Action.h	(revision 61541)
+++ include/clang/Parse/Action.h	(working copy)
@@ -16,6 +16,7 @@
 
 #include "clang/Basic/IdentifierTable.h"
 #include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/TypeTraits.h"
 #include "clang/Parse/AccessSpecifier.h"
 #include "clang/Parse/Ownership.h"
 
@@ -880,6 +881,14 @@
     return 0;
   }
 
+  virtual OwningExprResult ActOnUnaryTypeTrait(UnaryTypeTrait OTT,
+                                               SourceLocation KWLoc,
+                                               SourceLocation LParen,
+                                               TypeTy *Ty,
+                                               SourceLocation RParen) {
+    return ExprEmpty();
+  }
+
   //===---------------------------- C++ Classes ---------------------------===//
   /// ActOnBaseSpecifier - Parsed a base specifier
   virtual BaseResult ActOnBaseSpecifier(DeclTy *classdecl, 
Index: lib/Sema/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp	(revision 61541)
+++ lib/Sema/SemaDeclCXX.cpp	(working copy)
@@ -317,7 +317,7 @@
 Sema::ActOnBaseSpecifier(DeclTy *classdecl, SourceRange SpecifierRange,
                          bool Virtual, AccessSpecifier Access,
                          TypeTy *basetype, SourceLocation BaseLoc) {
-  RecordDecl *Decl = (RecordDecl*)classdecl;
+  CXXRecordDecl *Decl = (CXXRecordDecl*)classdecl;
   QualType BaseType = Context.getTypeDeclType((TypeDecl*)basetype);
 
   // Base specifiers must be record types.
@@ -347,8 +347,13 @@
   BaseDecl = BaseDecl->getDefinition(Context);
   assert(BaseDecl && "Base type is not incomplete, but has no definition");
   if (cast<CXXRecordDecl>(BaseDecl)->isPolymorphic())
-    cast<CXXRecordDecl>(Decl)->setPolymorphic(true);
+    Decl->setPolymorphic(true);
 
+  // C++ [dcl.init.aggr]p1:
+  //   An aggregate is [...] a class with [...] no base classes [...].
+  Decl->setAggregate(false);
+  Decl->setPOD(false);
+
   // Create the base specifier.
   return new CXXBaseSpecifier(SpecifierRange, Virtual, 
                               BaseType->isClassType(), Access, BaseType);
@@ -537,8 +542,12 @@
   // C++ [dcl.init.aggr]p1:
   //   An aggregate is an array or a class (clause 9) with [...] no
   //   private or protected non-static data members (clause 11).
-  if (isInstField && (AS == AS_private || AS == AS_protected))
-    cast<CXXRecordDecl>(CurContext)->setAggregate(false);
+  // A POD must be an aggregate.
+  if (isInstField && (AS == AS_private || AS == AS_protected)) {
+    CXXRecordDecl *Record = cast<CXXRecordDecl>(CurContext);
+    Record->setAggregate(false);
+    Record->setPOD(false);
+  }
 
   if (DS.isVirtualSpecified()) {
     if (!isFunc || DS.getStorageClassSpec() == DeclSpec::SCS_static) {
@@ -547,6 +556,7 @@
     } else {
       CXXRecordDecl *CurClass = cast<CXXRecordDecl>(CurContext);
       CurClass->setAggregate(false);
+      CurClass->setPOD(false);
       CurClass->setPolymorphic(true);
     }
   }
@@ -827,17 +837,17 @@
       }
     }
 
-    //  Otherwise, the implicitly declared copy constructor will have
-    //  the form
+    //   Otherwise, the implicitly declared copy constructor will have
+    //   the form
     //
     //       X::X(X&)
-    QualType ArgType = Context.getTypeDeclType(ClassDecl);
+    QualType ArgType = ClassType;
     if (HasConstCopyConstructor)
       ArgType = ArgType.withConst();
     ArgType = Context.getReferenceType(ArgType);
 
-    //  An implicitly-declared copy constructor is an inline public
-    //  member of its class.
+    //   An implicitly-declared copy constructor is an inline public
+    //   member of its class.
     DeclarationName Name 
       = Context.DeclarationNames.getCXXConstructorName(ClassType);
     CXXConstructorDecl *CopyConstructor
@@ -862,6 +872,83 @@
     ClassDecl->addDecl(Context, CopyConstructor);
   }
 
+  if (!ClassDecl->hasUserDeclaredCopyAssignment()) {
+    // Note: The following rules are largely analoguous to the copy
+    // constructor rules. Note that virtual bases are not taken into account
+    // for determining the argument type of the operator. Note also that
+    // operators taking an object instead of a reference are allowed.
+    //
+    // C++ [class.copy]p10:
+    //   If the class definition does not explicitly declare a copy
+    //   assignment operator, one is declared implicitly.
+    //   The implicitly-defined copy assignment operator for a class X
+    //   will have the form
+    //
+    //       X& X::operator=(const X&)
+    //
+    //   if
+    bool HasConstCopyAssignment = true;
+
+    //       -- each direct base class B of X has a copy assignment operator
+    //          whose parameter is of type const B&, const volatile B& or B,
+    //          and
+    for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin();
+         HasConstCopyAssignment && Base != ClassDecl->bases_end(); ++Base) {
+      const CXXRecordDecl *BaseClassDecl
+        = cast<CXXRecordDecl>(Base->getType()->getAsRecordType()->getDecl());
+      HasConstCopyAssignment = BaseClassDecl->hasConstCopyAssignment(Context);
+    }
+
+    //       -- for all the nonstatic data members of X that are of a class
+    //          type M (or array thereof), each such class type has a copy
+    //          assignment operator whose parameter is of type const M&,
+    //          const volatile M& or M.
+    for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin();
+         HasConstCopyAssignment && Field != ClassDecl->field_end(); ++Field) {
+      QualType FieldType = (*Field)->getType();
+      if (const ArrayType *Array = Context.getAsArrayType(FieldType))
+        FieldType = Array->getElementType();
+      if (const RecordType *FieldClassType = FieldType->getAsRecordType()) {
+        const CXXRecordDecl *FieldClassDecl
+          = cast<CXXRecordDecl>(FieldClassType->getDecl());
+        HasConstCopyAssignment
+          = FieldClassDecl->hasConstCopyAssignment(Context);
+      }
+    }
+
+    //   Otherwise, the implicitly declared copy assignment operator will
+    //   have the form
+    //
+    //       X& X::operator=(X&)
+    QualType ArgType = ClassType;
+    QualType RetType = Context.getReferenceType(ArgType);
+    if (HasConstCopyAssignment)
+      ArgType = ArgType.withConst();
+    ArgType = Context.getReferenceType(ArgType);
+
+    //   An implicitly-declared copy assignment operator is an inline public
+    //   member of its class.
+    DeclarationName Name =
+      Context.DeclarationNames.getCXXOperatorName(OO_Equal);
+    CXXMethodDecl *CopyAssignment =
+      CXXMethodDecl::Create(Context, ClassDecl, ClassDecl->getLocation(), Name,
+                            Context.getFunctionType(RetType, &ArgType, 1,
+                                                    false, 0),
+                            /*isStatic=*/false, /*isInline=*/true, 0);
+    CopyAssignment->setAccess(AS_public);
+
+    // Add the parameter to the operator.
+    ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment,
+                                                 ClassDecl->getLocation(),
+                                                 /*IdentifierInfo=*/0,
+                                                 ArgType, VarDecl::None, 0, 0);
+    CopyAssignment->setParams(&FromParam, 1);
+
+    // Don't call addedAssignmentOperator. There is no way to distinguish an
+    // implicit from an explicit assignment operator.
+    ClassDecl->addDecl(Context, CopyAssignment);
+  }
+
   if (!ClassDecl->hasUserDeclaredDestructor()) {
     // C++ [class.dtor]p2:
     //   If a class has no user-declared destructor, a destructor is
@@ -879,8 +966,6 @@
     Destructor->setAccess(AS_public);
     ClassDecl->addDecl(Context, Destructor);
   }
-
-  // FIXME: Implicit copy assignment operator
 }
 
 void Sema::ActOnFinishCXXClassDef(DeclTy *D) {
@@ -1963,7 +2048,7 @@
     return Diag(FnDecl->getLocation(), diag::err_operator_overload_must_be)
       << FnDecl->getDeclName() << NumParams << ErrorKind;
   }
-      
+
   // Overloaded operators other than operator() cannot be variadic.
   if (Op != OO_Call &&
       FnDecl->getType()->getAsFunctionTypeProto()->isVariadic()) {
@@ -2000,6 +2085,15 @@
         << LastParam->getType() << (Op == OO_MinusMinus);
   }
 
+  // Notify the class if it got an assignment operator.
+  if (Op == OO_Equal) {
+    // Would have returned earlier otherwise.
+    assert(isa<CXXMethodDecl>(FnDecl) &&
+      "Overloaded = not member, but not filtered.");
+    CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl);
+    Method->getParent()->addedAssignmentOperator(Context, Method);
+  }
+
   return false;
 }
 
Index: lib/Sema/SemaExprCXX.cpp
===================================================================
--- lib/Sema/SemaExprCXX.cpp	(revision 61541)
+++ lib/Sema/SemaExprCXX.cpp	(working copy)
@@ -842,3 +842,20 @@
   return false;
 }
 
+Sema::OwningExprResult Sema::ActOnUnaryTypeTrait(UnaryTypeTrait OTT,
+                                                 SourceLocation KWLoc,
+                                                 SourceLocation LParen,
+                                                 TypeTy *Ty,
+                                                 SourceLocation RParen) {
+  // FIXME: Some of the type traits have requirements. Interestingly, only the
+  // __is_base_of requirement is explicitly stated to be diagnosed. Indeed,
+  // G++ accepts __is_pod(Incomplete) without complaints, and claims that the
+  // type is indeed a POD.
+
+  // There is no point in eagerly computing the value. The traits are designed
+  // to be used from type trait templates, so Ty will be a template parameter
+  // 99% of the time.
+  return Owned(new UnaryTypeTraitExpr(KWLoc, OTT,
+                                      QualType::getFromOpaquePtr(Ty),
+                                      RParen, Context.BoolTy));
+}
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp	(revision 61541)
+++ lib/Sema/SemaDecl.cpp	(working copy)
@@ -1143,7 +1143,7 @@
     FunctionDecl::StorageClass SC = FunctionDecl::None;
     switch (D.getDeclSpec().getStorageClassSpec()) {
       default: assert(0 && "Unknown storage class!");
-      case DeclSpec::SCS_auto:        
+      case DeclSpec::SCS_auto:
       case DeclSpec::SCS_register:
       case DeclSpec::SCS_mutable:
         Diag(D.getIdentifierLoc(), diag::err_typecheck_sclass_func);
@@ -1309,9 +1309,14 @@
 
     if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD))
       InvalidDecl = InvalidDecl || CheckConstructor(Constructor);
-    else if (isa<CXXDestructorDecl>(NewFD))
-      cast<CXXRecordDecl>(NewFD->getParent())->setUserDeclaredDestructor(true);
-    else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(NewFD))
+    else if (isa<CXXDestructorDecl>(NewFD)) {
+      CXXRecordDecl *Record = cast<CXXRecordDecl>(NewFD->getParent());
+      Record->setUserDeclaredDestructor(true);
+      // C++ [class]p4: A POD-struct is an aggregate class that has [...] no
+      // user-defined destructor.
+      Record->setPOD(false);
+    } else if (CXXConversionDecl *Conversion =
+               dyn_cast<CXXConversionDecl>(NewFD))
       ActOnConversionDeclarator(Conversion);
 
     // Extra checking for C++ overloaded operators (C++ [over.oper]).
@@ -2826,7 +2831,7 @@
   QualType T = GetTypeForDeclarator(D, S);
   assert(!T.isNull() && "GetTypeForDeclarator() returned null type");
   bool InvalidDecl = false;
-  
+
   // C99 6.7.2.1p8: A member of a structure or union may have any type other
   // than a variably modified type.
   if (T->isVariablyModifiedType()) {
@@ -2862,8 +2867,11 @@
                               DeclSpec::SCS_mutable,
                             /*PrevDecl=*/0);
 
-  if (getLangOptions().CPlusPlus)
+  if (getLangOptions().CPlusPlus) {
     CheckExtraCXXDefaultArguments(D);
+    if (!T->isPODType())
+      cast<CXXRecordDecl>(Record)->setPOD(false);
+  }
 
   ProcessDeclAttributes(NewFD, D);
 
@@ -3078,7 +3086,7 @@
       ++NumNamedMembers;
     }
   }
- 
+
   // Okay, we successfully defined 'Record'.
   if (Record) {
     Record->completeDefinition(Context);
Index: lib/Sema/Sema.h
===================================================================
--- lib/Sema/Sema.h	(revision 61541)
+++ lib/Sema/Sema.h	(working copy)
@@ -923,6 +923,14 @@
                                                       SourceLocation EqualLoc,
                                                       ExprTy *AssignExprVal);
 
+  /// ActOnUnaryTypeTrait - Parsed one of the unary type trait support
+  /// pseudo-functions.
+  virtual OwningExprResult ActOnUnaryTypeTrait(UnaryTypeTrait OTT,
+                                               SourceLocation KWLoc,
+                                               SourceLocation LParen,
+                                               TypeTy *Ty,
+                                               SourceLocation RParen);
+
   /// ActOnCXXGlobalScopeSpecifier - Return the object that represents the
   /// global scope ('::').
   virtual CXXScopeTy *ActOnCXXGlobalScopeSpecifier(Scope *S,
Index: lib/AST/ExprCXX.cpp
===================================================================
--- lib/AST/ExprCXX.cpp	(revision 61541)
+++ lib/AST/ExprCXX.cpp	(working copy)
@@ -120,6 +120,21 @@
   return child_iterator();
 }
 
+// UnaryTypeTraitExpr
+Stmt::child_iterator UnaryTypeTraitExpr::child_begin() {
+  return child_iterator();
+}
+Stmt::child_iterator UnaryTypeTraitExpr::child_end() {
+  return child_iterator();
+}
+
+bool UnaryTypeTraitExpr::Evaluate() const {
+  switch(UTT) {
+  default: assert(false && "Unknown type trait or not implemented");
+  case UTT_IsPOD: return QueriedType->isPODType();
+  }
+}
+
 OverloadedOperatorKind CXXOperatorCallExpr::getOperator() const {
   // All simple function calls (e.g. func()) are implicitly cast to pointer to
   // function. As a result, we try and obtain the DeclRefExpr from the 
Index: lib/AST/Expr.cpp
===================================================================
--- lib/AST/Expr.cpp	(revision 61541)
+++ lib/AST/Expr.cpp	(working copy)
@@ -1092,6 +1092,10 @@
   case CXXDefaultArgExprClass:
     return cast<CXXDefaultArgExpr>(this)
              ->isIntegerConstantExpr(Result, Ctx, Loc, isEvaluated);
+
+  case UnaryTypeTraitExprClass:
+    Result = cast<UnaryTypeTraitExpr>(this)->Evaluate();
+    return true;
   }
 
   // Cases that are valid constant exprs fall through to here.
Index: lib/AST/Type.cpp
===================================================================
--- lib/AST/Type.cpp	(revision 61541)
+++ lib/AST/Type.cpp	(working copy)
@@ -670,6 +670,41 @@
   }
 }
 
+/// isPODType - Return true if this is a plain-old-data type (C++ 3.9p10)
+bool Type::isPODType() const {
+  // The compiler shouldn't query this for incomplete types, but the user might.
+  // We return false for that case.
+  if (isIncompleteType())
+    return false;
+
+  switch (CanonicalType->getTypeClass()) {
+    // Everything not explicitly mentioned is not POD.
+  default: return false;
+  case ASQual:
+    return cast<ASQualType>(CanonicalType)->getBaseType()->isPODType();
+  case VariableArray:
+  case ConstantArray:
+    // IncompleteArray is caught by isIncompleteType() above.
+    return cast<ArrayType>(CanonicalType)->getElementType()->isPODType();
+
+  case Builtin:
+  case Complex:
+  case Pointer:
+  case Vector:
+  case ExtVector:
+    return true;
+
+  case Tagged:
+    if (isEnumeralType())
+      return true;
+    if (CXXRecordDecl *RDecl = dyn_cast<CXXRecordDecl>(
+          cast<TagType>(CanonicalType)->getDecl()))
+      return RDecl->isPOD();
+    // C struct/union is POD.
+    return true;
+  }
+}
+
 bool Type::isPromotableIntegerType() const {
   if (const ASQualType *ASQT = dyn_cast<ASQualType>(CanonicalType))
     return ASQT->getBaseType()->isPromotableIntegerType();
Index: lib/AST/StmtSerialization.cpp
===================================================================
--- lib/AST/StmtSerialization.cpp	(revision 61541)
+++ lib/AST/StmtSerialization.cpp	(working copy)
@@ -12,6 +12,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "clang/Basic/TypeTraits.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/ExprObjC.h"
@@ -1530,6 +1531,24 @@
   return new CXXDependentNameExpr(N, Ty, L);
 }
 
+void UnaryTypeTraitExpr::EmitImpl(llvm::Serializer& S) const {
+  S.EmitInt(UTT);
+  S.Emit(Loc);
+  S.Emit(RParen);
+  S.Emit(QueriedType);
+  S.Emit(getType());
+}
+
+UnaryTypeTraitExpr *
+UnaryTypeTraitExpr::CreateImpl(llvm::Deserializer& D, ASTContext& C) {
+  UnaryTypeTrait UTT = static_cast<UnaryTypeTrait>(D.ReadInt());
+  SourceLocation Loc = SourceLocation::ReadVal(D);
+  SourceLocation RParen = SourceLocation::ReadVal(D);
+  QualType QueriedType = QualType::ReadVal(D);
+  QualType Ty = QualType::ReadVal(D);
+  return new UnaryTypeTraitExpr(Loc, UTT, QueriedType, RParen, Ty);
+}
+
 void CXXCatchStmt::EmitImpl(llvm::Serializer& S) const {
   S.Emit(CatchLoc);
   S.EmitOwnedPtr(ExceptionDecl);
Index: lib/AST/ExprConstant.cpp
===================================================================
--- lib/AST/ExprConstant.cpp	(revision 61541)
+++ lib/AST/ExprConstant.cpp	(working copy)
@@ -428,6 +428,12 @@
     return true;
   }
 
+  bool VisitUnaryTypeTraitExpr(const UnaryTypeTraitExpr *E) {
+    Result.zextOrTrunc(getIntTypeSizeInBits(E->getType()));
+    Result = E->Evaluate();
+    return true;
+  }
+
 private:
   bool HandleCast(CastExpr* E);
 };
Index: lib/AST/DeclCXX.cpp
===================================================================
--- lib/AST/DeclCXX.cpp	(revision 61541)
+++ lib/AST/DeclCXX.cpp	(working copy)
@@ -56,9 +56,9 @@
                              SourceLocation L, IdentifierInfo *Id) 
   : RecordDecl(CXXRecord, TK, DC, L, Id),
     UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false),
-    UserDeclaredDestructor(false), Aggregate(true), Polymorphic(false), 
-    Bases(0), NumBases(0),
-    Conversions(DC, DeclarationName()) { }
+    UserDeclaredCopyAssignment(false), UserDeclaredDestructor(false),
+    Aggregate(true), PlainOldData(true), Polymorphic(false), Bases(0),
+    NumBases(0), Conversions(DC, DeclarationName()) { }
 
 CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC,
                                      SourceLocation L, IdentifierInfo *Id,
@@ -91,7 +91,8 @@
 }
 
 bool CXXRecordDecl::hasConstCopyConstructor(ASTContext &Context) const {
-  QualType ClassType = Context.getTypeDeclType(const_cast<CXXRecordDecl*>(this));
+  QualType ClassType
+    = Context.getTypeDeclType(const_cast<CXXRecordDecl*>(this));
   DeclarationName ConstructorName 
     = Context.DeclarationNames.getCXXConstructorName(
                                            Context.getCanonicalType(ClassType));
@@ -107,7 +108,48 @@
   return false;
 }
 
-void 
+bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context) const {
+  QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(
+    const_cast<CXXRecordDecl*>(this)));
+  DeclarationName OpName =Context.DeclarationNames.getCXXOperatorName(OO_Equal);
+
+  DeclContext::lookup_const_iterator Op, OpEnd;
+  for (llvm::tie(Op, OpEnd) = this->lookup(Context, OpName);
+       Op != OpEnd; ++Op) {
+    // C++ [class.copy]p9:
+    //   A user-declared copy assignment operator is a non-static non-template
+    //   member function of class X with exactly one parameter of type X, X&,
+    //   const X&, volatile X& or const volatile X&.
+    const CXXMethodDecl* Method = cast<CXXMethodDecl>(*Op);
+    if (Method->isStatic())
+      continue;
+    // TODO: Skip templates? Or is this implicitly done due to parameter types?
+    const FunctionTypeProto *FnType =
+      Method->getType()->getAsFunctionTypeProto();
+    assert(FnType && "Overloaded operator has no prototype.");
+    // Don't assert on this; an invalid decl might have been left in the AST.
+    if (FnType->getNumArgs() != 1 || FnType->isVariadic())
+      continue;
+    bool AcceptsConst = true;
+    QualType ArgType = FnType->getArgType(0);
+    if (const ReferenceType *Ref = ArgType->getAsReferenceType()) {
+      ArgType = Ref->getPointeeType();
+      // Is it a non-const reference?
+      if (!ArgType.isConstQualified())
+        AcceptsConst = false;
+    }
+    if (Context.getCanonicalType(ArgType).getUnqualifiedType() != ClassType)
+      continue;
+
+    // We have a single argument of type cv X or cv X&, i.e. we've found the
+    // copy assignment operator. Return whether it accepts const arguments.
+    return AcceptsConst;
+  }
+  // FIXME: Is this even possible? Should we assert?
+  return false;
+}
+
+void
 CXXRecordDecl::addedConstructor(ASTContext &Context, 
                                 CXXConstructorDecl *ConDecl) {
   if (!ConDecl->isImplicitlyDeclared()) {
@@ -119,6 +161,10 @@
     //   user-declared constructors (12.1) [...].
     Aggregate = false;
 
+    // C++ [class]p4:
+    //   A POD-struct is an aggregate class [...]
+    PlainOldData = false;
+
     // Note when we have a user-declared copy constructor, which will
     // suppress the implicit declaration of a copy constructor.
     if (ConDecl->isCopyConstructor(Context))
@@ -126,6 +172,35 @@
   }
 }
 
+void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context,
+                                            CXXMethodDecl *OpDecl) {
+  // We're interested specifically in copy assignment operators.
+  // Unlike addedConstructor, this method is not called for implicit
+  // declarations.
+  const FunctionTypeProto *FnType = OpDecl->getType()->getAsFunctionTypeProto();
+  assert(FnType && "Overloaded operator has no proto function type.");
+  assert(FnType->getNumArgs() == 1 && !FnType->isVariadic());
+  QualType ArgType = FnType->getArgType(0);
+  if (const ReferenceType *Ref = ArgType->getAsReferenceType())
+    ArgType = Ref->getPointeeType();
+
+  ArgType = ArgType.getUnqualifiedType();
+  QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(
+    const_cast<CXXRecordDecl*>(this)));
+
+  if (ClassType != Context.getCanonicalType(ArgType))
+    return;
+
+  // This is a copy assignment operator.
+  // Suppress the implicit declaration of a copy constructor.
+  UserDeclaredCopyAssignment = true;
+
+  // C++ [class]p4:
+  //   A POD-struct is an aggregate class that [...] has no user-defined copy
+  //   assignment operator [...].
+  PlainOldData = false;
+}
+
 void CXXRecordDecl::addConversionFunction(ASTContext &Context, 
                                           CXXConversionDecl *ConvDecl) {
   Conversions.addOverload(ConvDecl);
Index: lib/AST/StmtPrinter.cpp
===================================================================
--- lib/AST/StmtPrinter.cpp	(revision 61541)
+++ lib/AST/StmtPrinter.cpp	(working copy)
@@ -1020,6 +1020,32 @@
   OS << E->getName()->getName();
 }
 
+static const char *getTypeTraitName(UnaryTypeTrait UTT) {
+  switch (UTT) {
+  default: assert(false && "Unknown type trait");
+  case UTT_HasNothrowAssign:      return "__has_nothrow_assign";
+  case UTT_HasNothrowCopy:        return "__has_nothrow_copy";
+  case UTT_HasNothrowConstructor: return "__has_nothrow_constructor";
+  case UTT_HasTrivialAssign:      return "__has_trivial_assign";
+  case UTT_HasTrivialCopy:        return "__has_trivial_copy";
+  case UTT_HasTrivialConstructor: return "__has_trivial_constructor";
+  case UTT_HasTrivialDestructor:  return "__has_trivial_destructor";
+  case UTT_HasVirtualDestructor:  return "__has_virtual_destructor";
+  case UTT_IsAbstract:            return "__is_abstract";
+  case UTT_IsClass:               return "__is_class";
+  case UTT_IsEmpty:               return "__is_empty";
+  case UTT_IsEnum:                return "__is_enum";
+  case UTT_IsPOD:                 return "__is_pod";
+  case UTT_IsPolymorphic:         return "__is_polymorphic";
+  case UTT_IsUnion:               return "__is_union";
+  }
+}
+
+void StmtPrinter::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) {
+  OS << getTypeTraitName(E->getTrait()) << "("
+     << E->getQueriedType().getAsString() << ")";
+}
+
 // Obj-C 
 
 void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) {
Index: lib/Parse/ParseExpr.cpp
===================================================================
--- lib/Parse/ParseExpr.cpp	(revision 61541)
+++ lib/Parse/ParseExpr.cpp	(working copy)
@@ -381,6 +381,8 @@
 /// [C++]   'typeid' '(' expression ')'                             [C++ 5.2p1]
 /// [C++]   'typeid' '(' type-id ')'                                [C++ 5.2p1]
 /// [C++]   'this'          [C++ 9.3.2]
+/// [G++]   unary-type-trait '(' type-id ')'
+/// [G++]   binary-type-trait '(' type-id ',' type-id ')'           [TODO]
 /// [clang] '^' block-literal
 ///
 ///       constant: [C99 6.4.4]
@@ -410,6 +412,9 @@
 ///                   '::'[opt] 'delete' cast-expression
 ///                   '::'[opt] 'delete' '[' ']' cast-expression
 ///
+/// [GNU] binary-type-trait:
+///                   '__is_base_of'                          [TODO]
+///
 Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression) {
   if (getLang().CPlusPlus) {
     // Annotate typenames and C++ scope specifiers.
@@ -640,6 +645,9 @@
   case tok::kw_delete: // [C++] delete-expression
     return ParseCXXDeleteExpression();
 
+  case tok::kw___is_pod: // [GNU] unary-type-trait
+    return ParseUnaryTypeTrait();
+
   case tok::at: {
     SourceLocation AtLoc = ConsumeToken();
     return ParseObjCAtExpression(AtLoc);
Index: lib/Parse/ParseExprCXX.cpp
===================================================================
--- lib/Parse/ParseExprCXX.cpp	(revision 61541)
+++ lib/Parse/ParseExprCXX.cpp	(working copy)
@@ -858,3 +858,65 @@
   return Owned(Actions.ActOnCXXDelete(Start, UseGlobal, ArrayDelete,
                                       Operand.release()));
 }
+
+static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind)
+{
+  switch(kind) {
+  default: assert(false && "Not a known unary type trait.");
+  case tok::kw___has_nothrow_assign:      return UTT_HasNothrowAssign;
+  case tok::kw___has_nothrow_copy:        return UTT_HasNothrowCopy;
+  case tok::kw___has_nothrow_constructor: return UTT_HasNothrowConstructor;
+  case tok::kw___has_trivial_assign:      return UTT_HasTrivialAssign;
+  case tok::kw___has_trivial_copy:        return UTT_HasTrivialCopy;
+  case tok::kw___has_trivial_constructor: return UTT_HasTrivialConstructor;
+  case tok::kw___has_trivial_destructor:  return UTT_HasTrivialDestructor;
+  case tok::kw___has_virtual_destructor:  return UTT_HasVirtualDestructor;
+  case tok::kw___is_abstract:             return UTT_IsAbstract;
+  case tok::kw___is_class:                return UTT_IsClass;
+  case tok::kw___is_empty:                return UTT_IsEmpty;
+  case tok::kw___is_enum:                 return UTT_IsEnum;
+  case tok::kw___is_pod:                  return UTT_IsPOD;
+  case tok::kw___is_polymorphic:          return UTT_IsPolymorphic;
+  case tok::kw___is_union:                return UTT_IsUnion;
+  }
+}
+
+/// ParseUnaryTypeTrait - Parse the built-in unary type-trait
+/// pseudo-functions that allow implementation of the TR1/C++0x type traits
+/// templates.
+///
+///       primary-expression:
+/// [GNU]             unary-type-trait '(' type-id ')'
+///
+/// [GNU] unary-type-trait:
+///                   '__has_nothrow_assign'                  [TODO]
+///                   '__has_nothrow_copy'                    [TODO]
+///                   '__has_nothrow_constructor'             [TODO]
+///                   '__has_trivial_assign'                  [TODO]
+///                   '__has_trivial_copy'                    [TODO]
+///                   '__has_trivial_constructor'             [TODO]
+///                   '__has_trivial_destructor'              [TODO]
+///                   '__has_virtual_destructor'              [TODO]
+///                   '__is_abstract'                         [TODO]
+///                   '__is_class'                            [TODO]
+///                   '__is_empty'                            [TODO]
+///                   '__is_enum'                             [TODO]
+///                   '__is_pod'
+///                   '__is_polymorphic'                      [TODO]
+///                   '__is_union'                            [TODO]
+///
+Parser::OwningExprResult Parser::ParseUnaryTypeTrait()
+{
+  UnaryTypeTrait UTT = UnaryTypeTraitFromTokKind(Tok.getKind());
+  SourceLocation Loc = ConsumeToken();
+
+  SourceLocation LParen = Tok.getLocation();
+  if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen))
+    return ExprError();
+
+  TypeTy *Ty = ParseTypeName();
+
+  SourceLocation RParen = MatchRHSPunctuation(tok::r_paren, LParen);
+
+  return Actions.ActOnUnaryTypeTrait(UTT, Loc, LParen, Ty, RParen);
+}
