<html><head><meta http-equiv="Content-Type" content="text/html charset=iso-8859-1"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><br><div><div>On Apr 20, 2012, at 1:20 PM, Richard Smith <<a href="mailto:richard@metafoo.co.uk">richard@metafoo.co.uk</a>> wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite">Without this, std::pair<std::unique_ptr<int>, int> fails to instantiate when using libstdc++4.7. Integrate to branch requested.<br></blockquote><div><br></div>Approved.</div><div><br></div><div><br><blockquote type="cite"><div class="gmail_quote">On Fri, Apr 20, 2012 at 11:46 AM, Richard Smith <span dir="ltr"><<a href="mailto:richard-llvm@metafoo.co.uk">richard-llvm@metafoo.co.uk</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: rsmith<br>
Date: Fri Apr 20 13:46:14 2012<br>
New Revision: 155218<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=155218&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=155218&view=rev</a><br>
Log:<br>
Fix bug where a class's (deleted) copy constructor would be implicitly given a<br>
non-const reference parameter type if the class had any subobjects with deleted<br>
copy constructors. This causes a rejects-valid if the class's copy constructor<br>
is explicitly defaulted (as happens for some implementations of std::pair etc).<br>
<br>
Added:<br>
    cfe/trunk/test/CXX/special/class.copy/p8-cxx11.cpp<br>
Modified:<br>
    cfe/trunk/include/clang/Sema/Sema.h<br>
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp<br>
    cfe/trunk/lib/Sema/SemaLookup.cpp<br>
    cfe/trunk/test/CXX/special/class.copy/implicit-move.cpp<br>
<br>
Modified: cfe/trunk/include/clang/Sema/Sema.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=155218&r1=155217&r2=155218&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=155218&r1=155217&r2=155218&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/include/clang/Sema/Sema.h (original)<br>
+++ cfe/trunk/include/clang/Sema/Sema.h Fri Apr 20 13:46:14 2012<br>
@@ -665,23 +665,19 @@<br>
   /// SpecialMemberOverloadResult - The overloading result for a special member<br>
   /// function.<br>
   ///<br>
-  /// This is basically a wrapper around PointerIntPair. The lowest bit of the<br>
-  /// integer is used to determine whether we have a parameter qualification<br>
-  /// match, the second-lowest is whether we had success in resolving the<br>
-  /// overload to a unique non-deleted function.<br>
-  ///<br>
-  /// The ConstParamMatch bit represents whether, when looking up a copy<br>
-  /// constructor or assignment operator, we found a potential copy<br>
-  /// constructor/assignment operator whose first parameter is const-qualified.<br>
-  /// This is used for determining parameter types of other objects and is<br>
-  /// utterly meaningless on other types of special members.<br>
+  /// This is basically a wrapper around PointerIntPair. The lowest bits of the<br>
+  /// integer are used to determine whether overload resolution succeeded, and<br>
+  /// whether, when looking up a copy constructor or assignment operator, we<br>
+  /// found a potential copy constructor/assignment operator whose first<br>
+  /// parameter is const-qualified. This is used for determining parameter types<br>
+  /// of other objects and is utterly meaningless on other types of special<br>
+  /// members.<br>
   class SpecialMemberOverloadResult : public llvm::FastFoldingSetNode {<br>
   public:<br>
     enum Kind {<br>
       NoMemberOrDeleted,<br>
       Ambiguous,<br>
-      SuccessNonConst,<br>
-      SuccessConst<br>
+      Success<br>
     };<br>
<br>
   private:<br>
@@ -697,9 +693,6 @@<br>
<br>
     Kind getKind() const { return static_cast<Kind>(Pair.getInt()); }<br>
     void setKind(Kind K) { Pair.setInt(K); }<br>
-<br>
-    bool hasSuccess() const { return getKind() >= SuccessNonConst; }<br>
-    bool hasConstParamMatch() const { return getKind() == SuccessConst; }<br>
   };<br>
<br>
   /// \brief A cache of special member function overload resolution results<br>
