aboutsummaryrefslogtreecommitdiff
path: root/lib/AST/ExprCXX.cpp
diff options
context:
space:
mode:
authorSebastian Redl <sebastian.redl@getdesigned.at>2010-08-31 04:59:00 +0000
committerSebastian Redl <sebastian.redl@getdesigned.at>2010-08-31 04:59:00 +0000
commitc238f09a268cd87a2568f6c97181252687ae07b1 (patch)
treeead292453cc86febca5c01157af9cdbe86f25d18 /lib/AST/ExprCXX.cpp
parent017ca15cb3d7032e3779e6abb7b51bfe73ab4dda (diff)
Implement the __has_nothrow trait family, by Steven Watanabe.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@112577 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/AST/ExprCXX.cpp')
-rw-r--r--lib/AST/ExprCXX.cpp102
1 files changed, 102 insertions, 0 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;
}
}