Implement basic __is_trivial type-trait support, enough to close PR9472.
This introduces a few APIs on the AST to bundle up the standard-based
logic so that programmatic clients have access to exactly the same
behavior.

There is only one serious FIXME here: checking for non-trivial move
constructors and move assignment operators. Those bits need to be added
to the declaration and accessors provided.

This implementation should be enough for the uses of __is_trivial in
libstdc++ 4.6's C++98 library implementation.

Ideas for more thorough test cases or any edge cases missing would be
appreciated. =D

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@130057 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 54c8c35..015b49a 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -217,6 +217,23 @@
   return getCopyConstructor(Context, Qualifiers::Const) != 0;
 }
 
+bool CXXRecordDecl::isTriviallyCopyable() const {
+  // C++0x [class]p5:
+  //   A trivially copyable class is a class that:
+  //   -- has no non-trivial copy constructors,
+  if (!hasTrivialCopyConstructor()) return false;
+  //   -- has no non-trivial move constructors,
+  // FIXME: C++0x: Track and check trivial move constructors.
+  //   -- has no non-trivial copy assignment operators,
+  if (!hasTrivialCopyAssignment()) return false;
+  //   -- has no non-trivial move assignment operators, and
+  // FIXME: C++0x: Track and check trivial move assignment operators.
+  //   -- has a trivial destructor.
+  if (!hasTrivialDestructor()) return false;
+
+  return true;
+}
+
 /// \brief Perform a simplistic form of overload resolution that only considers
 /// cv-qualifiers on a single parameter, and return the best overload candidate
 /// (if there is one).
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 8963126..3591c32 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -1266,6 +1266,7 @@
   case UTT_IsEnum:                return "__is_enum";
   case UTT_IsPOD:                 return "__is_pod";
   case UTT_IsPolymorphic:         return "__is_polymorphic";
+  case UTT_IsTrivial:             return "__is_trivial";
   case UTT_IsUnion:               return "__is_union";
   }
   return "";
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index ba3251b..a25f033 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -902,6 +902,33 @@
   }
 }
 
+bool Type::isTrivialType() const {
+  if (isIncompleteType())
+    return false;
+
+  // C++0x [basic.types]p9:
+  //   Scalar types, trivial class types, arrays of such types, and
+  //   cv-qualified versions of these types are collectively called trivial
+  //   types.
+  const Type *BaseTy = getBaseElementTypeUnsafe();
+  assert(BaseTy && "NULL element type");
+  if (BaseTy->isScalarType()) return true;
+  if (const RecordType *RT = BaseTy->getAs<RecordType>()) {
+    const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(RT->getDecl());
+
+    // C++0x [class]p5:
+    //   A trivial class is a class that has a trivial default constructor
+    if (!ClassDecl->hasTrivialConstructor()) return false;
+    //   and is trivially copyable.
+    if (!ClassDecl->isTriviallyCopyable()) return false;
+
+    return true;
+  }
+
+  // No other types can match.
+  return false;
+}
+
 bool Type::isPromotableIntegerType() const {
   if (const BuiltinType *BT = getAs<BuiltinType>())
     switch (BT->getKind()) {
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index 64b0baf..0e38e39 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -590,6 +590,7 @@
            .Case("is_literal", LangOpts.CPlusPlus)
            .Case("is_pod", LangOpts.CPlusPlus)
            .Case("is_polymorphic", LangOpts.CPlusPlus)
+           .Case("is_trivial", LangOpts.CPlusPlus)
            .Case("is_union", LangOpts.CPlusPlus)
            .Case("tls", PP.getTargetInfo().isTLSSupported())
            .Default(false);
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 1a3290a..d218c79 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -536,6 +536,7 @@
 ///                   '__is_enum'
 ///                   '__is_pod'
 ///                   '__is_polymorphic'
+///                   '__is_trivial'
 ///                   '__is_union'
 ///
 ///       binary-type-trait:
@@ -990,6 +991,7 @@
   case tok::kw___is_literal:
   case tok::kw___is_pod:
   case tok::kw___is_polymorphic:
+  case tok::kw___is_trivial:
   case tok::kw___is_union:
   case tok::kw___has_trivial_constructor:
   case tok::kw___has_trivial_copy:
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 3c9ebc3..38c074d 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -1929,6 +1929,7 @@
   case tok::kw___is_literal:              return UTT_IsLiteral;
   case tok::kw___is_pod:                  return UTT_IsPOD;
   case tok::kw___is_polymorphic:          return UTT_IsPolymorphic;
+  case tok::kw___is_trivial:              return UTT_IsTrivial;
   case tok::kw___is_union:                return UTT_IsUnion;
   }
 }
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index cdfe887..3e00a8c 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -662,6 +662,7 @@
   case tok::kw___is_literal:
   case tok::kw___is_pod:
   case tok::kw___is_polymorphic:
+  case tok::kw___is_trivial:
   case tok::kw___is_union:
   case tok::kw___uuidof:
     return TPResult::True();
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index c6a8210..27545d8 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -2362,6 +2362,7 @@
   default: assert(false && "Unknown type trait or not implemented");
   case UTT_IsPOD: return T->isPODType();
   case UTT_IsLiteral: return T->isLiteralType();
+  case UTT_IsTrivial: return T->isTrivialType();
   case UTT_IsClass: // Fallthrough
   case UTT_IsUnion:
     if (const RecordType *Record = T->getAs<RecordType>()) {