diff options
-rw-r--r-- | lib/AST/ExprCXX.cpp | 102 | ||||
-rw-r--r-- | lib/Parse/ParseExpr.cpp | 9 | ||||
-rw-r--r-- | test/SemaCXX/type-traits.cpp | 101 |
3 files changed, 209 insertions, 3 deletions
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 9161c1c080..669cac014c 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -386,6 +386,108 @@ bool UnaryTypeTraitExpr::EvaluateTrait(ASTContext& C) const { C.getBaseElementType(QueriedType)->getAs<RecordType>()) return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDestructor(); return false; + // TODO: Propagate nothrowness for implicitly declared special members. + case UTT_HasNothrowAssign: + // 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 __has_trivial_assign (type) + // is true then the trait is true, else if type is a cv class + // or union type with copy assignment operators that are known + // not to throw an exception then the trait is true, else it is + // false. + if (C.getBaseElementType(QueriedType).isConstQualified()) + return false; + if (QueriedType->isReferenceType()) + return false; + if (QueriedType->isPODType()) + return true; + if (const RecordType *RT = QueriedType->getAs<RecordType>()) { + CXXRecordDecl* RD = cast<CXXRecordDecl>(RT->getDecl()); + if (RD->hasTrivialCopyAssignment()) + return true; + + bool FoundAssign = false; + bool AllNoThrow = true; + DeclarationName Name = C.DeclarationNames.getCXXOperatorName(OO_Equal); + DeclContext::lookup_const_iterator Op, OpEnd; + for (llvm::tie(Op, OpEnd) = RD->lookup(Name); + Op != OpEnd; ++Op) { + CXXMethodDecl *Operator = cast<CXXMethodDecl>(*Op); + if (Operator->isCopyAssignmentOperator()) { + FoundAssign = true; + const FunctionProtoType *CPT + = Operator->getType()->getAs<FunctionProtoType>(); + if (!CPT->hasEmptyExceptionSpec()) { + AllNoThrow = false; + break; + } + } + } + + return FoundAssign && AllNoThrow; + } + return false; + case UTT_HasNothrowCopy: + // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: + // If __has_trivial_copy (type) is true then the trait is true, else + // if type is a cv class or union type with copy constructors that are + // known not to throw an exception then the trait is true, else it is + // false. + if (QueriedType->isPODType() || QueriedType->isReferenceType()) + return true; + if (const RecordType *RT = QueriedType->getAs<RecordType>()) { + CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + if (RD->hasTrivialCopyConstructor()) + return true; + + bool FoundConstructor = false; + bool AllNoThrow = true; + unsigned FoundTQs; + DeclarationName ConstructorName + = C.DeclarationNames.getCXXConstructorName( + C.getCanonicalType(QueriedType)); + DeclContext::lookup_const_iterator Con, ConEnd; + for (llvm::tie(Con, ConEnd) = RD->lookup(ConstructorName); + Con != ConEnd; ++Con) { + CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con); + if (Constructor->isCopyConstructor(FoundTQs)) { + FoundConstructor = true; + const FunctionProtoType *CPT + = Constructor->getType()->getAs<FunctionProtoType>(); + if (!CPT->hasEmptyExceptionSpec()) { + AllNoThrow = false; + break; + } + } + } + + return FoundConstructor && AllNoThrow; + } + return false; + case UTT_HasNothrowConstructor: + // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: + // If __has_trivial_constructor (type) is true then the trait is + // true, else if type is a cv class or union type (or array + // thereof) with a default constructor that is known not to + // throw an exception then the trait is true, else it is false. + if (QueriedType->isPODType()) + return true; + if (const RecordType *RT = + C.getBaseElementType(QueriedType)->getAs<RecordType>()) { + CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + if (RD->hasTrivialConstructor()) + return true; + + if (CXXConstructorDecl *Constructor = RD->getDefaultConstructor()) { + const FunctionProtoType *CPT + = Constructor->getType()->getAs<FunctionProtoType>(); + // TODO: check whether evaluating default arguments can throw. + // For now, we'll be conservative and assume that they can throw. + if (CPT->hasEmptyExceptionSpec() && CPT->getNumArgs() == 0) + return true; + } + } + return false; } } diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 290b72c4c0..f1abd59421 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -526,9 +526,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, /// '::'[opt] 'delete' '[' ']' cast-expression /// /// [GNU] unary-type-trait: -/// '__has_nothrow_assign' [TODO] -/// '__has_nothrow_copy' [TODO] -/// '__has_nothrow_constructor' [TODO] +/// '__has_nothrow_assign' +/// '__has_nothrow_copy' +/// '__has_nothrow_constructor' /// '__has_trivial_assign' [TODO] /// '__has_trivial_copy' [TODO] /// '__has_trivial_constructor' @@ -900,6 +900,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw___has_trivial_copy: case tok::kw___has_trivial_assign: case tok::kw___has_trivial_destructor: + case tok::kw___has_nothrow_assign: + case tok::kw___has_nothrow_copy: + case tok::kw___has_nothrow_constructor: return ParseUnaryTypeTrait(); case tok::at: { diff --git a/test/SemaCXX/type-traits.cpp b/test/SemaCXX/type-traits.cpp index 85bd596126..b561206143 100644 --- a/test/SemaCXX/type-traits.cpp +++ b/test/SemaCXX/type-traits.cpp @@ -34,6 +34,33 @@ typedef Derives NonPODAr[10]; typedef HasVirt VirtAr[10]; union NonPODUnion { int i; Derives n; }; +struct HasNoThrowCopyAssign { + void operator =(const HasNoThrowCopyAssign&) throw(); +}; +struct HasMultipleCopyAssign { + void operator =(const HasMultipleCopyAssign&) throw(); + void operator =(volatile HasMultipleCopyAssign&); +}; +struct HasMultipleNoThrowCopyAssign { + void operator =(const HasMultipleNoThrowCopyAssign&) throw(); + void operator =(volatile HasMultipleNoThrowCopyAssign&) throw(); +}; + +struct HasNoThrowConstructor { HasNoThrowConstructor() throw(); }; +struct HasNoThrowConstructorWithArgs { + HasNoThrowConstructorWithArgs(HasCons i = HasCons(0)) throw(); +}; + +struct HasNoThrowCopy { HasNoThrowCopy(const HasNoThrowCopy&) throw(); }; +struct HasMultipleCopy { + HasMultipleCopy(const HasMultipleCopy&) throw(); + HasMultipleCopy(volatile HasMultipleCopy&); +}; +struct HasMultipleNoThrowCopy { + HasMultipleNoThrowCopy(const HasMultipleNoThrowCopy&) throw(); + HasMultipleNoThrowCopy(volatile HasMultipleNoThrowCopy&) throw(); +}; + void is_pod() { int t01[T(__is_pod(int))]; @@ -258,3 +285,77 @@ void f() { int t01[T(!__has_trivial_destructor(A))]; int t02[T(!__has_trivial_destructor(B<int>))]; } + +void has_nothrow_assign() { + int t01[T(__has_nothrow_assign(Int))]; + int t02[T(__has_nothrow_assign(IntAr))]; + int t03[T(__has_nothrow_assign(Union))]; + int t04[T(__has_nothrow_assign(UnionAr))]; + int t05[T(__has_nothrow_assign(POD))]; + int t06[T(__has_nothrow_assign(Derives))]; + int t07[F(__has_nothrow_assign(ConstIntAr))]; + int t08[F(__has_nothrow_assign(ConstIntArAr))]; + int t09[T(__has_nothrow_assign(HasDest))]; + int t10[T(__has_nothrow_assign(HasPriv))]; + int t11[T(__has_nothrow_assign(HasCons))]; + int t12[T(__has_nothrow_assign(HasRef))]; + int t13[T(__has_nothrow_assign(HasCopy))]; + int t14[F(__has_nothrow_assign(IntRef))]; + int t15[F(__has_nothrow_assign(HasCopyAssign))]; + int t16[F(__has_nothrow_assign(const Int))]; + int t17[F(__has_nothrow_assign(NonPODAr))]; + int t18[F(__has_nothrow_assign(VirtAr))]; + + int t19[T(__has_nothrow_assign(HasNoThrowCopyAssign))]; + int t20[F(__has_nothrow_assign(HasMultipleCopyAssign))]; + int t21[T(__has_nothrow_assign(HasMultipleNoThrowCopyAssign))]; +} + +void has_nothrow_copy() { + int t01[T(__has_nothrow_copy(Int))]; + int t02[T(__has_nothrow_copy(IntAr))]; + int t03[T(__has_nothrow_copy(Union))]; + int t04[T(__has_nothrow_copy(UnionAr))]; + int t05[T(__has_nothrow_copy(POD))]; + int t06[T(__has_nothrow_copy(Derives))]; + int t07[T(__has_nothrow_copy(ConstIntAr))]; + int t08[T(__has_nothrow_copy(ConstIntArAr))]; + int t09[T(__has_nothrow_copy(HasDest))]; + int t10[T(__has_nothrow_copy(HasPriv))]; + int t11[T(__has_nothrow_copy(HasCons))]; + int t12[T(__has_nothrow_copy(HasRef))]; + int t13[F(__has_nothrow_copy(HasCopy))]; + int t14[T(__has_nothrow_copy(IntRef))]; + int t15[T(__has_nothrow_copy(HasCopyAssign))]; + int t16[T(__has_nothrow_copy(const Int))]; + int t17[F(__has_nothrow_copy(NonPODAr))]; + int t18[F(__has_nothrow_copy(VirtAr))]; + + int t19[T(__has_nothrow_copy(HasNoThrowCopy))]; + int t20[F(__has_nothrow_copy(HasMultipleCopy))]; + int t21[T(__has_nothrow_copy(HasMultipleNoThrowCopy))]; +} + +void has_nothrow_constructor() { + int t01[T(__has_nothrow_constructor(Int))]; + int t02[T(__has_nothrow_constructor(IntAr))]; + int t03[T(__has_nothrow_constructor(Union))]; + int t04[T(__has_nothrow_constructor(UnionAr))]; + int t05[T(__has_nothrow_constructor(POD))]; + int t06[T(__has_nothrow_constructor(Derives))]; + int t07[T(__has_nothrow_constructor(ConstIntAr))]; + int t08[T(__has_nothrow_constructor(ConstIntArAr))]; + int t09[T(__has_nothrow_constructor(HasDest))]; + int t10[T(__has_nothrow_constructor(HasPriv))]; + int t11[F(__has_nothrow_constructor(HasCons))]; + int t12[F(__has_nothrow_constructor(HasRef))]; + int t13[F(__has_nothrow_constructor(HasCopy))]; + int t14[F(__has_nothrow_constructor(IntRef))]; + int t15[T(__has_nothrow_constructor(HasCopyAssign))]; + int t16[T(__has_nothrow_constructor(const Int))]; + int t17[T(__has_nothrow_constructor(NonPODAr))]; + // int t18[T(__has_nothrow_constructor(VirtAr))]; // not implemented + + int t19[T(__has_nothrow_constructor(HasNoThrowConstructor))]; + int t20[F(__has_nothrow_constructor(HasNoThrowConstructorWithArgs))]; +} |