[cfe-commits] r131337 - in /cfe/trunk: include/clang/Sema/Sema.h lib/Sema/SemaDeclCXX.cpp

Sean Hunt scshunt at csclub.uwaterloo.ca
Fri May 13 22:23:24 PDT 2011


Author: coppro
Date: Sat May 14 00:23:24 2011
New Revision: 131337

URL: http://llvm.org/viewvc/llvm-project?rev=131337&view=rev
Log:
More progress towards defaulted copy assignment

Modified:
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=131337&r1=131336&r2=131337&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Sat May 14 00:23:24 2011
@@ -2610,6 +2610,10 @@
   /// deleted.
   bool ShouldDeleteCopyConstructor(CXXConstructorDecl *CD);
 
+  /// \brief Determine if a defaulted copy assignment operator ought to be
+  /// deleted.
+  bool ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD);
+
   /// \brief Determine if a defaulted destructor ought to be deleted.
   bool ShouldDeleteDestructor(CXXDestructorDecl *DD);
 

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=131337&r1=131336&r2=131337&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Sat May 14 00:23:24 2011
@@ -3552,6 +3552,193 @@
   return false;
 }
 
+bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) {
+  CXXRecordDecl *RD = MD->getParent();
+  assert(!RD->isDependentType() && "do deletion after instantiation");
+  if (!LangOpts.CPlusPlus0x)
+    return false;
+
+  // Do access control from the constructor
+  ContextRAII MethodContext(*this, MD);
+
+  bool Union = RD->isUnion();
+
+  bool ConstArg = MD->getParamDecl(0)->getType().isConstQualified();
+
+  // We do this because we should never actually use an anonymous
+  // union's constructor.
+  if (Union && RD->isAnonymousStructOrUnion())
+    return false;
+
+  DeclarationName OperatorName =
+    Context.DeclarationNames.getCXXOperatorName(OO_Equal);
+  LookupResult R(*this, OperatorName, SourceLocation(), LookupOrdinaryName);
+  R.suppressDiagnostics();
+
+  // FIXME: We should put some diagnostic logic right into this function.
+
+  // C++0x [class.copy]/11
+  //    A defaulted [copy] assignment operator for class X is defined as deleted
+  //    if X has:
+
+  for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(),
+                                          BE = RD->bases_end();
+       BI != BE; ++BI) {
+    // We'll handle this one later
+    if (BI->isVirtual())
+      continue;
+
+    QualType BaseType = BI->getType();
+    CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl();
+    assert(BaseDecl && "base isn't a CXXRecordDecl");
+
+    // -- a [direct base class] B that cannot be [copied] because overload
+    //    resolution, as applied to B's [copy] assignment operator, results in
+    //    an ambiguity or a function that is deleted or inaccessibl from the
+    //    assignment operator
+
+    LookupQualifiedName(R, BaseDecl, false);
+
+    // Filter out any result that isn't a copy-assignment operator.
+    LookupResult::Filter F = R.makeFilter();
+    while (F.hasNext()) {
+      NamedDecl *D = F.next();
+      if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
+        if (Method->isCopyAssignmentOperator())
+          continue;
+      
+      F.erase();
+    }
+    F.done();
+ 
+    // Build a fake argument expression
+    QualType ArgType = BaseType;
+    if (ConstArg)
+      ArgType.addConst();
+    Expr *Arg = new (Context) OpaqueValueExpr(SourceLocation(), ArgType,
+                                              VK_LValue);
+
+    OverloadCandidateSet OCS((SourceLocation()));
+    OverloadCandidateSet::iterator Best;
+
+    AddFunctionCandidates(R.asUnresolvedSet(), &Arg, 1, OCS);
+
+    if (OCS.BestViableFunction(*this, SourceLocation(), Best, false) !=
+        OR_Success)
+      return true;
+  }
+
+  for (CXXRecordDecl::base_class_iterator BI = RD->vbases_begin(),
+                                          BE = RD->vbases_end();
+       BI != BE; ++BI) {
+    QualType BaseType = BI->getType();
+    CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl();
+    assert(BaseDecl && "base isn't a CXXRecordDecl");
+
+    /*
+    // -- a [virtual base class] B that cannot be [copied] because overload
+    //    resolution, as applied to B's [copy] assignment operator, results in an
+    //    ambiguity or a function that is deleted or inaccessible from the
+    //    defaulted assignment operator
+    InitializedEntity BaseEntity =
+      InitializedEntity::InitializeBase(Context, BI, BI);
+    InitializationKind Kind =
+      InitializationKind::CreateDirect(SourceLocation(), SourceLocation(),
+                                       SourceLocation());
+
+    // Construct a fake expression to perform the copy overloading.
+    QualType ArgType = BaseType.getUnqualifiedType();
+    if (ArgType->isReferenceType())
+      ArgType = ArgType->getPointeeType();
+    if (ConstArg)
+      ArgType.addConst();
+    Expr *Arg = new (Context) OpaqueValueExpr(SourceLocation(), ArgType,
+                                              VK_LValue);
+
+    InitializationSequence InitSeq(*this, BaseEntity, Kind, &Arg, 1);
+
+    if (InitSeq.getKind() == InitializationSequence::FailedSequence)
+      return true;
+    */
+  }
+
+  for (CXXRecordDecl::field_iterator FI = RD->field_begin(),
+                                     FE = RD->field_end();
+       FI != FE; ++FI) {
+    QualType FieldType = Context.getBaseElementType(FI->getType());
+    
+    // -- a non-static data member of reference type
+    if (FieldType->isReferenceType())
+      return true;
+
+    // -- a non-static data member of const non-class type (or array thereof)
+    if (FieldType.isConstQualified() && !FieldType->isRecordType())
+      return true;
+ 
+    CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl();
+
+    if (FieldRecord) {
+      // This is an anonymous union
+      if (FieldRecord->isUnion() && FieldRecord->isAnonymousStructOrUnion()) {
+        // Anonymous unions inside unions do not variant members create
+        if (!Union) {
+          for (CXXRecordDecl::field_iterator UI = FieldRecord->field_begin(),
+                                             UE = FieldRecord->field_end();
+               UI != UE; ++UI) {
+            QualType UnionFieldType = Context.getBaseElementType(UI->getType());
+            CXXRecordDecl *UnionFieldRecord =
+              UnionFieldType->getAsCXXRecordDecl();
+
+            // -- a variant member with a non-trivial [copy] assignment operator
+            //    and X is a union-like class
+            if (UnionFieldRecord &&
+                !UnionFieldRecord->hasTrivialCopyAssignment())
+              return true;
+          }
+        }
+
+        // Don't try to initalize an anonymous union
+        continue;
+      // -- a variant member with a non-trivial [copy] assignment operator
+      //    and X is a union-like class
+      } else if (Union && !FieldRecord->hasTrivialCopyAssignment()) {
+          return true;
+      }
+    }
+
+    /*
+    llvm::SmallVector<InitializedEntity, 4> Entities;
+    QualType CurType = FI->getType();
+    Entities.push_back(InitializedEntity::InitializeMember(*FI, 0));
+    while (CurType->isArrayType()) {
+      Entities.push_back(InitializedEntity::InitializeElement(Context, 0, 
+                                                              Entities.back()));
+      CurType = Context.getAsArrayType(CurType)->getElementType();
+    }
+
+    InitializationKind Kind = 
+      InitializationKind::CreateDirect(SourceLocation(), SourceLocation(),
+                                       SourceLocation());
+ 
+    // Construct a fake expression to perform the copy overloading.
+    QualType ArgType = FieldType;
+    if (ArgType->isReferenceType())
+      ArgType = ArgType->getPointeeType();
+    if (ConstArg)
+      ArgType.addConst();
+    Expr *Arg = new (Context) OpaqueValueExpr(SourceLocation(), ArgType,
+                                              VK_LValue);
+   
+    InitializationSequence InitSeq(*this, Entities.back(), Kind, &Arg, 1);
+
+    if (InitSeq.getKind() == InitializationSequence::FailedSequence)
+      return true;
+    */
+  }
+
+  return false;
+}
+
 bool Sema::ShouldDeleteDestructor(CXXDestructorDecl *DD) {
   CXXRecordDecl *RD = DD->getParent();
   assert(!RD->isDependentType() && "do deletion after instantiation");
@@ -6383,6 +6570,7 @@
                             /*isInline=*/true,
                             SourceLocation());
   CopyAssignment->setAccess(AS_public);
+  CopyAssignment->setDefaulted();
   CopyAssignment->setImplicit();
   CopyAssignment->setTrivial(ClassDecl->hasTrivialCopyAssignment());
   
@@ -6397,6 +6585,9 @@
   // Note that we have added this copy-assignment operator.
   ++ASTContext::NumImplicitCopyAssignmentOperatorsDeclared;
   
+  if (ShouldDeleteCopyAssignmentOperator(CopyAssignment))
+    CopyAssignment->setDeletedAsWritten();
+
   if (Scope *S = getScopeForContext(ClassDecl))
     PushOnScopeChains(CopyAssignment, S, false);
   ClassDecl->addDecl(CopyAssignment);
@@ -6407,7 +6598,7 @@
 
 void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
                                         CXXMethodDecl *CopyAssignOperator) {
-  assert((CopyAssignOperator->isImplicit() && 
+  assert((CopyAssignOperator->isDefaulted() && 
           CopyAssignOperator->isOverloadedOperator() &&
           CopyAssignOperator->getOverloadedOperator() == OO_Equal &&
           !CopyAssignOperator->isUsed(false)) &&





More information about the cfe-commits mailing list