Store on the CXXRecordDecl whether the class has, or would have, a copy
constructor/assignment operator with a const-qualified parameter type. The
prior method for determining this incorrectly used overload resolution.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@168775 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index d661aa0..a3c0bab 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -55,9 +55,14 @@
     UserProvidedDefaultConstructor(false), DeclaredDefaultConstructor(false),
     DeclaredCopyConstructor(false), DeclaredMoveConstructor(false),
     DeclaredCopyAssignment(false), DeclaredMoveAssignment(false),
-    DeclaredDestructor(false), FailedImplicitMoveConstructor(false),
-    FailedImplicitMoveAssignment(false), IsLambda(false), NumBases(0),
-    NumVBases(0), Bases(), VBases(), Definition(D), FirstFriend(0) {
+    DeclaredDestructor(false),
+    ImplicitCopyConstructorHasConstParam(true),
+    ImplicitCopyAssignmentHasConstParam(true),
+    HasDeclaredCopyConstructorWithConstParam(false),
+    HasDeclaredCopyAssignmentWithConstParam(false),
+    FailedImplicitMoveConstructor(false), FailedImplicitMoveAssignment(false),
+    IsLambda(false), NumBases(0), NumVBases(0), Bases(), VBases(),
+    Definition(D), FirstFriend(0) {
 }
 
 CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getBasesSlowCase() const {
@@ -184,15 +189,25 @@
           BaseClassDecl->vbases_begin(),
          E = BaseClassDecl->vbases_end(); VBase != E; ++VBase) {
       // Add this base if it's not already in the list.
-      if (SeenVBaseTypes.insert(C.getCanonicalType(VBase->getType())))
+      if (SeenVBaseTypes.insert(C.getCanonicalType(VBase->getType()))) {
         VBases.push_back(VBase);
+
+        // C++11 [class.copy]p8:
+        //   The implicitly-declared copy constructor for a class X will have
+        //   the form 'X::X(const X&)' if each [...] virtual base class B of X
+        //   has a copy constructor whose first parameter is of type
+        //   'const B&' or 'const volatile B&' [...]
+        if (CXXRecordDecl *VBaseDecl = VBase->getType()->getAsCXXRecordDecl())
+          if (!VBaseDecl->hasCopyConstructorWithConstParam())
+            data().ImplicitCopyConstructorHasConstParam = false;
+      }
     }
 
     if (Base->isVirtual()) {
       // Add this base if it's not already in the list.
       if (SeenVBaseTypes.insert(C.getCanonicalType(BaseType)))
-          VBases.push_back(Base);
-      
+        VBases.push_back(Base);
+
       // C++0x [meta.unary.prop] is_empty:
       //    T is a class type, but not a union type, with ... no virtual base
       //    classes
@@ -276,6 +291,22 @@
     if (!BaseClassDecl->hasIrrelevantDestructor())
       data().HasIrrelevantDestructor = false;
 
+    // C++11 [class.copy]p18:
+    //   The implicitly-declared copy assignment oeprator for a class X will
+    //   have the form 'X& X::operator=(const X&)' if each direct base class B
+    //   of X has a copy assignment operator whose parameter is of type 'const
+    //   B&', 'const volatile B&', or 'B' [...]
+    if (!BaseClassDecl->hasCopyAssignmentWithConstParam())
+      data().ImplicitCopyAssignmentHasConstParam = false;
+
+    // C++11 [class.copy]p8:
+    //   The implicitly-declared copy constructor for a class X will have
+    //   the form 'X::X(const X&)' if each direct [...] base class B of X
+    //   has a copy constructor whose first parameter is of type
+    //   'const B&' or 'const volatile B&' [...]
+    if (!BaseClassDecl->hasCopyConstructorWithConstParam())
+      data().ImplicitCopyConstructorHasConstParam = false;
+
     // A class has an Objective-C object member if... or any of its bases
     // has an Objective-C object member.
     if (BaseClassDecl->hasObjectMember())
@@ -522,51 +553,25 @@
       data().IsStandardLayout = false;
     }
   }
-  
-  if (D->isImplicit()) {
-    // Notify that an implicit member was added after the definition
-    // was completed.
-    if (!isBeingDefined())
-      if (ASTMutationListener *L = getASTMutationListener())
-        L->AddedCXXImplicitMember(data().Definition, D);
 
-    // If this is a special member function, note that it was added and then
-    // return early.
-    if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
-      if (Constructor->isDefaultConstructor()) {
-        data().DeclaredDefaultConstructor = true;
-        if (Constructor->isConstexpr()) {
-          data().HasConstexprDefaultConstructor = true;
-          data().HasConstexprNonCopyMoveConstructor = true;
-        }
-      } else if (Constructor->isCopyConstructor()) {
-        data().DeclaredCopyConstructor = true;
-      } else if (Constructor->isMoveConstructor()) {
-        data().DeclaredMoveConstructor = true;
-      } else
-        goto NotASpecialMember;
-      return;
-    } else if (isa<CXXDestructorDecl>(D)) {
-      data().DeclaredDestructor = true;
-      return;
-    } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
-      if (Method->isCopyAssignmentOperator())
-        data().DeclaredCopyAssignment = true;
-      else if (Method->isMoveAssignmentOperator())
-        data().DeclaredMoveAssignment = true;
-      else
-        goto NotASpecialMember;
-      return;
-    }
+  // Notify the listener if an implicit member was added after the definition
+  // was completed.
+  if (!isBeingDefined() && D->isImplicit())
+    if (ASTMutationListener *L = getASTMutationListener())
+      L->AddedCXXImplicitMember(data().Definition, D);
 
