[cfe-commits] r74205 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/Sema.h lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExpr.cpp
Douglas Gregor
dgregor at apple.com
Fri Jun 26 08:36:10 PDT 2009
On Jun 25, 2009, at 2:45 PM, Fariborz Jahanian wrote:
> 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
p10 :)
> + // 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();
> +}
If we encounter an error, we should set the MethodDecl to be invalid.
> +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;
> +}
Asserting here is just a temporary measure, right? Because it's
possible for one to find a deleted copy assignment operator (C++0x),
and it may also be possible to end up with an ambiguity (but I can't
come up with a test case, so I could be wrong about that).
Thanks, Fariborz!
- Doug
> 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)) {
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
More information about the cfe-commits
mailing list