]> granicus.if.org Git - clang/commitdiff
Add support for the __has_trivial_constructor type trait.
authorAnders Carlsson <andersca@mac.com>
Thu, 16 Apr 2009 00:08:20 +0000 (00:08 +0000)
committerAnders Carlsson <andersca@mac.com>
Thu, 16 Apr 2009 00:08:20 +0000 (00:08 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69245 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/DeclCXX.h
lib/AST/DeclCXX.cpp
lib/AST/ExprCXX.cpp
lib/Parse/ParseExpr.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclCXX.cpp
test/SemaCXX/trivial-constructor.cpp [new file with mode: 0644]

index c82e5cf0e5e722ea6faccd15217f8d2ba322b967..328ec8701ec92a70edb0ce884bf815af443ff72a 100644 (file)
@@ -225,6 +225,9 @@ class CXXRecordDecl : public RecordDecl {
   /// pure virtual function, (that can come from a base class).
   bool Abstract : 1;
   
+  /// HasTrivialConstructor - True when this class has a trivial constructor
+  bool HasTrivialConstructor : 1;
+  
   /// Bases - Base classes of this class.
   /// FIXME: This is wasted space for a union.
   CXXBaseSpecifier *Bases;
@@ -375,6 +378,14 @@ public:
   /// setAbstract - Set whether this class is abstract (C++ [class.abstract])
   void setAbstract(bool Abs) { Abstract = Abs; }
   
+  // hasTrivialConstructor - Whether this class has a trivial constructor
+  // (C++ [class.ctor]p5)
+  bool hasTrivialConstructor() const { return HasTrivialConstructor; }
+  
+  // setHasTrivialConstructor - Set whether this class has a trivial constructor
+  // (C++ [class.ctor]p5)
+  void setHasTrivialConstructor(bool TC) { HasTrivialConstructor = TC; }
+  
   /// \brief If this record is an instantiation of a member class,
   /// retrieves the member class from which it was instantiated.
   ///
index ffc35fe1f74be09624758fc60e8ba250d27993f5..78ed3fcf4d75add02ef5985cac6c16d519313a28 100644 (file)
@@ -29,6 +29,7 @@ CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
     UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false),
     UserDeclaredCopyAssignment(false), UserDeclaredDestructor(false),
     Aggregate(true), PlainOldData(true), Polymorphic(false), Abstract(false),
+    HasTrivialConstructor(true),
     Bases(0), NumBases(0), Conversions(DC, DeclarationName()),
     TemplateOrInstantiation() { }
 
@@ -138,6 +139,11 @@ CXXRecordDecl::addedConstructor(ASTContext &Context,
     //   A POD-struct is an aggregate class [...]
     PlainOldData = false;
 
+    // C++ [class.ctor]p5:
+    //   A constructor is trivial if it is an implicitly-declared default
+    //   constructor.
+    HasTrivialConstructor = false;
+    
     // Note when we have a user-declared copy constructor, which will
     // suppress the implicit declaration of a copy constructor.
     if (ConDecl->isCopyConstructor(Context))
index c2fcc5f9ee4cbd75eb6509cf2a7cd9b7f40ced7f..3634c203566eaefcaa96a61bead33db8cbfefa32 100644 (file)
@@ -170,6 +170,10 @@ bool UnaryTypeTraitExpr::EvaluateTrait() const {
     if (const RecordType *RT = QueriedType->getAsRecordType())
       return cast<CXXRecordDecl>(RT->getDecl())->isAbstract();
     return false;
+  case UTT_HasTrivialConstructor:
+    if (const RecordType *RT = QueriedType->getAsRecordType())
+      return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialConstructor();
+   return false;
   }
 }
 
index 20a8359d1d3a36f61ced16bba65913aa67996d64..d41586ca919cd0ae64b7452fe2038fde029f10f2 100644 (file)
@@ -481,7 +481,7 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) {
 ///                   '__has_nothrow_constructor'             [TODO]
 ///                   '__has_trivial_assign'                  [TODO]
 ///                   '__has_trivial_copy'                    [TODO]
-///                   '__has_trivial_constructor'             [TODO]
+///                   '__has_trivial_constructor'
 ///                   '__has_trivial_destructor'              [TODO]
 ///                   '__has_virtual_destructor'              [TODO]
 ///                   '__is_abstract'                         [TODO]
@@ -771,6 +771,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
   case tok::kw___is_union:
   case tok::kw___is_polymorphic:
   case tok::kw___is_abstract:
+  case tok::kw___has_trivial_constructor:
     return ParseUnaryTypeTrait();
 
   case tok::at: {
index 6233871c9efd1673d20c5d8fb17d4ece52cffc78..6c4580df2871245b349997cfd724d038b8e98889 100644 (file)
@@ -2049,6 +2049,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
       CurClass->setAggregate(false);
       CurClass->setPOD(false);
       CurClass->setPolymorphic(true);
+      CurClass->setHasTrivialConstructor(false);
     }
   }
 
