diff options
author | Timur Iskhodzhanov <timurrrr@google.com> | 2014-08-10 11:40:51 +0000 |
---|---|---|
committer | Timur Iskhodzhanov <timurrrr@google.com> | 2014-08-10 11:40:51 +0000 |
commit | 16055e77b922695e2141b810a38508bc1aa00e0a (patch) | |
tree | 60b6caf7b87f51e6a4204aba0d16686c87d40678 /clang/lib/AST/VTableBuilder.cpp | |
parent | b696d460459e10c86d5edebddd420065a161cd5d (diff) | |
download | bcm5719-llvm-16055e77b922695e2141b810a38508bc1aa00e0a.tar.gz bcm5719-llvm-16055e77b922695e2141b810a38508bc1aa00e0a.zip |
Fix PR20444 -- wrong number of vftable slots created when return adjustment thunks are needed
Reviewed at http://reviews.llvm.org/D4822
llvm-svn: 215312
Diffstat (limited to 'clang/lib/AST/VTableBuilder.cpp')
-rw-r--r-- | clang/lib/AST/VTableBuilder.cpp | 58 |
1 files changed, 28 insertions, 30 deletions
diff --git a/clang/lib/AST/VTableBuilder.cpp b/clang/lib/AST/VTableBuilder.cpp index 42fafde4a5d..c03fb3244d0 100644 --- a/clang/lib/AST/VTableBuilder.cpp +++ b/clang/lib/AST/VTableBuilder.cpp @@ -2464,11 +2464,18 @@ private: /// or used for vcalls in the most derived class. bool Shadowed; - MethodInfo(uint64_t VBTableIndex, uint64_t VFTableIndex) + /// UsesExtraSlot - Indicates if this vftable slot was created because + /// any of the overridden slots required a return adjusting thunk. + bool UsesExtraSlot; + + MethodInfo(uint64_t VBTableIndex, uint64_t VFTableIndex, + bool UsesExtraSlot = false) : VBTableIndex(VBTableIndex), VFTableIndex(VFTableIndex), - Shadowed(false) {} + Shadowed(false), UsesExtraSlot(UsesExtraSlot) {} - MethodInfo() : VBTableIndex(0), VFTableIndex(0), Shadowed(false) {} + MethodInfo() + : VBTableIndex(0), VFTableIndex(0), Shadowed(false), + UsesExtraSlot(false) {} }; typedef llvm::DenseMap<const CXXMethodDecl *, MethodInfo> MethodInfoMapTy; @@ -2525,8 +2532,6 @@ private: } } - bool NeedsReturnAdjustingThunk(const CXXMethodDecl *MD); - /// AddMethods - Add the methods of this base subobject and the relevant /// subbases to the vftable we're currently laying out. void AddMethods(BaseSubobject Base, unsigned BaseDepth, @@ -2789,24 +2794,6 @@ static void GroupNewVirtualOverloads( VirtualMethods.append(Groups[I].rbegin(), Groups[I].rend()); } -/// We need a return adjusting thunk for this method if its return type is -/// not trivially convertible to the return type of any of its overridden -/// methods. -bool VFTableBuilder::NeedsReturnAdjustingThunk(const CXXMethodDecl *MD) { - OverriddenMethodsSetTy OverriddenMethods; - ComputeAllOverriddenMethods(MD, OverriddenMethods); - for (OverriddenMethodsSetTy::iterator I = OverriddenMethods.begin(), - E = OverriddenMethods.end(); - I != E; ++I) { - const CXXMethodDecl *OverriddenMD = *I; - BaseOffset Adjustment = - ComputeReturnAdjustmentBaseOffset(Context, MD, OverriddenMD); - if (!Adjustment.isEmpty()) - return true; - } - return false; -} - static bool isDirectVBase(const CXXRecordDecl *Base, const CXXRecordDecl *RD) { for (const auto &B : RD->bases()) { if (B.isVirtual() && B.getType()->getAsCXXRecordDecl() == Base) @@ -2873,7 +2860,7 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth, FindNearestOverriddenMethod(MD, VisitedBases); ThisAdjustment ThisAdjustmentOffset; - bool ReturnAdjustingThunk = false; + bool ReturnAdjustingThunk = false, ForceReturnAdjustmentMangling = false; CharUnits ThisOffset = ComputeThisOffset(Overrider); ThisAdjustmentOffset.NonVirtual = (ThisOffset - WhichVFPtr.FullOffsetInMDC).getQuantity(); @@ -2892,7 +2879,16 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth, MethodInfo &OverriddenMethodInfo = OverriddenMDIterator->second; - if (!NeedsReturnAdjustingThunk(MD)) { + // Let's check if the overrider requires any return adjustments. + // We must create a new slot if the MD's return type is not trivially + // convertible to the OverriddenMD's one. + // Once a chain of method overrides adds a return adjusting vftable slot, + // all subsequent overrides will also use an extra method slot. + ReturnAdjustingThunk = !ComputeReturnAdjustmentBaseOffset( + Context, MD, OverriddenMD).isEmpty() || + OverriddenMethodInfo.UsesExtraSlot; + + if (!ReturnAdjustingThunk) { // No return adjustment needed - just replace the overridden method info // with the current info. MethodInfo MI(OverriddenMethodInfo.VBTableIndex, @@ -2911,7 +2907,7 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth, // Force a special name mangling for a return-adjusting thunk // unless the method is the final overrider without this adjustment. - ReturnAdjustingThunk = + ForceReturnAdjustmentMangling = !(MD == OverriderMD && ThisAdjustmentOffset.isEmpty()); } else if (Base.getBaseOffset() != WhichVFPtr.FullOffsetInMDC || MD->size_overridden_methods()) { @@ -2926,7 +2922,8 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth, unsigned VBIndex = LastVBase ? VTables.getVBTableIndex(MostDerivedClass, LastVBase) : 0; MethodInfo MI(VBIndex, - HasRTTIComponent ? Components.size() - 1 : Components.size()); + HasRTTIComponent ? Components.size() - 1 : Components.size(), + ReturnAdjustingThunk); assert(!MethodInfoMap.count(MD) && "Should not have method info for this method yet!"); @@ -2941,7 +2938,7 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth, ComputeReturnAdjustmentBaseOffset(Context, OverriderMD, MD); } if (!ReturnAdjustmentOffset.isEmpty()) { - ReturnAdjustingThunk = true; + ForceReturnAdjustmentMangling = true; ReturnAdjustment.NonVirtual = ReturnAdjustmentOffset.NonVirtualOffset.getQuantity(); if (ReturnAdjustmentOffset.VirtualBase) { @@ -2955,8 +2952,9 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth, } } - AddMethod(OverriderMD, ThunkInfo(ThisAdjustmentOffset, ReturnAdjustment, - ReturnAdjustingThunk ? MD : nullptr)); + AddMethod(OverriderMD, + ThunkInfo(ThisAdjustmentOffset, ReturnAdjustment, + ForceReturnAdjustmentMangling ? MD : nullptr)); } } |