]> granicus.if.org Git - clang/commitdiff
When we are performing copy initialization of a class type via its
authorDouglas Gregor <dgregor@apple.com>
Sat, 24 Apr 2010 20:54:38 +0000 (20:54 +0000)
committerDouglas Gregor <dgregor@apple.com>
Sat, 24 Apr 2010 20:54:38 +0000 (20:54 +0000)
copy constructor, suppress user-defined conversions on the
argument. Otherwise, we can end up in a recursion loop where the
bind the argument of the copy constructor to another copy constructor call,
whose argument is then a copy constructor call...

Found by Boost.Regex which, alas, still isn't building.

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

lib/Sema/SemaInit.cpp
test/SemaCXX/conditional-expr.cpp
test/SemaCXX/conversion-function.cpp
test/SemaCXX/overload-call.cpp

index 5c55b56c7d39fed1d9c5aef5f0f95035b4aa681b..d552b163994c520a579ba610fa04b98463d42cbf 100644 (file)
@@ -2636,25 +2636,36 @@ static void TryConstructorInitialization(Sema &S,
        Con != ConEnd; ++Con) {
     NamedDecl *D = *Con;
     DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
-
+    bool SuppressUserConversions = false;
+    
     // Find the constructor (which may be a template).
     CXXConstructorDecl *Constructor = 0;
     FunctionTemplateDecl *ConstructorTmpl = dyn_cast<FunctionTemplateDecl>(D);
     if (ConstructorTmpl)
       Constructor = cast<CXXConstructorDecl>(
                                            ConstructorTmpl->getTemplatedDecl());
-    else
+    else {
       Constructor = cast<CXXConstructorDecl>(D);
+
+      // If we're performing copy initialization using a copy constructor, we 
+      // suppress user-defined conversions on the arguments.
+      // FIXME: Move constructors?
+      if (Kind.getKind() == InitializationKind::IK_Copy &&
+          Constructor->isCopyConstructor())
+        SuppressUserConversions = true;
+    }
     
     if (!Constructor->isInvalidDecl() &&
         (AllowExplicit || !Constructor->isExplicit())) {
       if (ConstructorTmpl)
         S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
                                        /*ExplicitArgs*/ 0,
-                                       Args, NumArgs, CandidateSet);
+                                       Args, NumArgs, CandidateSet,
+                                       SuppressUserConversions);
       else
         S.AddOverloadCandidate(Constructor, FoundDecl,
-                               Args, NumArgs, CandidateSet);
+                               Args, NumArgs, CandidateSet,
+                               SuppressUserConversions);
     }
   }    
     
@@ -2803,7 +2814,8 @@ static void TryUserDefinedConversion(Sema &S,
          Con != ConEnd; ++Con) {
       NamedDecl *D = *Con;
       DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
-
+      bool SuppressUserConversions = false;
+      
       // Find the constructor (which may be a template).
       CXXConstructorDecl *Constructor = 0;
       FunctionTemplateDecl *ConstructorTmpl
@@ -2811,18 +2823,29 @@ static void TryUserDefinedConversion(Sema &S,
       if (ConstructorTmpl)
         Constructor = cast<CXXConstructorDecl>(
                                            ConstructorTmpl->getTemplatedDecl());
-      else
+      else {
         Constructor = cast<CXXConstructorDecl>(D);
+        
+        // If we're performing copy initialization using a copy constructor, we 
+        // suppress user-defined conversions on the arguments.
+        // FIXME: Move constructors?
+        if (Kind.getKind() == InitializationKind::IK_Copy &&
+            Constructor->isCopyConstructor())
+          SuppressUserConversions = true;
+        
+      }
       
       if (!Constructor->isInvalidDecl() &&
           Constructor->isConvertingConstructor(AllowExplicit)) {
         if (ConstructorTmpl)
           S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
                                          /*ExplicitArgs*/ 0,
-                                         &Initializer, 1, CandidateSet);
+                                         &Initializer, 1, CandidateSet,
+                                         SuppressUserConversions);
         else
           S.AddOverloadCandidate(Constructor, FoundDecl,
-                                 &Initializer, 1, CandidateSet);
+                                 &Initializer, 1, CandidateSet,
+                                 SuppressUserConversions);
       }
     }    
   }
index aa413232391951375cba79ab8094d28b61ffc59a..a812a5920d65a50424ba0ebfe78fb7e760cdb241 100644 (file)
@@ -7,8 +7,7 @@
 struct ToBool { explicit operator bool(); };
 
 struct B;
-struct A { A(); A(const B&); }; // expected-note 2 {{candidate constructor}} \
-               // expected-note 2 {{candidate is the implicit copy constructor}}
+struct A { A(); A(const B&); }; // expected-note 2 {{candidate constructor}}
 struct B { operator A() const; }; // expected-note 2 {{candidate function}}
 struct I { operator int(); };
 struct J { operator I(); };
index dfc065064190a66946336eb956c3e97e2b293100..3e96d02495fe84e41564a3d76907cf8b292185b6 100644 (file)
@@ -56,7 +56,7 @@ public:
 
 // This used to crash Clang.
 struct Flip;
-struct Flop { // expected-note{{candidate is the implicit copy constructor}}
+struct Flop {
   Flop();
   Flop(const Flip&); // expected-note{{candidate constructor}}
 };
@@ -202,3 +202,16 @@ namespace smart_ptr {
     return X(Y());
   }
 }
+
+struct Any {
+  Any(...);
+};
+
+struct Other {
+  Other(const Other &); 
+  Other();
+};
+
+void test_any() {
+  Any any = Other(); // expected-error{{cannot pass object of non-POD type 'Other' through variadic constructor; call will abort at runtime}}
+}
index feec9df6b7a566d4e7f8a84ffe2457484936738e..79c74cec4947e71159c155a08759de71d1e41407 100644 (file)
@@ -408,7 +408,7 @@ namespace PR6483 {
 }
 
 namespace PR6078 {
-  struct A { // expected-note{{candidate is the implicit copy constructor}}
+  struct A {
     A(short); // expected-note{{candidate constructor}}
     A(long); // expected-note{{candidate constructor}}
   };