]> granicus.if.org Git - clang/commitdiff
Implement basic __is_trivial type-trait support, enough to close PR9472.
authorChandler Carruth <chandlerc@gmail.com>
Sat, 23 Apr 2011 10:47:28 +0000 (10:47 +0000)
committerChandler Carruth <chandlerc@gmail.com>
Sat, 23 Apr 2011 10:47:28 +0000 (10:47 +0000)
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

13 files changed:
include/clang/AST/DeclCXX.h
include/clang/AST/Type.h
include/clang/Basic/TokenKinds.def
include/clang/Basic/TypeTraits.h
lib/AST/DeclCXX.cpp
lib/AST/StmtPrinter.cpp
lib/AST/Type.cpp
lib/Lex/PPMacroExpansion.cpp
lib/Parse/ParseExpr.cpp
lib/Parse/ParseExprCXX.cpp
lib/Parse/ParseTentative.cpp
lib/Sema/SemaExprCXX.cpp
test/SemaCXX/type-traits.cpp

index 76510ca31483e9a4f7f6975bb969a98528079e45..dfd3bd6e262243519ab982342f568ea1cbfb583b 100644 (file)
@@ -741,6 +741,10 @@ public:
   // (C++ [class.dtor]p3)
   bool hasTrivialDestructor() const { return data().HasTrivialDestructor; }
 
+  // isTriviallyCopyable - Whether this class is considered trivially copyable
+  // (C++0x [class]p5).
+  bool isTriviallyCopyable() const;
+
   /// \brief If this record is an instantiation of a member class,
   /// retrieves the member class from which it was instantiated.
   ///
index 5d1588726b9234f5c9f74a265829c86a54467fa2..9ed30563598aaba224ed8f56ef6c100b91c3df26 100644 (file)
@@ -1171,6 +1171,10 @@ public:
   /// (C++0x [basic.types]p10)
   bool isLiteralType() const;
 
+  /// isTrivialType - Return true if this is a literal type
+  /// (C++0x [basic.types]p9)
+  bool isTrivialType() const;
+
   /// Helper methods to distinguish type categories. All type predicates
   /// operate on the canonical type, ignoring typedefs and qualifiers.
 
index 6e0dd056a1af7d348398068fad352ebe210dc29a..96f5aa9cada94037f1502cc2c93d9ae4fcc36ef0 100644 (file)
@@ -340,6 +340,7 @@ KEYWORD(__is_enum                   , KEYCXX)
 KEYWORD(__is_literal                , KEYCXX)
 KEYWORD(__is_pod                    , KEYCXX)
 KEYWORD(__is_polymorphic            , KEYCXX)
+KEYWORD(__is_trivial                , KEYCXX)
 KEYWORD(__is_union                  , KEYCXX)
 
 // Apple Extension.
index 791ed34bc3f00d38f1ec58f3db77f56e644d9a0a..5883efe3bb060c5297a4cd02e56d52a6e96822df 100644 (file)
@@ -33,6 +33,7 @@ namespace clang {
     UTT_IsLiteral,
     UTT_IsPOD,
     UTT_IsPolymorphic,
+    UTT_IsTrivial,
     UTT_IsUnion
   };
 
index 54c8c359863032fe452c88743672da8561ce84f2..015b49aed6fdb883cd3c776ddfa8d0f89abc21ab 100644 (file)
@@ -217,6 +217,23 @@ bool CXXRecordDecl::hasConstCopyConstructor(const ASTContext &Context) const {
   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).
index 89631261dcc2e79da35f38719f61a66d142ed696..3591c32ad828fb11f65484b3e35797338c84a7b7 100644 (file)
@@ -1266,6 +1266,7 @@ static const char *getTypeTraitName(UnaryTypeTrait UTT) {
   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 "";
index ba3251b88b8b76249e27703fd0b41311037863c9..a25f0331f44c9d772e63df1acee8df5193807bc1 100644 (file)
@@ -902,6 +902,33 @@ bool Type::isLiteralType() const {
   }
 }
 
+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()) {
index 64b0baf383296d025ff41c1b4deeb6c862e6bb02..0e38e39c26af43a2bc7641423989b8d2533b1dad 100644 (file)
@@ -590,6 +590,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
            .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);
index 1a3290a43dbb46339f6496c188cba3062194dcb4..d218c7973606f023b65423a811803ceea809a668 100644 (file)
@@ -536,6 +536,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
 ///                   '__is_enum'
 ///                   '__is_pod'
 ///                   '__is_polymorphic'
+///                   '__is_trivial'
 ///                   '__is_union'
 ///
 ///       binary-type-trait:
@@ -990,6 +991,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
   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:
index 3c9ebc388bcb67a1d75b823ed0419b9413aa6e5d..38c074d1de6f65d4c7b4433b873c8324a49f10f5 100644 (file)
@@ -1929,6 +1929,7 @@ static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind) {
   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;
   }
 }
index cdfe8875d4cfbabac192f70b663bb4f8454fdfaa..3e00a8c0db551d5e042c9cd6c44b4bf2803a2530 100644 (file)
@@ -662,6 +662,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
   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();
index c6a82109115ce93f540d2fa00bbac83f7a4006f7..27545d802e43920c6d39f2ec1f9352b4e8464d6f 100644 (file)
@@ -2362,6 +2362,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, QualType T,
   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>()) {
index ff9a6bf51a6f17b257110b3781d096aeb4db957f..cbb3549c501d4a8f27c1d654af7a27eb1053938e 100644 (file)
@@ -548,3 +548,37 @@ void is_convertible_to() {
   int t22[F(__is_convertible_to(PrivateCopy, PrivateCopy))];
   int t23[T(__is_convertible_to(X0<int>, X0<float>))];
 }
+
+void is_trivial()
+{
+  int t01[T(__is_trivial(int))];
+  int t02[T(__is_trivial(Enum))];
+  int t03[T(__is_trivial(POD))];
+  int t04[T(__is_trivial(Int))];
+  int t05[T(__is_trivial(IntAr))];
+  int t06[T(__is_trivial(Statics))];
+  int t07[T(__is_trivial(Empty))];
+  int t08[T(__is_trivial(EmptyUnion))];
+  int t09[T(__is_trivial(Union))];
+  int t10[T(__is_trivial(HasFunc))];
+  int t11[T(__is_trivial(HasOp))];
+  int t12[T(__is_trivial(HasConv))];
+  int t13[T(__is_trivial(HasAssign))];
+  int t15[T(__is_trivial(HasAnonymousUnion))];
+  int t16[T(__is_trivial(Derives))];
+  int t17[T(__is_trivial(DerivesEmpty))];
+  int t18[T(__is_trivial(NonPODAr))];
+  int t19[T(__is_trivial(HasPriv))];
+  int t20[T(__is_trivial(HasProt))];
+
+  int f01[F(__is_trivial(IntArNB))];
+  int f02[F(__is_trivial(HasCons))];
+  int f03[F(__is_trivial(HasCopyAssign))];
+  int f04[F(__is_trivial(HasDest))];
+  int f05[F(__is_trivial(HasRef))];
+  int f06[F(__is_trivial(HasNonPOD))];
+  int f07[F(__is_trivial(HasVirt))];
+  int f08[F(__is_trivial(void))];
+  int f09[F(__is_trivial(cvoid))];
+  int f10[F(__is_trivial(NonPODArNB))];
+}