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 {
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
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())
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
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:
// 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:
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
// 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())
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.
// 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.
data().Conversions.addDecl(getASTContext(), Conversion);
}
}
-
+
return;
}
// 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.
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);
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:
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();
QualType ArgType = Context.getTypeDeclType(ClassDecl);
QualType RetType = Context.getLValueReferenceType(ArgType);
- if (isImplicitCopyAssignmentArgConst(*this, ClassDecl))
+ if (ClassDecl->implicitCopyAssignmentHasConstParam())
ArgType = ArgType.withConst();
ArgType = Context.getLValueReferenceType(ArgType);
}
}
-/// 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();
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);