-NotASpecialMember:;
-    // Any other implicit declarations are handled like normal declarations.
-  }
-  
-  // Handle (user-declared) constructors.
+  // Handle constructors.
   if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
-    // Note that we have a user-declared constructor.
-    data().UserDeclaredConstructor = true;
+    if (!Constructor->isImplicit()) {
+      // Note that we have a user-declared constructor.
+      data().UserDeclaredConstructor = true;
+
+      // C++ [class]p4:
+      //   A POD-struct is an aggregate class [...]
+      // Since the POD bit is meant to be C++03 POD-ness, clear it even if the
+      // type is technically an aggregate in C++0x since it wouldn't be in 03.
+      data().PlainOldData = false;
+    }
 
     // Technically, "user-provided" is only defined for special member
     // functions, but the intent of the standard is clearly that it should apply
@@ -581,17 +586,17 @@
         data().HasTrivialDefaultConstructor = false;
         data().UserProvidedDefaultConstructor = true;
       }
-      if (Constructor->isConstexpr()) {
+      if (Constructor->isConstexpr())
         data().HasConstexprDefaultConstructor = true;
-        data().HasConstexprNonCopyMoveConstructor = true;
-      }
     }
 
     // Note when we have a user-declared copy or move constructor, which will
     // suppress the implicit declaration of those constructors.
     if (!FunTmpl) {
-      if (Constructor->isCopyConstructor()) {
-        data().UserDeclaredCopyConstructor = true;
+      unsigned Quals;
+      if (Constructor->isCopyConstructor(Quals)) {
+        if (!Constructor->isImplicit())
+          data().UserDeclaredCopyConstructor = true;
         data().DeclaredCopyConstructor = true;
 
         // C++0x [class.copy]p13:
@@ -599,8 +604,12 @@
         //   user-provided [...]
         if (UserProvided)
           data().HasTrivialCopyConstructor = false;
+
+        if (Quals & Qualifiers::Const)
+          data().HasDeclaredCopyConstructorWithConstParam = true;
       } else if (Constructor->isMoveConstructor()) {
-        data().UserDeclaredMoveConstructor = true;
+        if (!Constructor->isImplicit())
+          data().UserDeclaredMoveConstructor = true;
         data().DeclaredMoveConstructor = true;
 
         // C++0x [class.copy]p13:
@@ -610,11 +619,11 @@
           data().HasTrivialMoveConstructor = false;
       }
     }
-    if (Constructor->isConstexpr() && !Constructor->isCopyOrMoveConstructor()) {
-      // Record if we see any constexpr constructors which are neither copy
-      // nor move constructors.
+
+    // Record if we see any constexpr constructors which are neither copy
+    // nor move constructors.
+    if (Constructor->isConstexpr() && !Constructor->isCopyOrMoveConstructor())
       data().HasConstexprNonCopyMoveConstructor = true;
-    }
 
     // C++ [dcl.init.aggr]p1:
     //   An aggregate is an array or a class with no user-declared
@@ -622,31 +631,29 @@
     // C++0x [dcl.init.aggr]p1:
     //   An aggregate is an array or a class with no user-provided
     //   constructors [...].
-    if (!getASTContext().getLangOpts().CPlusPlus0x || UserProvided)
+    if (getASTContext().getLangOpts().CPlusPlus0x
+          ? UserProvided : !Constructor->isImplicit())
       data().Aggregate = false;
 
-    // C++ [class]p4:
-    //   A POD-struct is an aggregate class [...]
-    // Since the POD bit is meant to be C++03 POD-ness, clear it even if the
-    // type is technically an aggregate in C++0x since it wouldn't be in 03.
-    data().PlainOldData = false;
-
     return;
   }
 
-  // Handle (user-declared) destructors.
+  // Handle destructors.
   if (CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(D)) {
     data().DeclaredDestructor = true;
-    data().UserDeclaredDestructor = true;
-    data().HasIrrelevantDestructor = false;
 
-    // C++ [class]p4: 
-    //   A POD-struct is an aggregate class that has [...] no user-defined 
-    //   destructor.
-    // This bit is the C++03 POD bit, not the 0x one.
-    data().PlainOldData = false;
-    
-    // C++11 [class.dtor]p5: 
+    if (!DD->isImplicit()) {
+      data().UserDeclaredDestructor = true;
+      data().HasIrrelevantDestructor = false;
+
+      // C++ [class]p4:
+      //   A POD-struct is an aggregate class that has [...] no user-defined
+      //   destructor.
+      // This bit is the C++03 POD bit, not the 0x one.
+      data().PlainOldData = false;
+    }
+
+    // C++11 [class.dtor]p5:
     //   A destructor is trivial if it is not user-provided and if
     //    -- the destructor is not virtual.
     if (DD->isUserProvided() || DD->isVirtual())
@@ -654,45 +661,53 @@
 
     return;
   }