index cc70dc4a5cd3a58b0f7d5660138ad5a9c8a29865..ec1ed4668af8b5c336f2b417d6ef2210e0efc385 100644 (file)
@@ -369,6 +369,18 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
   Class->setAggregate(false);
   Class->setPOD(false);
 
+  if (Virtual) {
+    // C++ [class.ctor]p5:
+    //   A constructor is trivial if its class has no virtual base classes.
+    Class->setHasTrivialConstructor(false);
+  } else {
+    // C++ [class.ctor]p5:
+    //   A constructor is trivial if all the direct base classes of its 
+    //   class have trivial constructors.
+    Class->setHasTrivialConstructor(cast<CXXRecordDecl>(BaseDecl)->
+                                    hasTrivialConstructor());
+  }
+  
   // Create the base specifier.
   // FIXME: Allocate via ASTContext?
   return new CXXBaseSpecifier(SpecifierRange, Virtual, 
@@ -940,6 +952,24 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
   if (RD->isAbstract()) 
     AbstractClassUsageDiagnoser(*this, RD);
     
+  if (RD->hasTrivialConstructor()) {
+    for (RecordDecl::field_iterator i = RD->field_begin(Context), 
+         e = RD->field_end(Context); i != e; ++i) {
+      // All the nonstatic data members must have trivial constructors.
+      QualType FTy = i->getType();
+      while (const ArrayType *AT = Context.getAsArrayType(FTy))
+        FTy = AT->getElementType();
+      
+      if (const RecordType *RT = FTy->getAsRecordType()) {
+        CXXRecordDecl *FieldRD = cast<CXXRecordDecl>(RT->getDecl());
+        if (!FieldRD->hasTrivialConstructor()) {
+          RD->setHasTrivialConstructor(false);
+          break;
+        }
+      }
+    }
+  }
+      
   if (!Template)
     AddImplicitlyDeclaredMembersToClass(RD);
 }
diff --git a/test/SemaCXX/trivial-constructor.cpp b/test/SemaCXX/trivial-constructor.cpp
new file mode 100644 (file)
index 0000000..0c4231e
--- /dev/null
@@ -0,0 +1,34 @@
+// RUN: clang-cc -fsyntax-only -verify %s -std=c++0x
+struct T1 {
+};
+static_assert(__has_trivial_constructor(T1), "T1 has trivial constructor!");
+
+struct T2 {
+  T2();
+};
+static_assert(!__has_trivial_constructor(T2), "T2 has a user-declared constructor!");
+
+struct T3 {
+  virtual void f();
+};
+static_assert(!__has_trivial_constructor(T3), "T3 has a virtual function!");
+
+struct T4 : virtual T3 {
+};
+static_assert(!__has_trivial_constructor(T4), "T4 has a virtual base class!");
+
+struct T5 : T1 {
+};
+static_assert(__has_trivial_constructor(T5), "All the direct base classes of T5 have trivial constructors!");
+
+struct T6 {
+  T5 t5;
+  T1 t1[2][2];
+  static T2 t2;
+};
+static_assert(__has_trivial_constructor(T6), "All nonstatic data members of T6 have trivial constructors!");
+
+struct T7 {
+  T4 t4;
+};
+static_assert(!__has_trivial_constructor(T7), "t4 does not have a trivial constructor!");