[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