]> granicus.if.org Git - clang/commitdiff
Fix nothrow trait with multiple default constructors
authorAlp Toker <alp@nuanti.com>
Mon, 20 Jan 2014 00:23:47 +0000 (00:23 +0000)
committerAlp Toker <alp@nuanti.com>
Mon, 20 Jan 2014 00:23:47 +0000 (00:23 +0000)
Check all default ctors, not just the first one we see. This brings
__has_nothrow_constructor() in line with the other unary type traits.

A C++ class can have multiple default constructors but clang was only checking
the first one written, presumably due to ambiguity in the GNU specification.

MSVC has the same bug, while g++ has the correct implementation which we now
match.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@199618 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaExprCXX.cpp
test/SemaCXX/type-traits.cpp

index 5b4538d3f76dc8a217df0eeadbae7bf4c0f534d8..f9a3acc93f4071f9d2e72ff2447f729245e80a14 100644 (file)
@@ -3516,7 +3516,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
     }
     return false;
   case UTT_HasNothrowConstructor:
-    // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
+    // 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
@@ -3528,6 +3528,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
           !RD->hasNonTrivialDefaultConstructor())
         return true;
 
+      bool FoundConstructor = false;
       DeclContext::lookup_const_result R = Self.LookupConstructors(RD);
       for (DeclContext::lookup_const_iterator Con = R.begin(),
            ConEnd = R.end(); Con != ConEnd; ++Con) {
@@ -3536,16 +3537,19 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
           continue;
         CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con);
         if (Constructor->isDefaultConstructor()) {
+          FoundConstructor = true;
           const FunctionProtoType *CPT
               = Constructor->getType()->getAs<FunctionProtoType>();
           CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
           if (!CPT)
             return false;
-          // TODO: check whether evaluating default arguments can throw.
+          // FIXME: check whether evaluating default arguments can throw.
           // For now, we'll be conservative and assume that they can throw.
-          return CPT->isNothrow(Self.Context) && CPT->getNumArgs() == 0;
+          if (!CPT->isNothrow(Self.Context) || CPT->getNumArgs() > 0)
+            return false;
         }
       }
+      return FoundConstructor;
     }
     return false;
   case UTT_HasVirtualDestructor:
index 3e479215838e4dcbf5e2e2dcf5fdd1c41577a0ae..5b91201f8853852c0d43f599beb4d0aab5146d67 100644 (file)
@@ -112,6 +112,14 @@ struct HasNoThrowConstructor { HasNoThrowConstructor() throw(); };
 struct HasNoThrowConstructorWithArgs {
   HasNoThrowConstructorWithArgs(HasCons i = HasCons(0)) throw();
 };
+struct HasMultipleDefaultConstructor1 {
+  HasMultipleDefaultConstructor1() throw();
+  HasMultipleDefaultConstructor1(int i = 0);
+};
+struct HasMultipleDefaultConstructor2 {
+  HasMultipleDefaultConstructor2(int i = 0);
+  HasMultipleDefaultConstructor2() throw();
+};
 
 struct HasNoThrowCopy { HasNoThrowCopy(const HasNoThrowCopy&) throw(); };
 struct HasMultipleCopy {
@@ -1562,6 +1570,9 @@ void has_nothrow_constructor() {
   { int arr[F(__has_nothrow_constructor(void))]; }
   { int arr[F(__has_nothrow_constructor(cvoid))]; }
   { int arr[F(__has_nothrow_constructor(HasTemplateCons))]; }
+
+  { int arr[F(__has_nothrow_constructor(HasMultipleDefaultConstructor1))]; }
+  { int arr[F(__has_nothrow_constructor(HasMultipleDefaultConstructor2))]; }
 }
 
 void has_virtual_destructor() {