]> granicus.if.org Git - clang/commitdiff
Implement a little bit of cleanup and a lot more of the base work
authorSean Hunt <scshunt@csclub.uwaterloo.ca>
Wed, 25 May 2011 20:50:04 +0000 (20:50 +0000)
committerSean Hunt <scshunt@csclub.uwaterloo.ca>
Wed, 25 May 2011 20:50:04 +0000 (20:50 +0000)
behind implicit moves. We now correctly identify move constructors and
assignment operators and update bits on the record correctly. Generation
of implicit moves (declarations or definitions) is not yet supported.

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

include/clang/AST/ASTContext.h
include/clang/AST/DeclCXX.h
include/clang/Sema/Sema.h
lib/AST/ASTContext.cpp
lib/AST/DeclCXX.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclCXX.cpp

index 4f4d949735a33c1a594c6c970144a62938d67388..c28e3547a383639f28c265cce701e83d3a790065 100644 (file)
@@ -1546,6 +1546,13 @@ public:
   /// which declarations were built.
   static unsigned NumImplicitCopyConstructorsDeclared;
 
+  /// \brief The number of implicitly-declared move constructors.
+  static unsigned NumImplicitMoveConstructors;
+
+  /// \brief The number of implicitly-declared move constructors for
+  /// which declarations were built.
+  static unsigned NumImplicitMoveConstructorsDeclared;
+
   /// \brief The number of implicitly-declared copy assignment operators.
   static unsigned NumImplicitCopyAssignmentOperators;
   
@@ -1553,6 +1560,13 @@ public:
   /// which declarations were built.
   static unsigned NumImplicitCopyAssignmentOperatorsDeclared;
 
+  /// \brief The number of implicitly-declared move assignment operators.
+  static unsigned NumImplicitMoveAssignmentOperators;
+  
+  /// \brief The number of implicitly-declared move assignment operators for 
+  /// which declarations were built.
+  static unsigned NumImplicitMoveAssignmentOperatorsDeclared;
+
   /// \brief The number of implicitly-declared destructors.
   static unsigned NumImplicitDestructors;
   