@@ -1921,11 +1914,9 @@<br>
   DeclContextLookupResult LookupConstructors(CXXRecordDecl *Class);<br>
   CXXConstructorDecl *LookupDefaultConstructor(CXXRecordDecl *Class);<br>
   CXXConstructorDecl *LookupCopyingConstructor(CXXRecordDecl *Class,<br>
-                                               unsigned Quals,<br>
-                                               bool *ConstParam = 0);<br>
+                                               unsigned Quals);<br>
   CXXMethodDecl *LookupCopyingAssignment(CXXRecordDecl *Class, unsigned Quals,<br>
-                                         bool RValueThis, unsigned ThisQuals,<br>
-                                         bool *ConstParam = 0);<br>
+                                         bool RValueThis, unsigned ThisQuals);<br>
   CXXConstructorDecl *LookupMovingConstructor(CXXRecordDecl *Class);<br>
   CXXMethodDecl *LookupMovingAssignment(CXXRecordDecl *Class, bool RValueThis,<br>
                                         unsigned ThisQuals);<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=155218&r1=155217&r2=155218&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=155218&r1=155217&r2=155218&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Fri Apr 20 13:46:14 2012<br>
@@ -7577,8 +7577,9 @@<br>
     assert(!Base->getType()->isDependentType() &&<br>
            "Cannot generate implicit members for class with dependent bases.");<br>
     CXXRecordDecl *BaseClassDecl = Base->getType()->getAsCXXRecordDecl();<br>
-    LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const, false, 0,<br>
-                            &HasConstCopyAssignment);<br>
+    HasConstCopyAssignment &=<br>
+      (bool)LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const,<br>
+                                    false, 0);<br>
   }<br>
<br>
   // In C++11, the above citation has "or virtual" added<br>
@@ -7589,8 +7590,9 @@<br>
       assert(!Base->getType()->isDependentType() &&<br>
              "Cannot generate implicit members for class with dependent bases.");<br>
       CXXRecordDecl *BaseClassDecl = Base->getType()->getAsCXXRecordDecl();<br>
-      LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const, false, 0,<br>
-                              &HasConstCopyAssignment);<br>
+      HasConstCopyAssignment &=<br>
+        (bool)LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const,<br>
+                                      false, 0);<br>
     }<br>
   }<br>
<br>
@@ -7604,8 +7606,9 @@<br>
        ++Field) {<br>
     QualType FieldType = Context.getBaseElementType((*Field)->getType());<br>
     if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {<br>
-      LookupCopyingAssignment(FieldClassDecl, Qualifiers::Const, false, 0,<br>
-                              &HasConstCopyAssignment);<br>
+      HasConstCopyAssignment &=<br>
+        (bool)LookupCopyingAssignment(FieldClassDecl, Qualifiers::Const,<br>
+                                      false, 0);<br>
     }<br>
   }<br>
<br>
@@ -8608,8 +8611,8 @@<br>
<br>
     CXXRecordDecl *BaseClassDecl<br>
       = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());<br>
-    LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const,<br>
-                             &HasConstCopyConstructor);<br>
+    HasConstCopyConstructor &=<br>
+      (bool)LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const);<br>
   }<br>
<br>
   for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),<br>
@@ -8618,8 +8621,8 @@<br>
        ++Base) {<br>
     CXXRecordDecl *BaseClassDecl<br>
       = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());<br>
-    LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const,<br>
-                             &HasConstCopyConstructor);<br>
+    HasConstCopyConstructor &=<br>
+      (bool)LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const);<br>
   }<br>
<br>
   //     -- for all the nonstatic data members of X that are of a<br>
@@ -8632,8 +8635,8 @@<br>
        ++Field) {<br>
     QualType FieldType = Context.getBaseElementType((*Field)->getType());<br>
     if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {<br>
-      LookupCopyingConstructor(FieldClassDecl, Qualifiers::Const,<br>
-                               &HasConstCopyConstructor);<br>
+      HasConstCopyConstructor &=<br>
+        (bool)LookupCopyingConstructor(FieldClassDecl, Qualifiers::Const);<br>
     }<br>
   }<br>
   //   Otherwise, the implicitly declared copy constructor will have<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaLookup.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=155218&r1=155217&r2=155218&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=155218&r1=155217&r2=155218&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Fri Apr 20 13:46:14 2012<br>