-  
-  // Handle (user-declared) member functions.
+
+  // Handle member functions.
   if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
     if (Method->isCopyAssignmentOperator()) {
-      // C++ [class]p4:
-      //   A POD-struct is an aggregate class that [...] has no user-defined
-      //   copy assignment operator [...].
-      // This is the C++03 bit only.
-      data().PlainOldData = false;
-
-      // This is a copy assignment operator.
-
       // Suppress the implicit declaration of a copy constructor.
-      data().UserDeclaredCopyAssignment = true;
       data().DeclaredCopyAssignment = true;
 
-      // C++0x [class.copy]p27:
-      //   A copy/move assignment operator for class X is trivial if it is
-      //   neither user-provided nor deleted [...]
-      if (Method->isUserProvided())
-        data().HasTrivialCopyAssignment = false;
+      if (!Method->isImplicit()) {
+        data().UserDeclaredCopyAssignment = true;
 
-      return;
+        // C++ [class]p4:
+        //   A POD-struct is an aggregate class that [...] has no user-defined
+        //   copy assignment operator [...].
+        // This is the C++03 bit only.
+        data().PlainOldData = false;
+
+        // C++11 [class.copy]p25:
+        //   A copy/move assignment operator for class X is trivial if it is
+        //   not user-provided [...]
+        // FIXME: This is bogus. Having one user-provided copy assignment
+        // doesn't stop another one from being trivial.
+        if (Method->isUserProvided())
+          data().HasTrivialCopyAssignment = false;
+      }
+
+      const ReferenceType *ParamTy =
+        Method->getParamDecl(0)->getType()->getAs<ReferenceType>();
+      if (!ParamTy || ParamTy->getPointeeType().isConstQualified())
+        data().HasDeclaredCopyAssignmentWithConstParam = true;
     }
-    
-    if (Method->isMoveAssignmentOperator()) {
-      // This is an extension in C++03 mode, but we'll keep consistency by
-      // taking a move assignment operator to induce non-POD-ness
-      data().PlainOldData = false;
 
-      // This is a move assignment operator.
-      data().UserDeclaredMoveAssignment = true;
+    if (Method->isMoveAssignmentOperator()) {
       data().DeclaredMoveAssignment = true;
 
-      // C++0x [class.copy]p27:
-      //   A copy/move assignment operator for class X is trivial if it is
-      //   neither user-provided nor deleted [...]
-      if (Method->isUserProvided())
-        data().HasTrivialMoveAssignment = false;
+      if (!Method->isImplicit()) {
+        data().UserDeclaredMoveAssignment = true;
+
+        // This is an extension in C++03 mode, but we'll keep consistency by
+        // taking a move assignment operator to induce non-POD-ness
+        data().PlainOldData = false;
+
+        // C++0x [class.copy]p27:
+        //   A copy/move assignment operator for class X is trivial if it is
+        //   neither user-provided nor deleted [...]
+        if (Method->isUserProvided())
+          data().HasTrivialMoveAssignment = false;
+      }
     }
 
     // Keep the list of conversion functions up-to-date.
@@ -700,7 +715,7 @@
       // We don't record specializations.
       if (Conversion->getPrimaryTemplate())
         return;
-      
+
       // FIXME: We intentionally don't use the decl's access here because it
       // hasn't been set yet.  That's really just a misdesign in Sema.
 
@@ -718,7 +733,7 @@
           data().Conversions.addDecl(getASTContext(), Conversion);
       }
     }
-    
+
     return;
   }
   
@@ -902,6 +917,24 @@
           // The standard requires any in-class initializer to be a constant
           // expression. We consider this to be a defect.
           data().DefaultedDefaultConstructorIsConstexpr = false;
+
+        // C++11 [class.copy]p8:
+        //   The implicitly-declared copy constructor for a class X will have
+        //   the form 'X::X(const X&)' if [...] for all the non-static data
+        //   members of X that are of a class type M (or array thereof), each
+        //   such class type has a copy constructor whose first parameter is
+        //   of type 'const M&' or 'const volatile M&'.
+        if (!FieldRec->hasCopyConstructorWithConstParam())
+          data().ImplicitCopyConstructorHasConstParam = false;
+
+        // C++11 [class.copy]p18:
+        //   The implicitly-declared copy assignment oeprator for a class X will
+        //   have the form 'X& X::operator=(const X&)' if [...] for all the
+        //   non-static data members of X that are of a class type M (or array
+        //   thereof), each such class type has a copy assignment operator whose
+        //   parameter is of type 'const M&', 'const volatile M&' or 'M'.
+        if (!FieldRec->hasCopyAssignmentWithConstParam())
+          data().ImplicitCopyAssignmentHasConstParam = false;
       }
     } else {
       // Base element type of field is a non-class type.