[cfe-commits] r76916 - in /cfe/trunk: include/clang/AST/ASTContext.h include/clang/AST/ExprCXX.h include/clang/AST/Type.h lib/AST/ASTContext.cpp lib/AST/DeclCXX.cpp lib/AST/ExprCXX.cpp lib/AST/ExprConstant.cpp lib/AST/Type.cpp lib/Parse/ParseExpr.cpp lib/Sema/SemaDecl.cpp test/SemaCXX/type-traits.cpp

Douglas Gregor dgregor at apple.com
Thu Jul 23 16:49:44 PDT 2009


Author: dgregor
Date: Thu Jul 23 18:49:00 2009
New Revision: 76916

URL: http://llvm.org/viewvc/llvm-project?rev=76916&view=rev
Log:
This patch fixes the implementations of the __has_trivial_destructor
and __has_trivial_constructor builtin pseudo-functions and
additionally implements __has_trivial_copy and __has_trivial_assign,
from John McCall!

Modified:
    cfe/trunk/include/clang/AST/ASTContext.h
    cfe/trunk/include/clang/AST/ExprCXX.h
    cfe/trunk/include/clang/AST/Type.h
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/AST/ExprCXX.cpp
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/lib/AST/Type.cpp
    cfe/trunk/lib/Parse/ParseExpr.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/test/SemaCXX/type-traits.cpp

Modified: cfe/trunk/include/clang/AST/ASTContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=76916&r1=76915&r2=76916&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Thu Jul 23 18:49:00 2009
@@ -708,6 +708,10 @@
   /// getBaseElementType - Returns the innermost element type of a variable
   /// length array type. For example, will return "int" for int[m][n]
   QualType getBaseElementType(const VariableArrayType *VAT);
+
+  /// getBaseElementType - Returns the innermost element type of a type
+  /// (which needn't actually be an array type).
+  QualType getBaseElementType(QualType QT);
   
   /// getArrayDecayedType - Return the properly qualified result of decaying the
   /// specified array type to a pointer.  This operation is non-trivial when

Modified: cfe/trunk/include/clang/AST/ExprCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=76916&r1=76915&r2=76916&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/ExprCXX.h (original)
+++ cfe/trunk/include/clang/AST/ExprCXX.h Thu Jul 23 18:49:00 2009
@@ -913,7 +913,7 @@
 
   QualType getQueriedType() const { return QueriedType; }
 
-  bool EvaluateTrait() const;
+  bool EvaluateTrait(ASTContext&) const;
 
   static bool classof(const Stmt *T) {
     return T->getStmtClass() == UnaryTypeTraitExprClass;

Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=76916&r1=76915&r2=76916&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Thu Jul 23 18:49:00 2009
@@ -564,6 +564,39 @@
 };
 
 
+/// QualifierSet - This class is used to collect qualifiers.
+class QualifierSet {
+public:
+  QualifierSet() :
+    CVRMask(0), AddressSpace(0), GCAttrType(QualType::GCNone) {
+  }
+
+  /// Collect any qualifiers on the given type and return an
+  /// unqualified type.
+  const Type *strip(QualType QT) {
+    CVRMask |= QT.getCVRQualifiers();
+    return strip(QT.getTypePtr());
+  }
+
+  /// Collect any qualifiers on the given type and return an
+  /// unqualified type.
+  const Type *strip(const Type* T);
+
+  /// Apply the collected qualifiers to the given type.
+  QualType apply(QualType QT, ASTContext& C);
+
+  /// Apply the collected qualifiers to the given type.
+  QualType apply(const Type* T, ASTContext& C) {
+    return apply(QualType(T, 0), C);
+  }
+  
+private:
+  unsigned CVRMask;
+  unsigned AddressSpace;
+  QualType::GCAttrTypes GCAttrType;
+};
+
+
 /// BuiltinType - This class is used for builtin types like 'int'.  Builtin
 /// types are always canonical and have a literal name field.
 class BuiltinType : public Type {

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=76916&r1=76915&r2=76916&view=diff

==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Thu Jul 23 18:49:00 2009
@@ -2107,6 +2107,18 @@
   return PtrTy.getQualifiedType(PrettyArrayType->getIndexTypeQualifier());
 }
 
