diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-11-28 06:23:12 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-11-28 06:23:12 +0000 |
commit | acf796b4797c5b3e9e237148fa622afdc04b3eff (patch) | |
tree | 6c271132920ce500bffd5b7d570b9f537eba17ac /lib | |
parent | 3881866dc782c5e13b21031bd363e93fbf367167 (diff) |
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
Diffstat (limited to 'lib')
-rw-r--r-- | lib/AST/ASTImporter.cpp | 8 | ||||
-rw-r--r-- | lib/AST/DeclCXX.cpp | 247 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 145 | ||||
-rw-r--r-- | lib/Serialization/ASTReaderDecl.cpp | 4 | ||||
-rw-r--r-- | lib/Serialization/ASTWriter.cpp | 4 |
5 files changed, 160 insertions, 248 deletions
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 906cc3b4d0..054cd962f3 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -1950,6 +1950,14 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To, ToData.DeclaredCopyAssignment = FromData.DeclaredCopyAssignment; ToData.DeclaredMoveAssignment = FromData.DeclaredMoveAssignment; ToData.DeclaredDestructor = FromData.DeclaredDestructor; + ToData.ImplicitCopyConstructorHasConstParam + = FromData.ImplicitCopyConstructorHasConstParam; + ToData.ImplicitCopyAssignmentHasConstParam + = FromData.ImplicitCopyAssignmentHasConstParam; + ToData.HasDeclaredCopyConstructorWithConstParam + = FromData.HasDeclaredCopyConstructorWithConstParam; + ToData.HasDeclaredCopyAssignmentWithConstParam + = FromData.HasDeclaredCopyAssignmentWithConstParam; ToData.FailedImplicitMoveConstructor = FromData.FailedImplicitMoveConstructor; ToData.FailedImplicitMoveAssignment = FromData.FailedImplicitMoveAssignment; diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index d661aa04af..a3c0bab8b8 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -55,9 +55,14 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) 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 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, 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 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, 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 @@ void CXXRecordDecl::addedMember(Decl *D) { 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; - } -NotASpecialMember:; - // Any other implicit declarations are handled like normal declarations. - } - - // Handle (user-declared) constructors. + // 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); + + // 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 @@ NotASpecialMember:; 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 @@ NotASpecialMember:; // 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 @@ NotASpecialMember:; 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 @@ NotASpecialMember:; // 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 @@ NotASpecialMember:; 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; + + // 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; + } - return; + 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 @@ NotASpecialMember:; // 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 @@ NotASpecialMember:; data().Conversions.addDecl(getASTContext(), Conversion); } } - + return; } @@ -902,6 +917,24 @@ NotASpecialMember:; // 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. diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 86da9e907b..b8056795e9 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -4193,9 +4193,6 @@ void Sema::EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD) CanonicalFPT, ExceptSpec); } -static bool isImplicitCopyCtorArgConst(Sema &S, CXXRecordDecl *ClassDecl); -static bool isImplicitCopyAssignmentArgConst(Sema &S, CXXRecordDecl *ClassDecl); - void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) { CXXRecordDecl *RD = MD->getParent(); CXXSpecialMember CSM = getSpecialMember(MD); @@ -4238,11 +4235,11 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) { Trivial = RD->hasTrivialDefaultConstructor(); break; case CXXCopyConstructor: - CanHaveConstParam = isImplicitCopyCtorArgConst(*this, RD); + CanHaveConstParam = RD->implicitCopyConstructorHasConstParam(); Trivial = RD->hasTrivialCopyConstructor(); break; case CXXCopyAssignment: - CanHaveConstParam = isImplicitCopyAssignmentArgConst(*this, RD); + CanHaveConstParam = RD->implicitCopyAssignmentHasConstParam(); Trivial = RD->hasTrivialCopyAssignment(); break; case CXXMoveConstructor: @@ -7727,76 +7724,6 @@ buildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T, return Result; } -/// Determine whether an implicit copy assignment operator for ClassDecl has a -/// const argument. -/// FIXME: It ought to be possible to store this on the record. -static bool isImplicitCopyAssignmentArgConst(Sema &S, - CXXRecordDecl *ClassDecl) { - if (ClassDecl->isInvalidDecl()) - return true; - - // C++ [class.copy]p10: - // If the class definition does not explicitly declare a copy - // assignment operator, one is declared implicitly. - // The implicitly-defined copy assignment operator 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, - // and - for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), - BaseEnd = ClassDecl->bases_end(); - Base != BaseEnd; ++Base) { - // We'll handle this below - if (S.getLangOpts().CPlusPlus0x && Base->isVirtual()) - continue; - - assert(!Base->getType()->isDependentType() && - "Cannot generate implicit members for class with dependent bases."); - CXXRecordDecl *BaseClassDecl = Base->getType()->getAsCXXRecordDecl(); - if (!S.LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const, false, 0)) - return false; - } - - // In C++11, the above citation has "or virtual" added - if (S.getLangOpts().CPlusPlus0x) { - for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(), - BaseEnd = ClassDecl->vbases_end(); - Base != BaseEnd; ++Base) { - assert(!Base->getType()->isDependentType() && - "Cannot generate implicit members for class with dependent bases."); - CXXRecordDecl *BaseClassDecl = Base->getType()->getAsCXXRecordDecl(); - if (!S.LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const, - false, 0)) - return false; - } - } - - // -- for all the nonstatic 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. - for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), - FieldEnd = ClassDecl->field_end(); - Field != FieldEnd; ++Field) { - QualType FieldType = S.Context.getBaseElementType(Field->getType()); - if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) - if (!S.LookupCopyingAssignment(FieldClassDecl, Qualifiers::Const, - false, 0)) - return false; - } - - // Otherwise, the implicitly declared copy assignment operator will - // have the form - // - // X& X::operator=(X&) - - return true; -} - Sema::ImplicitExceptionSpecification Sema::ComputeDefaultedCopyAssignmentExceptionSpec(CXXMethodDecl *MD) { CXXRecordDecl *ClassDecl = MD->getParent(); @@ -7868,7 +7795,7 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { QualType ArgType = Context.getTypeDeclType(ClassDecl); QualType RetType = Context.getLValueReferenceType(ArgType); - if (isImplicitCopyAssignmentArgConst(*this, ClassDecl)) + if (ClassDecl->implicitCopyAssignmentHasConstParam()) ArgType = ArgType.withConst(); ArgType = Context.getLValueReferenceType(ArgType); @@ -8580,70 +8507,6 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, } } -/// Determine whether an implicit copy constructor for ClassDecl has a const -/// argument. -/// FIXME: It ought to be possible to store this on the record. -static bool isImplicitCopyCtorArgConst(Sema &S, CXXRecordDecl *ClassDecl) { - if (ClassDecl->isInvalidDecl()) - return true; - - // C++ [class.copy]p5: - // The implicitly-declared copy constructor for a class X will - // have the form - // - // X::X(const X&) - // - // if - // -- each direct or virtual base class B of X has a copy - // constructor whose first parameter is of type const B& or - // const volatile B&, and - for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), - BaseEnd = ClassDecl->bases_end(); - Base != BaseEnd; ++Base) { - // Virtual bases are handled below. - if (Base->isVirtual()) - continue; - - CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - // FIXME: This lookup is wrong. If the copy ctor for a member or base is - // ambiguous, we should still produce a constructor with a const-qualified - // parameter. - if (!S.LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const)) - return false; - } - - for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(), - BaseEnd = ClassDecl->vbases_end(); - Base != BaseEnd; ++Base) { - CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - if (!S.LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const)) - return false; - } - - // -- for all the nonstatic 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&. - for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), - FieldEnd = ClassDecl->field_end(); - Field != FieldEnd; ++Field) { - QualType FieldType = S.Context.getBaseElementType(Field->getType()); - if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) { - if (!S.LookupCopyingConstructor(FieldClassDecl, Qualifiers::Const)) - return false; - } - } - - // Otherwise, the implicitly declared copy constructor will have - // the form - // - // X::X(X&) - - return true; -} - Sema::ImplicitExceptionSpecification Sema::ComputeDefaultedCopyCtorExceptionSpec(CXXMethodDecl *MD) { CXXRecordDecl *ClassDecl = MD->getParent(); @@ -8708,7 +8571,7 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( QualType ClassType = Context.getTypeDeclType(ClassDecl); QualType ArgType = ClassType; - bool Const = isImplicitCopyCtorArgConst(*this, ClassDecl); + bool Const = ClassDecl->implicitCopyConstructorHasConstParam(); if (Const) ArgType = ArgType.withConst(); ArgType = Context.getLValueReferenceType(ArgType); diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index c42944df63..751b989c4d 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -1120,6 +1120,10 @@ void ASTDeclReader::ReadCXXDefinitionData( Data.DeclaredCopyAssignment = Record[Idx++]; Data.DeclaredMoveAssignment = Record[Idx++]; Data.DeclaredDestructor = Record[Idx++]; + Data.ImplicitCopyConstructorHasConstParam = Record[Idx++]; + Data.ImplicitCopyAssignmentHasConstParam = Record[Idx++]; + Data.HasDeclaredCopyConstructorWithConstParam = Record[Idx++]; + Data.HasDeclaredCopyAssignmentWithConstParam = Record[Idx++]; Data.FailedImplicitMoveConstructor = Record[Idx++]; Data.FailedImplicitMoveAssignment = Record[Idx++]; diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 41665d8969..d57dba8be1 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -4611,6 +4611,10 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec Record.push_back(Data.DeclaredCopyAssignment); Record.push_back(Data.DeclaredMoveAssignment); Record.push_back(Data.DeclaredDestructor); + Record.push_back(Data.ImplicitCopyConstructorHasConstParam); + Record.push_back(Data.ImplicitCopyAssignmentHasConstParam); + Record.push_back(Data.HasDeclaredCopyConstructorWithConstParam); + Record.push_back(Data.HasDeclaredCopyAssignmentWithConstParam); Record.push_back(Data.FailedImplicitMoveConstructor); Record.push_back(Data.FailedImplicitMoveAssignment); // IsLambda bit is already saved. |