Centralize the handling of
CXXRecordDecl::DefinitionData::DeclaredCopyAssignment, for
copy-assignment operators. Another step toward <rdar://problem/8459981>.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@114899 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index da32239..be5ec06 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -406,13 +406,12 @@
friend class DeclContext;
- /// \brief Notify the class that another constructor has
- /// been added.
+ /// \brief Notify the class that member has been added.
///
/// This routine helps maintain information about the class based on which
- /// constructors have been added. It will be invoked by DeclContext::addDecl()
- /// whenever a constructor is added to this record.
- void addedConstructor(CXXConstructorDecl *ConDecl);
+ /// members have been added. It will be invoked by DeclContext::addDecl()
+ /// whenever a member is added to this record.
+ void addedMember(Decl *D);
protected:
CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
@@ -610,11 +609,6 @@
return data().DeclaredCopyConstructor;
}
- /// addedAssignmentOperator - Notify the class that another assignment
- /// operator has been added. This routine helps maintain information about the
- /// class based on which operators have been added.
- void addedAssignmentOperator(ASTContext &Context, CXXMethodDecl *OpDecl);
-
/// hasUserDeclaredCopyAssignment - Whether this class has a
/// user-declared copy assignment operator. When false, a copy
/// assigment operator will be implicitly declared.
@@ -630,12 +624,6 @@
return data().DeclaredCopyAssignment;
}
- /// \brief Note whether this class has already had its copy assignment
- /// operator declared.
- void setDeclaredCopyAssignment(bool DCA) {
- data().DeclaredCopyAssignment = DCA;
- }
-
/// hasUserDeclaredDestructor - Whether this class has a
/// user-declared destructor. When false, a destructor will be
/// implicitly declared.
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 207edde..26ab925 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -778,14 +778,11 @@
} else {
FirstDecl = LastDecl = D;
}
-
- if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(this)) {
- Decl *InnerD = D;
- if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D))
- InnerD = FunTmpl->getTemplatedDecl();
- if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(InnerD))
- Record->addedConstructor(Constructor);
- }
+
+ // Notify a C++ record declaration that we've added a member, so it can
+ // update it's class-specific state.
+ if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(this))
+ Record->addedMember(D);
}
void DeclContext::addDecl(Decl *D) {
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index ffdb98d..1b89ab6 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -259,101 +259,128 @@
}
void
-CXXRecordDecl::addedConstructor(CXXConstructorDecl *Constructor) {
- // Ignore friends.
- if (Constructor->getFriendObjectKind())
+CXXRecordDecl::addedMember(Decl *D) {
+ // Ignore friends and invalid declarations.
+ if (D->getFriendObjectKind() || D->isInvalidDecl())
return;
- if (Constructor->isImplicit()) {
- // If this is the implicit default constructor, note that we have now
- // declared it.
- if (Constructor->isDefaultConstructor())
- data().DeclaredDefaultConstructor = true;
- // If this is the implicit copy constructor, note that we have now
- // declared it.
- else if (Constructor->isCopyConstructor())
+ FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D);
+ if (FunTmpl)
+ D = FunTmpl->getTemplatedDecl();
+
+ if (D->isImplicit()) {
+ if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
+ // If this is the implicit default constructor, note that we have now
+ // declared it.
+ 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;
+ }
+ // FIXME: Destructors
+ else 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) {
+ data().DeclaredCopyAssignment = true;
+ Method->setCopyAssignment(true);
+ }
+ }
+
+ // Nothing else to do for implicitly-declared members.
+ return;
+ }
+
+ // Handle (user-declared) constructors.
+ if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
+ // Note that we have a user-declared constructor.
+ data().UserDeclaredConstructor = true;
+
+ // Note that we have no need of an implicitly-declared default constructor.
+ data().DeclaredDefaultConstructor = true;
+
+ // C++ [dcl.init.aggr]p1:
+ // An aggregate is an array or a class (clause 9) with no
+ // user-declared constructors (12.1) [...].
+ data().Aggregate = false;
+
+ // C++ [class]p4:
+ // A POD-struct is an aggregate class [...]
+ data().PlainOldData = false;
+
+ // C++ [class.ctor]p5:
+ // A constructor is trivial if it is an implicitly-declared default
+ // constructor.
+ // FIXME: C++0x: don't do this for "= default" default constructors.
+ data().HasTrivialConstructor = false;
+
+ // Note when we have a user-declared copy constructor, which will
+ // suppress the implicit declaration of a copy constructor.
+ if (!FunTmpl && Constructor->isCopyConstructor()) {
+ data().UserDeclaredCopyConstructor = true;
data().DeclaredCopyConstructor = true;
+
+ // C++ [class.copy]p6:
+ // A copy constructor is trivial if it is implicitly declared.
+ // FIXME: C++0x: don't do this for "= default" copy constructors.
+ data().HasTrivialCopyConstructor = false;
+ }
- // Nothing else to do for implicitly-declared constructors.
return;
}
+
+ // FIXME: Destructors.
- // Note that we have a user-declared constructor.
- data().UserDeclaredConstructor = true;
-
- // Note that we have no need of an implicitly-declared default constructor.
- data().DeclaredDefaultConstructor = true;
-
- // C++ [dcl.init.aggr]p1:
- // An aggregate is an array or a class (clause 9) with no
- // user-declared constructors (12.1) [...].
- data().Aggregate = false;
-
- // C++ [class]p4:
- // A POD-struct is an aggregate class [...]
- data().PlainOldData = false;
-
- // C++ [class.ctor]p5:
- // A constructor is trivial if it is an implicitly-declared default
- // constructor.
- // FIXME: C++0x: don't do this for "= default" default constructors.
- data().HasTrivialConstructor = false;
-
- // Note when we have a user-declared copy constructor, which will
- // suppress the implicit declaration of a copy constructor.
- if (!Constructor->getDescribedFunctionTemplate() &&
- Constructor->isCopyConstructor()) {
- data().UserDeclaredCopyConstructor = true;
- data().DeclaredCopyConstructor = true;
+ 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 ArgType = FnType->getArgType(0);
+ if (const LValueReferenceType *Ref =ArgType->getAs<LValueReferenceType>())
+ ArgType = Ref->getPointeeType();
+
+ ArgType = ArgType.getUnqualifiedType();
+ QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(
+ const_cast<CXXRecordDecl*>(this)));
+
+ if (!Context.hasSameUnqualifiedType(ClassType, ArgType))
+ return;
+
+ // This is a copy assignment operator.
+ // Note on the decl that it is a copy assignment operator.
+ Method->setCopyAssignment(true);
+
+ // Suppress the implicit declaration of a copy constructor.
+ data().UserDeclaredCopyAssignment = true;
+ data().DeclaredCopyAssignment = true;
+
+ // C++ [class.copy]p11:
+ // A copy assignment operator is trivial if it is implicitly declared.
+ // FIXME: C++0x: don't do this for "= default" copy operators.
+ data().HasTrivialCopyAssignment = false;
+
+ // C++ [class]p4:
+ // A POD-struct is an aggregate class that [...] has no user-defined copy
+ // assignment operator [...].
+ data().PlainOldData = false;
+ }
- // C++ [class.copy]p6:
- // A copy constructor is trivial if it is implicitly declared.
- // FIXME: C++0x: don't do this for "= default" copy constructors.
- data().HasTrivialCopyConstructor = false;
+ return;
}
}
-void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context,
- CXXMethodDecl *OpDecl) {
- // We're interested specifically in copy assignment operators.
- const FunctionProtoType *FnType = OpDecl->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 (OpDecl->getPrimaryTemplate() || OpDecl->getDescribedFunctionTemplate())
- return;
-
- QualType ArgType = FnType->getArgType(0);
- if (const LValueReferenceType *Ref = ArgType->getAs<LValueReferenceType>())
- ArgType = Ref->getPointeeType();
-
- ArgType = ArgType.getUnqualifiedType();
- QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(
- const_cast<CXXRecordDecl*>(this)));
-
- if (!Context.hasSameUnqualifiedType(ClassType, ArgType))
- return;
-
- // This is a copy assignment operator.
- // Note on the decl that it is a copy assignment operator.
- OpDecl->setCopyAssignment(true);
-
- // Suppress the implicit declaration of a copy constructor.
- data().UserDeclaredCopyAssignment = true;
- data().DeclaredCopyAssignment = true;
-
- // C++ [class.copy]p11:
- // A copy assignment operator is trivial if it is implicitly declared.
- // FIXME: C++0x: don't do this for "= default" copy operators.
- data().HasTrivialCopyAssignment = false;
-
- // C++ [class]p4:
- // A POD-struct is an aggregate class that [...] has no user-defined copy
- // assignment operator [...].
- data().PlainOldData = false;
-}
-
static CanQualType GetConversionType(ASTContext &Context, NamedDecl *Conv) {
QualType T;
if (isa<UsingShadowDecl>(Conv))
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 48e36a9..48beca7 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -544,7 +544,9 @@
if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(D))
return CD->isCopyConstructor();
- return D->isCopyAssignment();
+ if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
+ return Method->isCopyAssignmentOperator();
+ return false;
}
bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const {
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 025ac3b..92655da 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -4942,7 +4942,6 @@
CopyAssignment->setParams(&FromParam, 1);
// Note that we have added this copy-assignment operator.
- ClassDecl->setDeclaredCopyAssignment(true);
++ASTContext::NumImplicitCopyAssignmentOperatorsDeclared;
if (Scope *S = getScopeForContext(ClassDecl))
@@ -5952,15 +5951,6 @@
<< LastParam->getType() << (Op == OO_MinusMinus);
}
- // Notify the class if it got an assignment operator.
- if (Op == OO_Equal) {
- // Would have returned earlier otherwise.
- assert(isa<CXXMethodDecl>(FnDecl) &&
- "Overloaded = not member, but not filtered.");
- CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl);
- Method->getParent()->addedAssignmentOperator(Context, Method);
- }
-
return false;
}