index 51fc729ea565f541d56a6f92fc5968e4d8311379..096ace712859a1aa23a6acf444d930e43ab3447d 100644 (file)
@@ -278,10 +278,18 @@ class CXXRecordDecl : public RecordDecl {
     /// user-declared copy constructor.
     bool UserDeclaredCopyConstructor : 1;
 
+    /// UserDeclareMoveConstructor - True when this class has a
+    /// user-declared move constructor.
+    bool UserDeclaredMoveConstructor : 1;
+
     /// UserDeclaredCopyAssignment - True when this class has a
     /// user-declared copy assignment operator.
     bool UserDeclaredCopyAssignment : 1;
 
+    /// UserDeclareMoveAssignment - True when this class has a
+    /// user-declared move assignment.
+    bool UserDeclaredMoveAssignment : 1;
+
     /// UserDeclaredDestructor - True when this class has a
     /// user-declared destructor.
     bool UserDeclaredDestructor : 1;
@@ -448,9 +456,15 @@ class CXXRecordDecl : public RecordDecl {
 
     /// \brief Whether we have already declared the copy constructor.
     bool DeclaredCopyConstructor : 1;
+
+    /// \brief Whether we have already declared the move constructor.
+    bool DeclaredMoveConstructor : 1;
     
     /// \brief Whether we have already declared the copy-assignment operator.
     bool DeclaredCopyAssignment : 1;
+
+    /// \brief Whether we have already declared the move-assignment operator.
+    bool DeclaredMoveAssignment : 1;
     
     /// \brief Whether we have already declared a destructor within the class.
     bool DeclaredDestructor : 1;
@@ -695,11 +709,13 @@ public:
 
   /// hasConstCopyConstructor - Determines whether this class has a
   /// copy constructor that accepts a const-qualified argument.
-  bool hasConstCopyConstructor(const ASTContext &Context) const;
+  bool hasConstCopyConstructor() const;
 
   /// getCopyConstructor - Returns the copy constructor for this class
-  CXXConstructorDecl *getCopyConstructor(const ASTContext &Context,
-                                         unsigned TypeQuals) const;
+  CXXConstructorDecl *getCopyConstructor(unsigned TypeQuals) const;
+
+  /// getMoveConstructor - Returns the move constructor for this class
+  CXXConstructorDecl *getMoveConstructor() const; 
 
   /// \brief Retrieve the copy-assignment operator for this class, if available.
   ///
@@ -712,6 +728,10 @@ public:
   /// \returns The copy-assignment operator that can be invoked, or NULL if
   /// a unique copy-assignment operator could not be found.
   CXXMethodDecl *getCopyAssignmentOperator(bool ArgIsConst) const;
+
+  /// getMoveAssignmentOperator - Returns the move assignment operator for this
+  /// class
+  CXXMethodDecl *getMoveAssignmentOperator() const;
   
   /// hasUserDeclaredConstructor - Whether this class has any
   /// user-declared constructors. When true, a default constructor
@@ -740,7 +760,27 @@ public:
   bool hasDeclaredCopyConstructor() const {
     return data().DeclaredCopyConstructor;
   }
-  
+
+  /// hasUserDeclaredMoveOperation - Whether this class has a user-
+  /// declared move constructor or assignment operator. When false, a
+  /// move constructor and assignment operator may be implicitly declared.
+  bool hasUserDeclaredMoveOperation() const {
+    return data().UserDeclaredMoveConstructor ||
+           data().UserDeclaredMoveAssignment;
+  }
+
+  /// \brief Determine whether this class has had a move constructor
+  /// declared by the user.
+  bool hasUserDeclaredMoveConstructor() const {
+    return data().UserDeclaredMoveConstructor;
+  }
+
+  /// \brief Determine whether this class has had a move constructor
+  /// declared.
+  bool hasDeclaredMoveConstructor() const {
+    return data().DeclaredMoveConstructor;
+  }
+
   /// hasUserDeclaredCopyAssignment - Whether this class has a
   /// user-declared copy assignment operator. When false, a copy
   /// assigment operator will be implicitly declared.
@@ -755,7 +795,19 @@ public:
   bool hasDeclaredCopyAssignment() const {
     return data().DeclaredCopyAssignment;
   }
-  
+
+  /// \brief Determine whether this class has had a move assignment
+  /// declared by the user.
+  bool hasUserDeclaredMoveAssignment() const {
+    return data().UserDeclaredMoveAssignment;
+  }
+
+  /// hasDeclaredMoveAssignment - Whether this class has a
+  /// declared move assignment operator.
+  bool hasDeclaredMoveAssignment() const {
+    return data().DeclaredMoveAssignment;
+  }
+
   /// hasUserDeclaredDestructor - Whether this class has a
   /// user-declared destructor. When false, a destructor will be
   /// implicitly declared.
@@ -1225,6 +1277,9 @@ public:
   /// \brief Determine whether this is a copy-assignment operator, regardless
   /// of whether it was declared implicitly or explicitly.
   bool isCopyAssignmentOperator() const;
+
+  /// \brief Determine whether this is a move assignment operator.
+  bool isMoveAssignmentOperator() const;
   
   const CXXMethodDecl *getCanonicalDecl() const {
     return cast<CXXMethodDecl>(FunctionDecl::getCanonicalDecl());
index 2cbfd9f3d616104ed39dae65b6346e7323802af9..be76a4a75518bac9ef37a6808804a751e6ad82b2 100644 (file)
@@ -1118,7 +1118,9 @@ public:
     CXXDefaultConstructor = 0,
     CXXCopyConstructor = 1,
     CXXCopyAssignment = 2,
-    CXXDestructor = 3
+    CXXDestructor = 3,
+    CXXMoveConstructor = 4,
+    CXXMoveAssignment = 5
   };
   bool CheckNontrivialField(FieldDecl *FD);
   void DiagnoseNontrivial(const RecordType* Record, CXXSpecialMember mem);
index d5003be5dea2b21467fcb05bf3928f317eeb5063..1535efec984893f8ab8311fa9941662c01ec0a31 100644 (file)
@@ -39,8 +39,12 @@ unsigned ASTContext::NumImplicitDefaultConstructors;
 unsigned ASTContext::NumImplicitDefaultConstructorsDeclared;
 unsigned ASTContext::NumImplicitCopyConstructors;
 unsigned ASTContext::NumImplicitCopyConstructorsDeclared;
+unsigned ASTContext::NumImplicitMoveConstructors;
+unsigned ASTContext::NumImplicitMoveConstructorsDeclared;
 unsigned ASTContext::NumImplicitCopyAssignmentOperators;
 unsigned ASTContext::NumImplicitCopyAssignmentOperatorsDeclared;
+unsigned ASTContext::NumImplicitMoveAssignmentOperators;
+unsigned ASTContext::NumImplicitMoveAssignmentOperatorsDeclared;
 unsigned ASTContext::NumImplicitDestructors;
 unsigned ASTContext::NumImplicitDestructorsDeclared;
 
@@ -318,9 +322,17 @@ void ASTContext::PrintStats() const {
   fprintf(stderr, "  %u/%u implicit copy constructors created\n",
           NumImplicitCopyConstructorsDeclared, 
           NumImplicitCopyConstructors);
+  if (getLangOptions().CPlusPlus)
+    fprintf(stderr, "  %u/%u implicit move constructors created\n",
+            NumImplicitMoveConstructorsDeclared, 
+            NumImplicitMoveConstructors);
   fprintf(stderr, "  %u/%u implicit copy assignment operators created\n",
           NumImplicitCopyAssignmentOperatorsDeclared, 
           NumImplicitCopyAssignmentOperators);
+  if (getLangOptions().CPlusPlus)
+    fprintf(stderr, "  %u/%u implicit move assignment operators created\n",
+            NumImplicitMoveAssignmentOperatorsDeclared, 
+            NumImplicitMoveAssignmentOperators);
   fprintf(stderr, "  %u/%u implicit destructors created\n",
           NumImplicitDestructorsDeclared, NumImplicitDestructors);
   
@@ -3717,7 +3729,7 @@ bool ASTContext::BlockRequiresCopying(QualType Ty) const {
   if (getLangOptions().CPlusPlus) {
     if (const RecordType *RT = Ty->getAs<RecordType>()) {
       CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
-      return RD->hasConstCopyConstructor(*this);
+      return RD->hasConstCopyConstructor();
       
     }
   }
index 43cea51e93c34ad4b957ee7b134618aa0f6359ec..9e82a1a84c8f7c886874a192142842e7e0eccd7a 100644 (file)
@@ -29,7 +29,8 @@ using namespace clang;
 
 CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
   : UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false),
-    UserDeclaredCopyAssignment(false), UserDeclaredDestructor(false),
+    UserDeclaredMoveConstructor(false), UserDeclaredCopyAssignment(false),
+    UserDeclaredMoveAssignment(false), UserDeclaredDestructor(false),
     Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false),
     Abstract(false), IsStandardLayout(true), HasNoNonEmptyBases(true),
     HasPrivateFields(false), HasProtectedFields(false), HasPublicFields(false),
@@ -39,7 +40,8 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
     HasTrivialMoveAssignment(true), HasTrivialDestructor(true),
     HasNonLiteralTypeFieldsOrBases(false), ComputedVisibleConversions(false),
     UserProvidedDefaultConstructor(false), DeclaredDefaultConstructor(false),
-    DeclaredCopyConstructor(false), DeclaredCopyAssignment(false),
+    DeclaredCopyConstructor(false), DeclaredMoveConstructor(false),
+    DeclaredCopyAssignment(false), DeclaredMoveAssignment(false),
     DeclaredDestructor(false), NumBases(0), NumVBases(0), Bases(), VBases(),
     Definition(D), FirstFriend(0) {
 }
@@ -268,8 +270,8 @@ bool CXXRecordDecl::hasAnyDependentBases() const {
   return !forallBases(SawBase, 0);
 }
 
-bool CXXRecordDecl::hasConstCopyConstructor(const ASTContext &Context) const {
-  return getCopyConstructor(Context, Qualifiers::Const) != 0;
+bool CXXRecordDecl::hasConstCopyConstructor() const {
+  return getCopyConstructor(Qualifiers::Const) != 0;
 }
 
 bool CXXRecordDecl::isTriviallyCopyable() const {
@@ -312,8 +314,8 @@ GetBestOverloadCandidateSimple(
   return Cands[Best].first;
 }
 
-CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(const ASTContext &Context,
-                                                      unsigned TypeQuals) const{
+CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(unsigned TypeQuals) const{
+  ASTContext &Context = getASTContext();
   QualType ClassType
     = Context.getTypeDeclType(const_cast<CXXRecordDecl*>(this));
   DeclarationName ConstructorName
@@ -343,6 +345,14 @@ CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(const ASTContext &Context,
                                         GetBestOverloadCandidateSimple(Found));
 }
 
+CXXConstructorDecl *CXXRecordDecl::getMoveConstructor() const {
+  for (ctor_iterator I = ctor_begin(), E = ctor_end(); I != E; ++I)
+    if (I->isMoveConstructor())
+      return *I;
+
+  return 0;
+}
+
 CXXMethodDecl *CXXRecordDecl::getCopyAssignmentOperator(bool ArgIsConst) const {
   ASTContext &Context = getASTContext();
   QualType Class = Context.getTypeDeclType(const_cast<CXXRecordDecl *>(this));
@@ -393,6 +403,14 @@ CXXMethodDecl *CXXRecordDecl::getCopyAssignmentOperator(bool ArgIsConst) const {
   return GetBestOverloadCandidateSimple(Found);
 }
 
+CXXMethodDecl *CXXRecordDecl::getMoveAssignmentOperator() const {
+  for (method_iterator I = method_begin(), E = method_end(); I != E; ++I)
+    if (I->isMoveAssignmentOperator())
+      return *I;
+
+  return 0;
+}
+
 void CXXRecordDecl::markedVirtualFunctionPure() {
   // C++ [class.abstract]p2: 
   //   A class is abstract if it has at least one pure virtual function.
@@ -459,33 +477,32 @@ void CXXRecordDecl::addedMember(Decl *D) {
       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 this is the implicit default constructor, note that we have now
-      // declared it.
-      if (Constructor->isDefaultConstructor()) {
+      if (Constructor->isDefaultConstructor())
         data().DeclaredDefaultConstructor = true;
-      }
-      // If this is the implicit copy constructor, note that we have now
-      // declared it.
       else if (Constructor->isCopyConstructor())
         data().DeclaredCopyConstructor = true;
+      else if (Constructor->isMoveConstructor())
+        data().DeclaredMoveConstructor = true;
+      else
+        goto NotASpecialMember;
       return;
-    } 
-
-    if (isa<CXXDestructorDecl>(D)) {
+    } else if (isa<CXXDestructorDecl>(D)) {
       data().DeclaredDestructor = true;
       return;
-    } 
-
-    if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
-      // If this is the implicit copy constructor, note that we have now
-      // declared it.
-      // FIXME: Move constructors
-      if (Method->getOverloadedOperator() == OO_Equal)
+    } 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;
     }
 
+NotASpecialMember:;
     // Any other implicit declarations are handled like normal declarations.
   }
   
@@ -524,6 +541,9 @@ void CXXRecordDecl::addedMember(Decl *D) {
           UserProvided = true;
         }
       } else if (Constructor->isMoveConstructor()) {
+        data().UserDeclaredMoveConstructor = true;
+        data().DeclaredMoveConstructor = true;
+
         // C++0x [class.copy]p13:
         //   A copy/move constructor for class X is trivial if it is not
         //   user-provided [...]
@@ -579,61 +599,42 @@ void CXXRecordDecl::addedMember(Decl *D) {
   
   // Handle (user-declared) member functions.
   if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
-    if (Method->getOverloadedOperator() == OO_Equal) {
-      // We're interested specifically in copy assignment operators.
-      const FunctionProtoType *FnType 
-        = Method->getType()->getAs<FunctionProtoType>();
-      assert(FnType && "Overloaded operator has no proto function type.");
-      assert(FnType->getNumArgs() == 1 && !FnType->isVariadic());
-      
-      // Copy assignment operators must be non-templates.
-      if (Method->getPrimaryTemplate() || FunTmpl)
-        return;
-      
-      ASTContext &Context = getASTContext();
-      QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(
-                                             const_cast<CXXRecordDecl*>(this)));
-
-      bool isRValueRefArg = false;
-      QualType ArgType = FnType->getArgType(0);
-      if (const LValueReferenceType *Ref =
-          ArgType->getAs<LValueReferenceType>()) {
-        ArgType = Ref->getPointeeType();
-      } else if (const RValueReferenceType *Ref =
-               ArgType->getAs<RValueReferenceType>()) {
-        ArgType = Ref->getPointeeType();
-        isRValueRefArg = true;
-      }
-      if (!Context.hasSameUnqualifiedType(ClassType, ArgType))
-        return;
-
+    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;
 
-      if (!isRValueRefArg) {
-        // This is a copy assignment operator.
+      // This is a copy assignment operator.
 
-        // Suppress the implicit declaration of a copy constructor.
-        data().UserDeclaredCopyAssignment = true;
-        data().DeclaredCopyAssignment = true;
+      // 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;
-      } else {
-        // This is a move assignment operator.
+      // 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;
 
-        // 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;
-      }
+      return;
+    }
+    
+    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;
+      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;
     }
 
     // Keep the list of conversion functions up-to-date.
@@ -1170,14 +1171,13 @@ bool CXXMethodDecl::isUsualDeallocationFunction() const {
 }
 
 bool CXXMethodDecl::isCopyAssignmentOperator() const {
-  // C++0x [class.copy]p19:
+  // C++0x [class.copy]p17:
   //  A user-declared copy assignment operator X::operator= is a non-static 
   //  non-template member function of class X with exactly one parameter of 
   //  type X, X&, const X&, volatile X& or const volatile X&.
   if (/*operator=*/getOverloadedOperator() != OO_Equal ||
       /*non-static*/ isStatic() || 
-      /*non-template*/getPrimaryTemplate() || getDescribedFunctionTemplate() ||
-      /*exactly one parameter*/getNumParams() != 1)
+      /*non-template*/getPrimaryTemplate() || getDescribedFunctionTemplate())
     return false;
       
   QualType ParamType = getParamDecl(0)->getType();
@@ -1190,6 +1190,26 @@ bool CXXMethodDecl::isCopyAssignmentOperator() const {
   return Context.hasSameUnqualifiedType(ClassType, ParamType);
 }
 
+bool CXXMethodDecl::isMoveAssignmentOperator() const {
+  // C++0x [class.copy]p19:
+  //  A user-declared move assignment operator X::operator= is a non-static
+  //  non-template member function of class X with exactly one parameter of type
+  //  X&&, const X&&, volatile X&&, or const volatile X&&.
+  if (getOverloadedOperator() != OO_Equal || isStatic() ||
+      getPrimaryTemplate() || getDescribedFunctionTemplate())
+    return false;
+
+  QualType ParamType = getParamDecl(0)->getType();
+  if (!isa<RValueReferenceType>(ParamType))
+    return false;
+  ParamType = ParamType->getPointeeType();
+
+  ASTContext &Context = getASTContext();
+  QualType ClassType
+    = Context.getCanonicalType(Context.getTypeDeclType(getParent()));
+  return Context.hasSameUnqualifiedType(ClassType, ParamType);
+}
+
 void CXXMethodDecl::addOverriddenMethod(const CXXMethodDecl *MD) {
   assert(MD->isCanonicalDecl() && "Method is not canonical!");
   assert(!MD->getParent()->isDependentContext() &&
index 41e05d5cdb5ba053d60603091e30b3ca6cf9fda8..8b0ee7057a75d062ea6d4a27ba2fff8d540ea700 100644 (file)
@@ -7736,7 +7736,15 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
   case CXXCopyConstructor:
     if (RD->hasUserDeclaredCopyConstructor()) {
       SourceLocation CtorLoc =
-        RD->getCopyConstructor(Context, 0)->getLocation();
+        RD->getCopyConstructor(0)->getLocation();
+      Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member;
+      return;
+    }
+    break;
+
+  case CXXMoveConstructor:
+    if (RD->hasUserDeclaredMoveConstructor()) {
+      SourceLocation CtorLoc = RD->getMoveConstructor()->getLocation();
       Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member;
       return;
     }
@@ -7752,6 +7760,14 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
     }
     break;
 
+  case CXXMoveAssignment:
+    if (RD->hasUserDeclaredMoveAssignment()) {
+      SourceLocation AssignLoc = RD->getMoveAssignmentOperator()->getLocation();
+      Diag(AssignLoc, diag::note_nontrivial_user_defined) << QT << member;
+      return;
+    }
+    break;
+
   case CXXDestructor:
     if (RD->hasUserDeclaredDestructor()) {
       SourceLocation DtorLoc = LookupDestructor(RD)->getLocation();
index e8f2f57a220015300b1ab0dc427c575a734030a4..1e3baa26f3399f38ed44db42e822bbd12f886be7 100644 (file)
@@ -7069,8 +7069,7 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) {
     if (!BaseClassDecl->hasDeclaredCopyConstructor())
       DeclareImplicitCopyConstructor(BaseClassDecl);
   
-    HasConstCopyConstructor
-      = BaseClassDecl->hasConstCopyConstructor(Context);
+    HasConstCopyConstructor = BaseClassDecl->hasConstCopyConstructor();
   }
 
   for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
@@ -7082,8 +7081,7 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) {
     if (!BaseClassDecl->hasDeclaredCopyConstructor())
       DeclareImplicitCopyConstructor(BaseClassDecl);
     
-    HasConstCopyConstructor
-      = BaseClassDecl->hasConstCopyConstructor(Context);
+    HasConstCopyConstructor= BaseClassDecl->hasConstCopyConstructor();
   }
   
   //     -- for all the nonstatic data members of X that are of a
@@ -7101,8 +7099,7 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) {
       if (!FieldClassDecl->hasDeclaredCopyConstructor())
         DeclareImplicitCopyConstructor(FieldClassDecl);
 
-      HasConstCopyConstructor
-        = FieldClassDecl->hasConstCopyConstructor(Context);
+      HasConstCopyConstructor = FieldClassDecl->hasConstCopyConstructor();
     }
   }
   //   Otherwise, the implicitly declared copy constructor will have
@@ -7129,7 +7126,7 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) {
       DeclareImplicitCopyConstructor(BaseClassDecl);
 
     if (CXXConstructorDecl *CopyConstructor
-                          = BaseClassDecl->getCopyConstructor(Context, Quals))
+                          = BaseClassDecl->getCopyConstructor(Quals))
       ExceptSpec.CalledDecl(CopyConstructor);
   }
   for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
@@ -7142,7 +7139,7 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) {
       DeclareImplicitCopyConstructor(BaseClassDecl);
 
     if (CXXConstructorDecl *CopyConstructor
-                          = BaseClassDecl->getCopyConstructor(Context, Quals))
+                          = BaseClassDecl->getCopyConstructor(Quals))
       ExceptSpec.CalledDecl(CopyConstructor);
   }
   for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
@@ -7157,7 +7154,7 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) {
         DeclareImplicitCopyConstructor(FieldClassDecl);
 
       if (CXXConstructorDecl *CopyConstructor
-                          = FieldClassDecl->getCopyConstructor(Context, Quals))
+                          = FieldClassDecl->getCopyConstructor(Quals))
         ExceptSpec.CalledDecl(CopyConstructor);
     }
   }