@@ -2277,7 +2277,7 @@<br>
     Result->setMethod(DD);<br>
     Result->setKind(DD->isDeleted() ?<br>
                     SpecialMemberOverloadResult::NoMemberOrDeleted :<br>
-                    SpecialMemberOverloadResult::SuccessNonConst);<br>
+                    SpecialMemberOverloadResult::Success);<br>
     return Result;<br>
   }<br>
<br>
@@ -2288,6 +2288,9 @@<br>
   Expr *Arg = 0;<br>
   unsigned NumArgs;<br>
<br>
+  QualType ArgType = CanTy;<br>
+  ExprValueKind VK = VK_LValue;<br>
+<br>
   if (SM == CXXDefaultConstructor) {<br>
     Name = Context.DeclarationNames.getCXXConstructorName(CanTy);<br>
     NumArgs = 0;<br>
@@ -2308,7 +2311,6 @@<br>
         DeclareImplicitMoveAssignment(RD);<br>
     }<br>
<br>
-    QualType ArgType = CanTy;<br>
     if (ConstArg)<br>
       ArgType.addConst();<br>
     if (VolatileArg)<br>
@@ -2321,14 +2323,17 @@<br>
     // Possibly an XValue is actually correct in the case of move, but<br>
     // there is no semantic difference for class types in this restricted<br>
     // case.<br>
-    ExprValueKind VK;<br>
     if (SM == CXXCopyConstructor || SM == CXXCopyAssignment)<br>
       VK = VK_LValue;<br>
     else<br>
       VK = VK_RValue;<br>
+  }<br>
<br>
+  OpaqueValueExpr FakeArg(SourceLocation(), ArgType, VK);<br>
+<br>
+  if (SM != CXXDefaultConstructor) {<br>
     NumArgs = 1;<br>
-    Arg = new (Context) OpaqueValueExpr(SourceLocation(), ArgType, VK);<br>
+    Arg = &FakeArg;<br>
   }<br>
<br>
   // Create the object argument<br>
@@ -2338,17 +2343,14 @@<br>
   if (VolatileThis)<br>
     ThisTy.addVolatile();<br>
   Expr::Classification Classification =<br>
-    (new (Context) OpaqueValueExpr(SourceLocation(), ThisTy,<br>
-                                   RValueThis ? VK_RValue : VK_LValue))-><br>
-        Classify(Context);<br>
+    OpaqueValueExpr(SourceLocation(), ThisTy,<br>
+                    RValueThis ? VK_RValue : VK_LValue).Classify(Context);<br>
<br>
   // Now we perform lookup on the name we computed earlier and do overload<br>
   // resolution. Lookup is only performed directly into the class since there<br>
   // will always be a (possibly implicit) declaration to shadow any others.<br>
   OverloadCandidateSet OCS((SourceLocation()));<br>
   DeclContext::lookup_iterator I, E;<br>
-  SpecialMemberOverloadResult::Kind SuccessKind =<br>
-      SpecialMemberOverloadResult::SuccessNonConst;<br>
<br>
   llvm::tie(I, E) = RD->lookup(Name);<br>
   assert((I != E) &&<br>
@@ -2378,17 +2380,6 @@<br>
       else<br>
         AddOverloadCandidate(M, DeclAccessPair::make(M, AS_public),<br>
                              llvm::makeArrayRef(&Arg, NumArgs), OCS, true);<br>
-<br>
-      // Here we're looking for a const parameter to speed up creation of<br>
-      // implicit copy methods.<br>
-      if ((SM == CXXCopyAssignment && M->isCopyAssignmentOperator()) ||<br>
-          (SM == CXXCopyConstructor &&<br>
-            cast<CXXConstructorDecl>(M)->isCopyConstructor())) {<br>
-        QualType ArgType = M->getType()->getAs<FunctionProtoType>()->getArgType(0);<br>
-        if (!ArgType->isReferenceType() ||<br>
-            ArgType->getPointeeType().isConstQualified())<br>
-          SuccessKind = SpecialMemberOverloadResult::SuccessConst;<br>
-      }<br>
     } else if (FunctionTemplateDecl *Tmpl =<br>
                  dyn_cast<FunctionTemplateDecl>(Cand)) {<br>
       if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)<br>
