From: Anders Carlsson Date: Thu, 16 Apr 2009 00:08:20 +0000 (+0000) Subject: Add support for the __has_trivial_constructor type trait. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=347ba89dec89091868982434154c3508085b727a;p=clang Add support for the __has_trivial_constructor type trait. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69245 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index c82e5cf0e5..328ec8701e 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -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. /// diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index ffc35fe1f7..78ed3fcf4d 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -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)) diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index c2fcc5f9ee..3634c20356 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -170,6 +170,10 @@ bool UnaryTypeTraitExpr::EvaluateTrait() const { if (const RecordType *RT = QueriedType->getAsRecordType()) return cast(RT->getDecl())->isAbstract(); return false; + case UTT_HasTrivialConstructor: + if (const RecordType *RT = QueriedType->getAsRecordType()) + return cast(RT->getDecl())->hasTrivialConstructor(); + return false; } } diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 20a8359d1d..d41586ca91 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -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: { diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 6233871c9e..6c4580df28 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2049,6 +2049,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, CurClass->setAggregate(false); CurClass->setPOD(false); CurClass->setPolymorphic(true); + CurClass->setHasTrivialConstructor(false); } } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index cc70dc4a5c..ec1ed4668a 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -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(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(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 index 0000000000..0c4231ef19 --- /dev/null +++ b/test/SemaCXX/trivial-constructor.cpp @@ -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!");