[cfe-commits] r74205 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/Sema.h lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExpr.cpp
Fariborz Jahanian
fjahanian at apple.com
Thu Jun 25 14:45:19 PDT 2009
Author: fjahanian
Date: Thu Jun 25 16:45:19 2009
New Revision: 74205
URL: http://llvm.org/viewvc/llvm-project?rev=74205&view=rev
Log:
Patch to diagnose and Mark use of implicit default assignment operator.
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaExpr.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=74205&r1=74204&r2=74205&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Jun 25 16:45:19 2009
@@ -584,6 +584,12 @@
"%2 does not have any default constructor">;
def note_previous_class_decl : Note<
"%0 declared here">;
+def err_unintialized_member_for_assign : Error<
+ "cannot define the implicit default assignment operator for %0, because "
+ "non-static %select{reference|const}1 member %2 can't use default "
+ "assignment operator">;
+def note_first_required_here : Note<
+ "synthesized method is first required here">;
def err_unintialized_member : Error<
"cannot define the implicit default constructor for %0, because "
"%select{reference|const}1 member %2 cannot be default-initialized">;
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=74205&r1=74204&r2=74205&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Thu Jun 25 16:45:19 2009
@@ -1598,6 +1598,16 @@
void DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
CXXConstructorDecl *Constructor,
unsigned TypeQuals);
+
+ /// DefineImplicitOverloadedAssign - Checks for feasibility of
+ /// defining implicit this overloaded assignment operator.
+ void DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
+ CXXMethodDecl *MethodDecl);
+
+ /// getAssignOperatorMethod - Returns the default copy assignmment operator
+ /// for the class.
+ CXXMethodDecl *getAssignOperatorMethod(ParmVarDecl *Decl,
+ CXXRecordDecl *ClassDecl);
/// MaybeBindToTemporary - If the passed in expression has a record type with
/// a non-trivial destructor, this will return CXXBindTemporaryExpr. Otherwise
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=74205&r1=74204&r2=74205&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Thu Jun 25 16:45:19 2009
@@ -1942,6 +1942,94 @@
Constructor->setUsed();
}
+void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
+ CXXMethodDecl *MethodDecl) {
+ assert((MethodDecl->isImplicit() && MethodDecl->isOverloadedOperator() &&
+ MethodDecl->getOverloadedOperator() == OO_Equal &&
+ !MethodDecl->isUsed()) &&
+ "DefineImplicitOverloadedAssign - call it for implicit assignment op");
+
+ CXXRecordDecl *ClassDecl
+ = cast<CXXRecordDecl>(MethodDecl->getDeclContext());
+ assert(ClassDecl && "DefineImplicitOverloadedAssign - invalid constructor");
+
+ // C++[class.copy] p210
+ // Before the implicitly-declared copy assignment operator for a class is
+ // implicitly defined, all implicitly-declared copy assignment operators
+ // for its direct base classes and its nonstatic data members shall have
+ // been implicitly defined.
+ bool err = false;
+ for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin();
+ Base != ClassDecl->bases_end(); ++Base) {
+ CXXRecordDecl *BaseClassDecl
+ = cast<CXXRecordDecl>(Base->getType()->getAsRecordType()->getDecl());
+ if (CXXMethodDecl *BaseAssignOpMethod =
+ getAssignOperatorMethod(MethodDecl->getParamDecl(0), BaseClassDecl))
+ MarkDeclarationReferenced(CurrentLocation, BaseAssignOpMethod);
+ }
+ for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(Context);
+ Field != ClassDecl->field_end(Context);
+ ++Field) {
+ QualType FieldType = Context.getCanonicalType((*Field)->getType());
+ if (const ArrayType *Array = Context.getAsArrayType(FieldType))
+ FieldType = Array->getElementType();
+ if (const RecordType *FieldClassType = FieldType->getAsRecordType()) {
+ CXXRecordDecl *FieldClassDecl
+ = cast<CXXRecordDecl>(FieldClassType->getDecl());
+ if (CXXMethodDecl *FieldAssignOpMethod =
+ getAssignOperatorMethod(MethodDecl->getParamDecl(0), FieldClassDecl))
+ MarkDeclarationReferenced(CurrentLocation, FieldAssignOpMethod);
+ }
+ else if (FieldType->isReferenceType()) {
+ Diag(ClassDecl->getLocation(), diag::err_unintialized_member_for_assign)
+ << Context.getTagDeclType(ClassDecl) << 0 << (*Field)->getNameAsCString();
+ Diag((*Field)->getLocation(), diag::note_declared_at);
+ Diag(CurrentLocation, diag::note_first_required_here);
+ err = true;
+ }
+ else if (FieldType.isConstQualified()) {
+ Diag(ClassDecl->getLocation(), diag::err_unintialized_member_for_assign)
+ << Context.getTagDeclType(ClassDecl) << 1 << (*Field)->getNameAsCString();
+ Diag((*Field)->getLocation(), diag::note_declared_at);
+ Diag(CurrentLocation, diag::note_first_required_here);
+ err = true;
+ }
+ }
+ if (!err)
+ MethodDecl->setUsed();
+}
+
+CXXMethodDecl *
+Sema::getAssignOperatorMethod(ParmVarDecl *ParmDecl,
+ CXXRecordDecl *ClassDecl) {
+ QualType LHSType = Context.getTypeDeclType(ClassDecl);
+ QualType RHSType(LHSType);
+ // If class's assignment operator argument is const/volatile qualified,
+ // look for operator = (const/volatile B&). Otherwise, look for
+ // operator = (B&).
+ if (ParmDecl->getType().isConstQualified())
+ RHSType.addConst();
+ if (ParmDecl->getType().isVolatileQualified())
+ RHSType.addVolatile();
+ ExprOwningPtr<Expr> LHS(this, new (Context) DeclRefExpr(ParmDecl,
+ LHSType,
+ SourceLocation()));
+ ExprOwningPtr<Expr> RHS(this, new (Context) DeclRefExpr(ParmDecl,
+ RHSType,
+ SourceLocation()));
+ Expr *Args[2] = { &*LHS, &*RHS };
+ OverloadCandidateSet CandidateSet;
+ AddMemberOperatorCandidates(clang::OO_Equal, SourceLocation(), Args, 2,
+ CandidateSet);
+ OverloadCandidateSet::iterator Best;
+ if (BestViableFunction(CandidateSet,
+ ClassDecl->getLocation(), Best) == OR_Success)
+ return cast<CXXMethodDecl>(Best->Function);
+ assert(false &&
+ "getAssignOperatorMethod - copy assignment operator method not found");
+ return 0;
+}
+
void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
CXXConstructorDecl *CopyConstructor,
unsigned TypeQuals) {
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=74205&r1=74204&r2=74205&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Jun 25 16:45:19 2009
@@ -5547,7 +5547,13 @@
// FIXME: more checking for other implicits go here.
else
Constructor->setUsed(true);
- }
+ } else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(D)) {
+ if (MethodDecl->isImplicit() && MethodDecl->isOverloadedOperator() &&
+ MethodDecl->getOverloadedOperator() == OO_Equal) {
+ if (!MethodDecl->isUsed())
+ DefineImplicitOverloadedAssign(Loc, MethodDecl);
+ }
+ }
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
// Implicit instantiation of function templates
if (!Function->getBody(Context)) {
More information about the cfe-commits
mailing list