]> granicus.if.org Git - clang/commitdiff
Implement the __has_nothrow trait family, by Steven Watanabe.
authorSebastian Redl <sebastian.redl@getdesigned.at>
Tue, 31 Aug 2010 04:59:00 +0000 (04:59 +0000)
committerSebastian Redl <sebastian.redl@getdesigned.at>
Tue, 31 Aug 2010 04:59:00 +0000 (04:59 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@112577 91177308-0d34-0410-b5e6-96231b3b80d8

lib/AST/ExprCXX.cpp
lib/Parse/ParseExpr.cpp
test/SemaCXX/type-traits.cpp

index 9161c1c0807a9142bc001fe74be9ebff1e6c4e36..669cac014c91fc7db5b406b7478d208db8325f44 100644 (file)
@@ -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;
   }
 }
 
index 290b72c4c0da78f454ea156b39585db9506ce69b..f1abd59421e4931cccd8fb873561e69f3dd30cb7 100644 (file)
@@ -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: {
index 85bd59612688440ffecd12d5b59c9be93b20157d..b561206143e001aca810a6cb518e995ad96c7a76 100644 (file)
@@ -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))];
+}