]> granicus.if.org Git - clang/commitdiff
More work on the final overriders.
authorAnders Carlsson <andersca@mac.com>
Fri, 12 Feb 2010 01:40:03 +0000 (01:40 +0000)
committerAnders Carlsson <andersca@mac.com>
Fri, 12 Feb 2010 01:40:03 +0000 (01:40 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@95954 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGVtable.cpp

index 51c76af628cd936d83916413677b6e3e7f31a645..eeee22c275e7e183e160a5385209df7ade90138b 100644 (file)
@@ -120,14 +120,49 @@ class FinalOverriders {
   /// all the base subobjects of the most derived class.
   OverridersMapTy OverridersMap;
   
+  typedef llvm::SmallVector<uint64_t, 1> OffsetVectorTy;
+  
+  /// SubobjectOffsetsMapTy - This map is used for keeping track of all the
+  /// base subobject offsets that a single class declaration might refer to.
+  ///
+  /// For example, in:
+  ///
+  /// struct A { virtual void f(); };
+  /// struct B1 : A { };
+  /// struct B2 : A { };
+  /// struct C : B1, B2 { virtual void f(); };
+  ///
+  /// when we determine that C::f() overrides A::f(), we need to update the
+  /// overriders map for both A-in-B1 and A-in-B2 and the subobject offsets map
+  /// will have the subobject offsets for both A copies.
+  typedef llvm::DenseMap<const CXXRecordDecl *, OffsetVectorTy>
+    SubobjectOffsetsMapTy;
+  
   /// ComputeFinalOverriders - Compute the final overriders for a given base
   /// subobject (and all its direct and indirect bases).
-  void ComputeFinalOverriders(BaseSubobject Base);
+  void ComputeFinalOverriders(BaseSubobject Base,
+                              SubobjectOffsetsMapTy &Offsets);
   
   /// AddOverriders - Add the final overriders for this base subobject to the
   /// map of final overriders.  
-  void AddOverriders(BaseSubobject Base);
-  
+  void AddOverriders(BaseSubobject Base, SubobjectOffsetsMapTy &Offsets);
+
+  /// PropagateOverrider - Propagate the NewMD overrider to all the functions 
+  /// that OldMD overrides. For example, if we have:
+  ///
+  /// struct A { virtual void f(); };
+  /// struct B : A { virtual void f(); };
+  /// struct C : B { virtual void f(); };
+  ///
+  /// and we want to override B::f with C::f, we also need to override A::f with
+  /// C::f.
+  void PropagateOverrider(const CXXMethodDecl *OldMD,
+                          const CXXMethodDecl *NewMD,
+                          SubobjectOffsetsMapTy &Offsets);
+  
+  static void MergeSubobjectOffsets(const SubobjectOffsetsMapTy &NewOffsets,
+                                    SubobjectOffsetsMapTy &Offsets);
+
 public:
   explicit FinalOverriders(const CXXRecordDecl *MostDerivedClass);
   
@@ -157,13 +192,15 @@ FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass)
   MostDerivedClassLayout(Context.getASTRecordLayout(MostDerivedClass)) {
     
   // Compute the final overriders.
-  ComputeFinalOverriders(BaseSubobject(MostDerivedClass, 0));
+  SubobjectOffsetsMapTy Offsets;
+  ComputeFinalOverriders(BaseSubobject(MostDerivedClass, 0), Offsets);
     
   // And dump them (for now).
   dump();
 }
 
-void FinalOverriders::AddOverriders(BaseSubobject Base) {
+void FinalOverriders::AddOverriders(BaseSubobject Base,
+                                    SubobjectOffsetsMapTy &Offsets) {
   const CXXRecordDecl *RD = Base.getBase();
 
   for (CXXRecordDecl::method_iterator I = RD->method_begin(), 
@@ -173,7 +210,10 @@ void FinalOverriders::AddOverriders(BaseSubobject Base) {
     if (!MD->isVirtual())
       continue;
 
-    // Add the overrider.
+    // First, propagate the overrider.
+    PropagateOverrider(MD, MD, Offsets);
+
+    // Add the overrider as the final overrider of itself.
     const CXXMethodDecl *&Overrider = OverridersMap[std::make_pair(Base, MD)];
     assert(!Overrider && "Overrider should not exist yet!");
 
@@ -181,12 +221,92 @@ void FinalOverriders::AddOverriders(BaseSubobject Base) {
   }
 }
 
-void FinalOverriders::ComputeFinalOverriders(BaseSubobject Base) {
+void FinalOverriders::PropagateOverrider(const CXXMethodDecl *OldMD,
+                                         const CXXMethodDecl *NewMD,
+                                         SubobjectOffsetsMapTy &Offsets) {
+  for (CXXMethodDecl::method_iterator I = OldMD->begin_overridden_methods(),
+       E = OldMD->end_overridden_methods(); I != E; ++I) {
+    const CXXMethodDecl *OverriddenMD = *I;
+    const CXXRecordDecl *OverriddenRD = OverriddenMD->getParent();
+
+    // We want to override OverriddenMD in all subobjects, for example:
+    //
+    /// struct A { virtual void f(); };
+    /// struct B1 : A { };
+    /// struct B2 : A { };
+    /// struct C : B1, B2 { virtual void f(); };
+    ///
+    /// When overriding A::f with C::f we need to do so in both A subobjects.
+    const OffsetVectorTy &OffsetVector = Offsets[OverriddenRD];
+    
+    // Go through all the subobjects.
+    for (unsigned I = 0, E = OffsetVector.size(); I != E; ++I) {
+      uint64_t Offset = OffsetVector[I];
+
+      const CXXMethodDecl *&Overrider = 
+          OverridersMap[std::make_pair(BaseSubobject(OverriddenRD, Offset),
+                                       OverriddenMD)];
+      assert(Overrider && "Did not find existing overrider!");
+
+      // Set the new overrider.
+      Overrider = NewMD;
+      
+      // And propagate it further.
+      PropagateOverrider(OverriddenMD, NewMD, Offsets);
+    }
+  }
+}
+
+void 
+FinalOverriders::MergeSubobjectOffsets(const SubobjectOffsetsMapTy &NewOffsets,
+                                       SubobjectOffsetsMapTy &Offsets) {
+  // Iterate over the new offsets.
+  for (SubobjectOffsetsMapTy::const_iterator I = NewOffsets.begin(),
+       E = NewOffsets.end(); I != E; ++I) {
+    const CXXRecordDecl *NewRD = I->first;
+    const OffsetVectorTy& NewOffsetsVector = I->second;
+    
+    OffsetVectorTy &OffsetsVector = Offsets[NewRD];
+    if (OffsetsVector.empty()) {
+      // There were no previous offsets in this vector, just insert all entries
+      // from the new offsets vector.
+      OffsetsVector.append(NewOffsetsVector.begin(), NewOffsetsVector.end());
+      continue;
+    }
+    
+    assert(false && "FIXME: Handle merging the subobject offsets!");
+  }
+}
+
+void FinalOverriders::ComputeFinalOverriders(BaseSubobject Base,
+                                             SubobjectOffsetsMapTy &Offsets) {
   const CXXRecordDecl *RD = Base.getBase();
-  if (RD->getNumBases())
-    assert(false && "FIXME: Handle bases!");
+  const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+  
+  SubobjectOffsetsMapTy NewOffsets;
+  
+  for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+       E = RD->bases_end(); I != E; ++I) {
+    const CXXRecordDecl *BaseDecl = 
+      cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+    
+    assert(!I->isVirtual() && "FIXME: Handle virtual bases!");
+
+    uint64_t BaseOffset = Layout.getBaseClassOffset(BaseDecl) + 
+      Base.getBaseOffset();
+
+    // Compute the final overriders for this base.
+    ComputeFinalOverriders(BaseSubobject(BaseDecl, BaseOffset), NewOffsets);
+  }
+
+  /// Now add the overriders for this particular subobject.
+  AddOverriders(Base, NewOffsets);
   
-  AddOverriders(Base);
+  // And merge the newly discovered subobject offsets.
+  MergeSubobjectOffsets(NewOffsets, Offsets);
+
+  /// Finally, add the offset for our own subobject.
+  Offsets[RD].push_back(Base.getBaseOffset());
 }
 
 void FinalOverriders::dump(llvm::raw_ostream &Out, BaseSubobject Base) const {