+QualType ASTContext::getBaseElementType(QualType QT) {
+  QualifierSet qualifiers;
+  while (true) {
+    const Type *UT = qualifiers.strip(QT);
+    if (const ArrayType *AT = getAsArrayType(QualType(UT,0))) {
+      QT = AT->getElementType();
+    }else {
+      return qualifiers.apply(QT, *this);
+    }
+  }
+}
+
 QualType ASTContext::getBaseElementType(const VariableArrayType *VAT) {
   QualType ElemTy = VAT->getElementType();
   

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=76916&r1=76915&r2=76916&view=diff

==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Thu Jul 23 18:49:00 2009
@@ -537,14 +537,11 @@
   // non-static data members.
   for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
        E = ClassDecl->field_end(); Field != E; ++Field) {
-    QualType FieldType = C.getCanonicalType((*Field)->getType());
-    while (const ArrayType *AT = C.getAsArrayType(FieldType))
-      FieldType = AT->getElementType();
+    QualType FieldType = C.getBaseElementType((*Field)->getType());
     
-    if (FieldType->getAsRecordType()) {
+    if (const RecordType* RT = FieldType->getAsRecordType()) {
       // Skip over virtual bases which have trivial destructors.
-      CXXRecordDecl *BaseClassDecl
-        = cast<CXXRecordDecl>(FieldType->getAsRecordType()->getDecl());
+      CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(RT->getDecl());
       if (BaseClassDecl->hasTrivialDestructor())
         continue;
       uintptr_t Member = reinterpret_cast<uintptr_t>(*Field);
@@ -640,16 +637,12 @@
       AllToInit.push_back(AllBaseFields[Key]);
       continue;
     }
-    QualType FieldType = C.getCanonicalType((*Field)->getType());
-    while (const ArrayType *AT = C.getAsArrayType(FieldType))
-      FieldType = AT->getElementType();
-      
-    if (FieldType->getAsRecordType()) {
-      CXXConstructorDecl *Ctor = 0;
-      if (CXXRecordDecl *FieldClassDecl = 
-            dyn_cast<CXXRecordDecl>(FieldType->getAsRecordType()->getDecl()))
-        Ctor = FieldClassDecl->getDefaultConstructor(C);
-      if (!Ctor && !FieldType->isDependentType())
+
+    QualType FT = C.getBaseElementType((*Field)->getType());
+    if (const RecordType* RT = FT->getAsRecordType()) {
+      CXXConstructorDecl *Ctor =
+        cast<CXXRecordDecl>(RT->getDecl())->getDefaultConstructor(C);
+      if (!Ctor && !FT->isDependentType())
         Fields.push_back(*Field);
       CXXBaseOrMemberInitializer *Member = 
         new (C) CXXBaseOrMemberInitializer((*Field), 0, 0,

Modified: cfe/trunk/lib/AST/ExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprCXX.cpp?rev=76916&r1=76915&r2=76916&view=diff

==============================================================================
--- cfe/trunk/lib/AST/ExprCXX.cpp (original)
+++ cfe/trunk/lib/AST/ExprCXX.cpp Thu Jul 23 18:49:00 2009
@@ -213,7 +213,7 @@
   return Stmt::child_iterator();
 }
 
-bool UnaryTypeTraitExpr::EvaluateTrait() const {
+bool UnaryTypeTraitExpr::EvaluateTrait(ASTContext& C) const {
   switch(UTT) {
   default: assert(false && "Unknown type trait or not implemented");
   case UTT_IsPOD: return QueriedType->isPODType();
@@ -236,11 +236,58 @@
       return cast<CXXRecordDecl>(RT->getDecl())->isAbstract();
     return false;
   case UTT_HasTrivialConstructor:
-    if (const RecordType *RT = QueriedType->getAsRecordType())
+    // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
+    //   If __is_pod (type) is true then the trait is true, else if type is
+    //   a cv class or union type (or array thereof) with a trivial default
+    //   constructor ([class.ctor]) then the trait is true, else it is false.
+    if (QueriedType->isPODType())
+      return true;
+    if (const RecordType *RT =
+          C.getBaseElementType(QueriedType)->getAsRecordType())
       return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialConstructor();
     return false;
-  case UTT_HasTrivialDestructor:
+  case UTT_HasTrivialCopy:
+    // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
+    //   If __is_pod (type) is true or type is a reference type then
+    //   the trait is true, else if type is a cv class or union type
+    //   with a trivial copy constructor ([class.copy]) then the trait
+    //   is true, else it is false.
+    if (QueriedType->isPODType() || QueriedType->isReferenceType())
+      return true;
+    if (const RecordType *RT = QueriedType->getAsRecordType())
+      return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialCopyConstructor();
+    return false;
+  case UTT_HasTrivialAssign:
+    // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
+    //   If type is const qualified or is a reference type then the
+    //   trait is false. Otherwise if __is_pod (type) is true then the
+    //   trait is true, else if type is a cv class or union type with
+    //   a trivial copy assignment ([class.copy]) then the trait is
+    //   true, else it is false.
+    // Note: the const and reference restrictions are interesting,
+    // given that const and reference members don't prevent a class
+    // from having a trivial copy assignment operator (but do cause
+    // errors if the copy assignment operator is actually used, q.v.
+    // [class.copy]p12).
+
+    if (C.getBaseElementType(QueriedType).isConstQualified())
+      return false;
+    if (QueriedType->isPODType())
+      return true;
     if (const RecordType *RT = QueriedType->getAsRecordType())
+      return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialCopyAssignment();
+    return false;
+  case UTT_HasTrivialDestructor:
+    // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
+    //   If __is_pod (type) is true or type is a reference type
+    //   then the trait is true, else if type is a cv class or union
+    //   type (or array thereof) with a trivial destructor
+    //   ([class.dtor]) then the trait is true, else it is
+    //   false.
+    if (QueriedType->isPODType() || QueriedType->isReferenceType())
+      return true;
+    if (const RecordType *RT =
+          C.getBaseElementType(QueriedType)->getAsRecordType())
       return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDestructor();
     return false;
   }

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=76916&r1=76915&r2=76916&view=diff

==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Thu Jul 23 18:49:00 2009
@@ -735,7 +735,7 @@
   }
 
   bool VisitUnaryTypeTraitExpr(const UnaryTypeTraitExpr *E) {
-    return Success(E->EvaluateTrait(), E);
+    return Success(E->EvaluateTrait(Info.Ctx), E);
   }
 
   bool VisitChooseExpr(const ChooseExpr *E) {

Modified: cfe/trunk/lib/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=76916&r1=76915&r2=76916&view=diff

==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Thu Jul 23 18:49:00 2009
@@ -1072,6 +1072,30 @@
     Args[Idx].Profile(ID);
 }
 
+const Type *QualifierSet::strip(const Type* T) {
+  QualType DT = T->getDesugaredType();
+  CVRMask |= DT.getCVRQualifiers();
+  
+  if (const ExtQualType* EQT = dyn_cast<ExtQualType>(DT)) {
+    if (EQT->getAddressSpace())
+      AddressSpace = EQT->getAddressSpace();
+    if (EQT->getObjCGCAttr())
+      GCAttrType = EQT->getObjCGCAttr();
+    return EQT->getBaseType();
+  }else {
+    // Use the sugared type unless desugaring found extra qualifiers.
+    return (DT.getCVRQualifiers() ? DT.getTypePtr() : T);
+  }
+}
+
+QualType QualifierSet::apply(QualType QT, ASTContext& C) {
+  QT = QT.getWithAdditionalQualifiers(CVRMask);
+  if (GCAttrType) QT = C.getObjCGCQualType(QT, GCAttrType);
+  if (AddressSpace) QT = C.getAddrSpaceQualType(QT, AddressSpace);
+  return QT;
+}
+
+
 //===----------------------------------------------------------------------===//
 // Type Printing
 //===----------------------------------------------------------------------===//

Modified: cfe/trunk/lib/Parse/ParseExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=76916&r1=76915&r2=76916&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseExpr.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExpr.cpp Thu Jul 23 18:49:00 2009
@@ -815,6 +815,8 @@
   case tok::kw___is_polymorphic:
   case tok::kw___is_abstract:
   case tok::kw___has_trivial_constructor:
+  case tok::kw___has_trivial_copy:
+  case tok::kw___has_trivial_assign:
   case tok::kw___has_trivial_destructor:
     return ParseUnaryTypeTrait();
 

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=76916&r1=76915&r2=76916&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Jul 23 18:49:00 2009
@@ -4244,9 +4244,7 @@
   }
 
   if (getLangOptions().CPlusPlus) {
-    QualType EltTy = T;
-    while (const ArrayType *AT = Context.getAsArrayType(EltTy))
-      EltTy = AT->getElementType();
+    QualType EltTy = Context.getBaseElementType(T);
 
     if (const RecordType *RT = EltTy->getAsRecordType()) {
       CXXRecordDecl* RDecl = cast<CXXRecordDecl>(RT->getDecl());
@@ -4430,10 +4428,7 @@
   typedef RecordDecl::field_iterator field_iter;
   for (field_iter fi = RD->field_begin(), fe = RD->field_end(); fi != fe;
        ++fi) {
-    QualType EltTy = (*fi)->getType();
-    while (const ArrayType *AT = Context.getAsArrayType(EltTy))
-      EltTy = AT->getElementType();
-
+    QualType EltTy = Context.getBaseElementType((*fi)->getType());
     if (const RecordType *EltRT = EltTy->getAsRecordType()) {
       CXXRecordDecl* EltRD = cast<CXXRecordDecl>(EltRT->getDecl());
 

Modified: cfe/trunk/test/SemaCXX/type-traits.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/type-traits.cpp?rev=76916&r1=76915&r2=76916&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/type-traits.cpp (original)
+++ cfe/trunk/test/SemaCXX/type-traits.cpp Thu Jul 23 18:49:00 2009
@@ -22,6 +22,7 @@
 struct HasNonPOD { NonPOD np; };
 struct HasVirt { virtual void Virt() {}; };
 typedef Derives NonPODAr[10];
+typedef HasVirt VirtAr[10];
 
 void is_pod()
 {
@@ -109,3 +110,95 @@
   int t17[F(__is_polymorphic(ClassType))];
   int t18[F(__is_polymorphic(Enum))];
 }
+
+typedef Int& IntRef;
+typedef const IntAr ConstIntAr;
+typedef ConstIntAr ConstIntArAr[4];
+
+struct HasCopy {
+  HasCopy(HasCopy& cp);
+};
+
+void has_trivial_default_constructor() {
+  int t01[T(__has_trivial_constructor(Int))];
+  int t02[T(__has_trivial_constructor(IntAr))];
+  int t03[T(__has_trivial_constructor(Union))];
+  int t04[T(__has_trivial_constructor(UnionAr))];
+  int t05[T(__has_trivial_constructor(POD))];
+  int t06[T(__has_trivial_constructor(Derives))];
+  int t07[T(__has_trivial_constructor(ConstIntAr))];
+  int t08[T(__has_trivial_constructor(ConstIntArAr))];
+  int t09[T(__has_trivial_constructor(HasDest))];
+  int t10[T(__has_trivial_constructor(HasPriv))];
+  int t11[F(__has_trivial_constructor(HasCons))];
+  int t12[F(__has_trivial_constructor(HasRef))];
+  int t13[F(__has_trivial_constructor(HasCopy))];
+  int t14[F(__has_trivial_constructor(IntRef))];
+  int t15[T(__has_trivial_constructor(HasAssign))];
+  int t16[T(__has_trivial_constructor(const Int))];
+  int t17[T(__has_trivial_constructor(NonPODAr))];
+  int t18[F(__has_trivial_constructor(VirtAr))];
+}
+
+void has_trivial_copy_constructor() {
+  int t01[T(__has_trivial_copy(Int))];
+  int t02[T(__has_trivial_copy(IntAr))];
+  int t03[T(__has_trivial_copy(Union))];
+  int t04[T(__has_trivial_copy(UnionAr))];
+  int t05[T(__has_trivial_copy(POD))];
+  int t06[T(__has_trivial_copy(Derives))];
+  int t07[T(__has_trivial_copy(ConstIntAr))];
+  int t08[T(__has_trivial_copy(ConstIntArAr))];
+  int t09[T(__has_trivial_copy(HasDest))];
+  int t10[T(__has_trivial_copy(HasPriv))];
+  int t11[T(__has_trivial_copy(HasCons))];
+  int t12[T(__has_trivial_copy(HasRef))];
+  int t13[F(__has_trivial_copy(HasCopy))];
+  int t14[T(__has_trivial_copy(IntRef))];
+  int t15[T(__has_trivial_copy(HasAssign))];
+  int t16[T(__has_trivial_copy(const Int))];
+  int t17[F(__has_trivial_copy(NonPODAr))];
+  int t18[F(__has_trivial_copy(VirtAr))];
+}
+
+void has_trivial_copy_assignment() {
+  int t01[T(__has_trivial_assign(Int))];
+  int t02[T(__has_trivial_assign(IntAr))];
+  int t03[T(__has_trivial_assign(Union))];
+  int t04[T(__has_trivial_assign(UnionAr))];
+  int t05[T(__has_trivial_assign(POD))];
+  int t06[T(__has_trivial_assign(Derives))];
+  int t07[F(__has_trivial_assign(ConstIntAr))];
+  int t08[F(__has_trivial_assign(ConstIntArAr))];
+  int t09[T(__has_trivial_assign(HasDest))];
+  int t10[T(__has_trivial_assign(HasPriv))];
+  int t11[T(__has_trivial_assign(HasCons))];
+  int t12[T(__has_trivial_assign(HasRef))];
+  int t13[T(__has_trivial_assign(HasCopy))];
+  int t14[F(__has_trivial_assign(IntRef))];
+  int t15[F(__has_trivial_assign(HasAssign))];
+  int t16[F(__has_trivial_assign(const Int))];
+  int t17[F(__has_trivial_assign(NonPODAr))];
+  int t18[F(__has_trivial_assign(VirtAr))];
+}
+
+void has_trivial_destructor() {
+  int t01[T(__has_trivial_destructor(Int))];
+  int t02[T(__has_trivial_destructor(IntAr))];
+  int t03[T(__has_trivial_destructor(Union))];
+  int t04[T(__has_trivial_destructor(UnionAr))];
+  int t05[T(__has_trivial_destructor(POD))];
+  int t06[T(__has_trivial_destructor(Derives))];
+  int t07[T(__has_trivial_destructor(ConstIntAr))];
+  int t08[T(__has_trivial_destructor(ConstIntArAr))];
+  int t09[F(__has_trivial_destructor(HasDest))];
+  int t10[T(__has_trivial_destructor(HasPriv))];
+  int t11[T(__has_trivial_destructor(HasCons))];
+  int t12[T(__has_trivial_destructor(HasRef))];
+  int t13[T(__has_trivial_destructor(HasCopy))];
+  int t14[T(__has_trivial_destructor(IntRef))];
+  int t15[T(__has_trivial_destructor(HasAssign))];
+  int t16[T(__has_trivial_destructor(const Int))];
+  int t17[T(__has_trivial_destructor(NonPODAr))];
+  int t18[T(__has_trivial_destructor(VirtAr))];
+}





More information about the cfe-commits mailing list