@@ -2409,7 +2400,7 @@<br>
   switch (OCS.BestViableFunction(*this, SourceLocation(), Best)) {<br>
     case OR_Success:<br>
       Result->setMethod(cast<CXXMethodDecl>(Best->Function));<br>
-      Result->setKind(SuccessKind);<br>
+      Result->setKind(SpecialMemberOverloadResult::Success);<br>
       break;<br>
<br>
     case OR_Deleted:<br>
@@ -2442,17 +2433,13 @@<br>
<br>
 /// \brief Look up the copying constructor for the given class.<br>
 CXXConstructorDecl *Sema::LookupCopyingConstructor(CXXRecordDecl *Class,<br>
-                                                   unsigned Quals,<br>
-                                                   bool *ConstParamMatch) {<br>
+                                                   unsigned Quals) {<br>
   assert(!(Quals & ~(Qualifiers::Const | Qualifiers::Volatile)) &&<br>
          "non-const, non-volatile qualifiers for copy ctor arg");<br>
   SpecialMemberOverloadResult *Result =<br>
     LookupSpecialMember(Class, CXXCopyConstructor, Quals & Qualifiers::Const,<br>
                         Quals & Qualifiers::Volatile, false, false, false);<br>
<br>
-  if (ConstParamMatch)<br>
-    *ConstParamMatch = Result->hasConstParamMatch();<br>
-<br>
   return cast_or_null<CXXConstructorDecl>(Result->getMethod());<br>
 }<br>
<br>
@@ -2485,8 +2472,7 @@<br>
 /// \brief Look up the copying assignment operator for the given class.<br>
 CXXMethodDecl *Sema::LookupCopyingAssignment(CXXRecordDecl *Class,<br>
                                              unsigned Quals, bool RValueThis,<br>
-                                             unsigned ThisQuals,<br>
-                                             bool *ConstParamMatch) {<br>
+                                             unsigned ThisQuals) {<br>
   assert(!(Quals & ~(Qualifiers::Const | Qualifiers::Volatile)) &&<br>
          "non-const, non-volatile qualifiers for copy assignment arg");<br>
   assert(!(ThisQuals & ~(Qualifiers::Const | Qualifiers::Volatile)) &&<br>
@@ -2497,9 +2483,6 @@<br>
                         ThisQuals & Qualifiers::Const,<br>
                         ThisQuals & Qualifiers::Volatile);<br>
<br>
-  if (ConstParamMatch)<br>
-    *ConstParamMatch = Result->hasConstParamMatch();<br>
-<br>
   return Result->getMethod();<br>
 }<br>
<br>
<br>
Modified: cfe/trunk/test/CXX/special/class.copy/implicit-move.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.copy/implicit-move.cpp?rev=155218&r1=155217&r2=155218&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.copy/implicit-move.cpp?rev=155218&r1=155217&r2=155218&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/test/CXX/special/class.copy/implicit-move.cpp (original)<br>
+++ cfe/trunk/test/CXX/special/class.copy/implicit-move.cpp Fri Apr 20 13:46:14 2012<br>
@@ -198,15 +198,15 @@<br>
   struct NoMove4 : NonTrivialCopyAssign {}; // expected-note 2{{'const DR1402::NoMove4 &'}}<br>
   struct NoMove5 : virtual NonTrivialCopyCtor {}; // expected-note 2{{'const DR1402::NoMove5 &'}}<br>
   struct NoMove6 : virtual NonTrivialCopyAssign {}; // expected-note 2{{'const DR1402::NoMove6 &'}}<br>
-  struct NoMove7 : NonTrivialCopyCtorVBase {}; // expected-note 2{{'DR1402::NoMove7 &'}}<br>
-  struct NoMove8 : NonTrivialCopyAssignVBase {}; // expected-note 2{{'DR1402::NoMove8 &'}}<br>
+  struct NoMove7 : NonTrivialCopyCtorVBase {}; // expected-note 2{{'const DR1402::NoMove7 &'}}<br>
+  struct NoMove8 : NonTrivialCopyAssignVBase {}; // expected-note 2{{'const DR1402::NoMove8 &'}}<br>
<br>
   // A non-trivially-move-assignable virtual base class inhibits the declaration<br>
   // of a move assignment (which might move-assign the base class multiple<br>
   // times).<br>
   struct NoMove9 : NonTrivialMoveAssign {};<br>
-  struct NoMove10 : virtual NonTrivialMoveAssign {}; // expected-note {{'DR1402::NoMove10 &'}}<br>
-  struct NoMove11 : NonTrivialMoveAssignVBase {}; // expected-note {{'DR1402::NoMove11 &'}}<br>
+  struct NoMove10 : virtual NonTrivialMoveAssign {}; // expected-note {{'const DR1402::NoMove10 &'}}<br>
+  struct NoMove11 : NonTrivialMoveAssignVBase {}; // expected-note {{'const DR1402::NoMove11 &'}}<br>
<br>
   struct Test {<br>
     friend NoMove1::NoMove1(NoMove1 &&); // expected-error {{no matching function}}<br>
<br>
Added: cfe/trunk/test/CXX/special/class.copy/p8-cxx11.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.copy/p8-cxx11.cpp?rev=155218&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.copy/p8-cxx11.cpp?rev=155218&view=auto</a><br>

==============================================================================<br>
--- cfe/trunk/test/CXX/special/class.copy/p8-cxx11.cpp (added)<br>
+++ cfe/trunk/test/CXX/special/class.copy/p8-cxx11.cpp Fri Apr 20 13:46:14 2012<br>
@@ -0,0 +1,48 @@<br>
+// RUN: %clang_cc1 -std=c++11 %s -verify<br>
+<br>
+// C++98 [class.copy]p5 / C++11 [class.copy]p8.<br>
+<br>
+// The implicitly-declared copy constructor for a class X will have the form<br>
+//   X::X(const X&)<br>
+// if [every direct subobject] has a copy constructor whose first parameter is<br>
+// of type 'const volatile[opt] T &'. Otherwise, it will have the form<br>
+//   X::X(X&)<br>
+<br>
+struct ConstCopy {<br>
+  ConstCopy(const ConstCopy &);<br>
+};<br>
+<br>
+struct NonConstCopy {<br>
+  NonConstCopy(NonConstCopy &);<br>
+};<br>
+<br>
+struct DeletedConstCopy {<br>
+  DeletedConstCopy(const DeletedConstCopy &) = delete;<br>
+};<br>
+<br>
+struct DeletedNonConstCopy {<br>
+  DeletedNonConstCopy(DeletedNonConstCopy &) = delete;<br>
+};<br>
+<br>
+struct ImplicitlyDeletedConstCopy {<br>
+  ImplicitlyDeletedConstCopy(ImplicitlyDeletedConstCopy &&);<br>
+};<br>
+<br>
+<br>
+struct A : ConstCopy {};<br>
+struct B : NonConstCopy { ConstCopy a; };<br>
+struct C : ConstCopy { NonConstCopy a; };<br>
+struct D : DeletedConstCopy {};<br>
+struct E : DeletedNonConstCopy {};<br>
+struct F { ImplicitlyDeletedConstCopy a; };<br>
+struct G : virtual B {};<br>
+<br>
+struct Test {<br>
+  friend A::A(const A &);<br>
+  friend B::B(B &);<br>
+  friend C::C(C &);<br>
+  friend D::D(const D &);<br>
+  friend E::E(E &);<br>
+  friend F::F(const F &);<br>
+  friend G::G(G &);<br>
+};<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br>
</blockquote></div><br></body></html>