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!


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@76916 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 727dc4e..5572b7a 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -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();
   
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 7b5a290..4d861be 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -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,
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index 399c302..fbefcd1 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -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;
   }
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index c3d0402..0291f6a 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -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) {
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 1df8b63..c3bb29b 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -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
 //===----------------------------------------------------------------------===//