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.
I found it useful to introduce a method
clang::Type::getBaseElementTypeNoTypeQual(), which just drills down past
any array types and type qualifiers; it's both more convenient and
probably more efficient than iteratively calling getAsArrayType() /
getElementType(). I'm not totally confident in its implementation, so
I'd appreciate a review specifically of that. I also went ahead and
retrofitted some call sites that fit the iterative pattern.
John.
Index: test/SemaCXX/type-traits.cpp
===================================================================
--- test/SemaCXX/type-traits.cpp (revision 76866)
+++ test/SemaCXX/type-traits.cpp (working copy)
@@ -22,6 +22,7 @@ struct HasRef { int i; int& ref; HasRef(
struct HasNonPOD { NonPOD np; };
struct HasVirt { virtual void Virt() {}; };
typedef Derives NonPODAr[10];
+typedef HasVirt VirtAr[10];
void is_pod()
{
@@ -109,3 +110,95 @@ void is_polymorphic()
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))];
+}
Index: include/clang/AST/Type.h
===================================================================
--- include/clang/AST/Type.h (revision 76866)
+++ include/clang/AST/Type.h (working copy)
@@ -473,6 +473,11 @@ public:
/// element type of the array, potentially with type qualifiers missing.
/// This method should never be used when type qualifiers are meaningful.
const Type *getArrayElementTypeNoTypeQual() const;
+
+ /// getBaseElementTypeNoTypeQual - Recursively strip qualifiers and
+ /// array types off this type. This method should never be used when
+ /// type qualifiers are meaningful.
+ const Type *getBaseElementTypeNoTypeQual() const;
/// getPointeeType - If this is a pointer, ObjC object pointer, or block
/// pointer, this returns the respective pointee.
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp (revision 76866)
+++ lib/Sema/SemaDecl.cpp (working copy)
@@ -4233,9 +4233,7 @@ FieldDecl *Sema::CheckFieldDecl(Declarat
}
if (getLangOptions().CPlusPlus) {
- QualType EltTy = T;
- while (const ArrayType *AT = Context.getAsArrayType(EltTy))
- EltTy = AT->getElementType();
+ const Type* EltTy = T->getBaseElementTypeNoTypeQual();
if (const RecordType *RT = EltTy->getAsRecordType()) {
CXXRecordDecl* RDecl = cast<CXXRecordDecl>(RT->getDecl());
@@ -4419,10 +4417,7 @@ void Sema::DiagnoseNontrivial(const Reco
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();
-
+ const Type *EltTy = (*fi)->getType()->getBaseElementTypeNoTypeQual();
if (const RecordType *EltRT = EltTy->getAsRecordType()) {
CXXRecordDecl* EltRD = cast<CXXRecordDecl>(EltRT->getDecl());
Index: lib/AST/ExprCXX.cpp
===================================================================
--- lib/AST/ExprCXX.cpp (revision 76866)
+++ lib/AST/ExprCXX.cpp (working copy)
@@ -236,11 +236,78 @@ bool UnaryTypeTraitExpr::EvaluateTrait()
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 =
+ QueriedType->getBaseElementTypeNoTypeQual()->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).
+
+ // Arrays make this const check really annoying, especially since
+ // we don't have an ASTContext right now.
+ {
+ QualType QT = QueriedType;
+ while (true) {
+ if (QT.isConstQualified())
+ return false;
+
+ QT = QT->getDesugaredType();
+ if (QT.isConstQualified())
+ return false;
+
+ if (const ArrayType* AT = dyn_cast<ArrayType>(QT)) {
+ QT = AT->getElementType();
+ }else if (const ExtQualType* EQT = dyn_cast<ExtQualType>(QT)) {
+ QT = QualType(EQT->getBaseType(), 0);
+ }else {
+ break;
+ }
+ }
+ }
+
+ 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 =
+ QueriedType->getBaseElementTypeNoTypeQual()->getAsRecordType())
return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDestructor();
return false;
}
Index: lib/AST/Type.cpp
===================================================================
--- lib/AST/Type.cpp (revision 76866)
+++ lib/AST/Type.cpp (working copy)
@@ -92,6 +92,23 @@ const Type *Type::getArrayElementTypeNoT
return cast<ArrayType>(getDesugaredType())->getElementType().getTypePtr();
}
+/// getBaseElementTypeNoTypeQual - Recursively strip qualifiers and
+/// array types off this type. This method should never be used when
+/// type qualifiers are meaningful.
+const Type *Type::getBaseElementTypeNoTypeQual() const {
+ const Type* Ty = this;
+ while (true) {
+ const Type* DTy = Ty->getDesugaredType().getTypePtr();
+ if (const ArrayType* ATy = dyn_cast<ArrayType>(DTy)) {
+ Ty = ATy->getElementType().getTypePtr();
+ }else if (const ExtQualType* EQTy = dyn_cast<ExtQualType>(DTy)) {
+ Ty = EQTy->getBaseType();
+ }else {
+ return Ty; // the sugared type
+ }
+ }
+}
+
/// getDesugaredType - Return the specified type with any "sugar" removed from
/// the type. This takes off typedefs, typeof's etc. If the outer level of
/// the type is already concrete, it returns it unmodified. This is similar
Index: lib/AST/DeclCXX.cpp
===================================================================
--- lib/AST/DeclCXX.cpp (revision 76866)
+++ lib/AST/DeclCXX.cpp (working copy)
@@ -537,14 +537,11 @@ CXXDestructorDecl::computeBaseOrMembersT
// 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();
+ const Type *FieldType =
(*Field)->getType()->getBaseElementTypeNoTypeQual();
- 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);
@@ -634,15 +631,11 @@ CXXConstructorDecl::setBaseOrMemberIniti
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);
+
+ const Type* FT = (*Field)->getType()->getBaseElementTypeNoTypeQual();
+ if (const RecordType* RT = FT->getAsRecordType()) {
+ CXXConstructorDecl *Ctor =
+ cast<CXXRecordDecl>(RT->getDecl())->getDefaultConstructor(C);
// FIXME. Issue error if default ctor is missing.
CXXBaseOrMemberInitializer *Member =
new (C) CXXBaseOrMemberInitializer((*Field), 0, 0,
Index: lib/Parse/ParseExpr.cpp
===================================================================
--- lib/Parse/ParseExpr.cpp (revision 76866)
+++ lib/Parse/ParseExpr.cpp (working copy)
@@ -815,6 +815,8 @@ Parser::OwningExprResult Parser::ParseCa
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();
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits