Hi timurrrr,
These destructors are used by cl.exe to implement polymorphic delete[],
a language extension which we don't support (yet). However, we
are forced by the ABI to implement some support for them. This is
because cl.exe, when compiling delete[] with a parameter of pointer to
dynamic class type, will emit a call to the vector deleting destructor
via the vftable. Unless we implement the correct semantics for this
destructor, the wrong number of objects will be deleted and the wrong
memory address will be freed.
To begin with, place a reference to the vector deleting dtor in the
vtable (instead of the scalar deleting dtor), and emit the vector
deleting dtor as a weak alias of the scalar deleting dtor. This is
what cl.exe does when the TU does not contain a new[] expression for
that class type. We don't actually emit the definition of the vector
deleting dtor yet, that will be done in a later change.
http://llvm-reviews.chandlerc.com/D824
Files:
include/clang/Basic/ABI.h
lib/AST/ItaniumMangle.cpp
lib/AST/MicrosoftMangle.cpp
lib/AST/VTableBuilder.cpp
lib/CodeGen/CGCXX.cpp
lib/CodeGen/CGClass.cpp
lib/CodeGen/CGVTables.cpp
lib/CodeGen/CodeGenModule.cpp
lib/CodeGen/CodeGenModule.h
lib/CodeGen/MicrosoftCXXABI.cpp
test/CodeGenCXX/microsoft-abi-structors.cpp
test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp
Index: include/clang/Basic/ABI.h
===================================================================
--- include/clang/Basic/ABI.h
+++ include/clang/Basic/ABI.h
@@ -29,9 +29,10 @@
/// \brief C++ destructor types.
enum CXXDtorType {
- Dtor_Deleting, ///< Deleting dtor
- Dtor_Complete, ///< Complete object dtor
- Dtor_Base ///< Base object dtor
+ Dtor_Deleting, ///< Deleting dtor
+ Dtor_Complete, ///< Complete object dtor
+ Dtor_Base, ///< Base object dtor
+ Dtor_VectorDeleting ///< Vector deleting dtor
};
/// \brief A return adjustment.
Index: lib/AST/ItaniumMangle.cpp
===================================================================
--- lib/AST/ItaniumMangle.cpp
+++ lib/AST/ItaniumMangle.cpp
@@ -3071,6 +3071,8 @@
case Dtor_Base:
Out << "D2";
break;
+ case Dtor_VectorDeleting:
+ llvm_unreachable("Itanium ABI does not use vector deleting dtors");
}
}
Index: lib/AST/MicrosoftMangle.cpp
===================================================================
--- lib/AST/MicrosoftMangle.cpp
+++ lib/AST/MicrosoftMangle.cpp
@@ -570,6 +570,9 @@
void MicrosoftCXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
switch (T) {
+ case Dtor_VectorDeleting:
+ Out << "?_E";
+ return;
case Dtor_Deleting:
Out << "?_G";
return;
@@ -1188,8 +1191,8 @@
// ::= @ # structors (they have no declared return type)
if (IsStructor) {
if (isa<CXXDestructorDecl>(D) && D == Structor &&
- StructorType == Dtor_Deleting) {
- // The scalar deleting destructor takes an extra int argument.
+ (StructorType == Dtor_Deleting || StructorType == Dtor_VectorDeleting)){
+ // The deleting destructors take an extra int argument.
// However, the FunctionType generated has 0 arguments.
// FIXME: This is a temporary hack.
// Maybe should fix the FunctionType creation instead?
Index: lib/AST/VTableBuilder.cpp
===================================================================
--- lib/AST/VTableBuilder.cpp
+++ lib/AST/VTableBuilder.cpp
@@ -1304,7 +1304,7 @@
Components.push_back(VTableComponent::MakeCompleteDtor(DD));
Components.push_back(VTableComponent::MakeDeletingDtor(DD));
} else {
- // Add the scalar deleting destructor.
+ // Add the vector deleting destructor.
Components.push_back(VTableComponent::MakeDeletingDtor(DD));
}
} else {
@@ -1951,7 +1951,7 @@
if (IsComplete)
Out << "() [complete]";
else if (isMicrosoftABI())
- Out << "() [scalar deleting]";
+ Out << "() [vector deleting]";
else
Out << "() [deleting]";
@@ -2143,8 +2143,9 @@
IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Deleting))]
= MethodName + " [deleting]";
} else {
- IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Deleting))]
- = MethodName + " [scalar deleting]";
+ IndicesMap[VTables.getMethodVTableIndex(
+ GlobalDecl(DD, Dtor_VectorDeleting))]
+ = MethodName + " [vector deleting]";
}
} else {
IndicesMap[VTables.getMethodVTableIndex(MD)] = MethodName;
@@ -2276,9 +2277,9 @@
MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] =
getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting));
} else {
- // Add the scalar deleting destructor.
- MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] =
- getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting));
+ // Add the vector deleting destructor.
+ MethodVTableIndices[GlobalDecl(DD, Dtor_VectorDeleting)] =
+ getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_VectorDeleting));
}
} else {
MethodVTableIndices[MD] = getMethodVTableIndex(OverriddenMD);
@@ -2305,7 +2306,8 @@
MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++;
} else {
// Add the scalar deleting dtor.
- MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++;
+ MethodVTableIndices[GlobalDecl(DD, Dtor_VectorDeleting)] =
+ CurrentIndex++;
}
} else {
// Add the entry.
Index: lib/CodeGen/CGCXX.cpp
===================================================================
--- lib/CodeGen/CGCXX.cpp
+++ lib/CodeGen/CGCXX.cpp
@@ -136,6 +136,18 @@
if (llvm::GlobalValue::isWeakForLinker(TargetLinkage))
return true;
+ EmitDefinitionAsAlias(AliasDecl, TargetDecl);
+ return false;
+}
+
+/// Emit a definition as a global alias for another definition, unconditionally.
+/// Use this function with care as it can produce invalid aliases. Generally
+/// this function should be used only where there is an ABI requirement to emit
+/// an alias.
+void CodeGenModule::EmitDefinitionAsAlias(GlobalDecl AliasDecl,
+ GlobalDecl TargetDecl) {
+ llvm::GlobalValue::LinkageTypes Linkage = getFunctionLinkage(AliasDecl);
+
// Derive the type for the alias.
llvm::PointerType *AliasType
= getTypes().GetFunctionType(AliasDecl)->getPointerTo();
@@ -168,8 +180,6 @@
// Finally, set up the alias with its proper name and attributes.
SetCommonAttributes(cast<NamedDecl>(AliasDecl.getDecl()), Alias);
-
- return false;
}
void CodeGenModule::EmitCXXConstructors(const CXXConstructorDecl *D) {
@@ -263,6 +273,15 @@
if (dtorType == Dtor_Base && !TryEmitBaseDestructorAsAlias(dtor))
return;
+ // The Microsoft ABI requires that the vector deleting destructor
+ // be weak aliased to the scalar deleting destructor.
+ // TODO: emission of the vector deleting destructor (when required).
+ if (dtorType == Dtor_VectorDeleting) {
+ EmitDefinitionAsAlias(GlobalDecl(dtor, Dtor_VectorDeleting),
+ GlobalDecl(dtor, Dtor_Deleting));
+ return;
+ }
+
const CGFunctionInfo &fnInfo =
getTypes().arrangeCXXDestructor(dtor, dtorType);
Index: lib/CodeGen/CGClass.cpp
===================================================================
--- lib/CodeGen/CGClass.cpp
+++ lib/CodeGen/CGClass.cpp
@@ -1277,6 +1277,7 @@
// we'd introduce *two* handler blocks.
switch (DtorType) {
case Dtor_Deleting: llvm_unreachable("already handled deleting case");
+ case Dtor_VectorDeleting: llvm_unreachable("TODO");
case Dtor_Complete:
// Enter the cleanup scopes for virtual bases.
Index: lib/CodeGen/CGVTables.cpp
===================================================================
--- lib/CodeGen/CGVTables.cpp
+++ lib/CodeGen/CGVTables.cpp
@@ -554,7 +554,10 @@
GD = GlobalDecl(Component.getDestructorDecl(), Dtor_Complete);
break;
case VTableComponent::CK_DeletingDtorPointer:
- GD = GlobalDecl(Component.getDestructorDecl(), Dtor_Deleting);
+ GD = GlobalDecl(Component.getDestructorDecl(),
+ CGM.getTarget().getCXXABI().isMicrosoft()
+ ? Dtor_VectorDeleting
+ : Dtor_Deleting);
break;
}
Index: lib/CodeGen/CodeGenModule.cpp
===================================================================
--- lib/CodeGen/CodeGenModule.cpp
+++ lib/CodeGen/CodeGenModule.cpp
@@ -529,9 +529,14 @@
// In the Microsoft ABI, most destructor types are not emitted with the
// definition, and must be emitted on demand. Give these linkonce_odr
- // linkage.
+ // linkage, with the exception of vector deleting destructors, which get
+ // weak linkage because they may not necessarily be referenced in the
+ // translation unit which requires them to be emitted, and they may be
+ // overridden by other translation units.
if (getTarget().getCXXABI().isMicrosoft() && isa<CXXDestructorDecl>(D)) {
- if (GD.getDtorType() != Dtor_Base)
+ if (GD.getDtorType() == Dtor_VectorDeleting)
+ return llvm::Function::WeakAnyLinkage;
+ else if (GD.getDtorType() != Dtor_Base)
return llvm::Function::LinkOnceODRLinkage;
}
Index: lib/CodeGen/CodeGenModule.h
===================================================================
--- lib/CodeGen/CodeGenModule.h
+++ lib/CodeGen/CodeGenModule.h
@@ -1021,6 +1021,7 @@
bool TryEmitDefinitionAsAlias(GlobalDecl Alias, GlobalDecl Target);
bool TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D);
+ void EmitDefinitionAsAlias(GlobalDecl Alias, GlobalDecl Target);
void EmitNamespace(const NamespaceDecl *D);
void EmitLinkageSpec(const LinkageSpecDecl *D);
Index: lib/CodeGen/MicrosoftCXXABI.cpp
===================================================================
--- lib/CodeGen/MicrosoftCXXABI.cpp
+++ lib/CodeGen/MicrosoftCXXABI.cpp
@@ -263,16 +263,17 @@
// 'this' is already in place
// TODO: 'for base' flag
- if (Type == Dtor_Deleting) {
+ if (Type == Dtor_Deleting || Type == Dtor_VectorDeleting) {
// The deleting destructors take an implicit int parameter.
ArgTys.push_back(CGM.getContext().IntTy);
}
}
static bool IsDeletingDtor(GlobalDecl GD) {
const CXXMethodDecl* MD = cast<CXXMethodDecl>(GD.getDecl());
if (isa<CXXDestructorDecl>(MD)) {
- return GD.getDtorType() == Dtor_Deleting;
+ return GD.getDtorType() == Dtor_Deleting ||
+ GD.getDtorType() == Dtor_VectorDeleting;
}
return false;
}
@@ -371,9 +372,10 @@
// We have only one destructor in the vftable but can get both behaviors
// by passing an implicit bool parameter.
const CGFunctionInfo *FInfo
- = &CGM.getTypes().arrangeCXXDestructor(Dtor, Dtor_Deleting);
+ = &CGM.getTypes().arrangeCXXDestructor(Dtor, Dtor_VectorDeleting);
llvm::Type *Ty = CGF.CGM.getTypes().GetFunctionType(*FInfo);
- llvm::Value *Callee = CGF.BuildVirtualCall(Dtor, Dtor_Deleting, This, Ty);
+ llvm::Value *Callee
+ = CGF.BuildVirtualCall(Dtor, Dtor_VectorDeleting, This, Ty);
ASTContext &Context = CGF.getContext();
llvm::Value *ImplicitParam
Index: test/CodeGenCXX/microsoft-abi-structors.cpp
===================================================================
--- test/CodeGenCXX/microsoft-abi-structors.cpp
+++ test/CodeGenCXX/microsoft-abi-structors.cpp
@@ -246,6 +246,7 @@
// The emission of the ctor requires emission of the vtable and therefore
// of the other dtor forms, despite not being defined in this TU.
+// DTOR5: @"\01??_EA@bodyless_dtors@@UAEPAXI@Z" = alias weak void (%"struct.bodyless_dtors::A"*, i32)* @"\01??_GA@bodyless_dtors@@UAEPAXI@Z"
// DTOR5: define linkonce_odr x86_thiscallcc void @"\01??_GA@bodyless_dtors@@UAEPAXI@Z"(%"struct.bodyless_dtors::A"* %this, i32 %flags)
// DTORS: define linkonce_odr x86_thiscallcc void @"\01??_DA@bodyless_dtors@@UAE@XZ"(%"struct.bodyless_dtors::A"* %this)
Index: test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp
===================================================================
--- test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp
+++ test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp
@@ -37,10 +37,10 @@
struct C {
// CHECK-C: Vtable for 'C' (2 entries)
- // CHECK-C-NEXT: 0 | C::~C() [scalar deleting]
+ // CHECK-C-NEXT: 0 | C::~C() [vector deleting]
// CHECK-C-NEXT: 1 | void C::f()
// CHECK-C: VTable indices for 'C' (2 entries).
- // CHECK-C-NEXT: 0 | C::~C() [scalar deleting]
+ // CHECK-C-NEXT: 0 | C::~C() [vector deleting]
// CHECK-C-NEXT: 1 | void C::f()
// Never used, so doesn't emit a vtable.
virtual ~C();
@@ -52,7 +52,7 @@
struct D {
// CHECK-D: Vtable for 'D' (2 entries)
// CHECK-D-NEXT: 0 | void D::f()
- // CHECK-D-NEXT: 1 | D::~D() [scalar deleting]
+ // CHECK-D-NEXT: 1 | D::~D() [vector deleting]
// EMITS-VTABLE: @"\01??_7D@@6B@" = unnamed_addr constant [2 x i8*]
virtual void f();
@@ -65,10 +65,10 @@
// CHECK-E-NEXT: 0 | void A::f()
// CHECK-E-NEXT: 1 | void A::g()
// CHECK-E-NEXT: 2 | void A::h()
- // CHECK-E-NEXT: 3 | E::~E() [scalar deleting]
+ // CHECK-E-NEXT: 3 | E::~E() [vector deleting]
// CHECK-E-NEXT: 4 | void E::i()
// CHECK-E: VTable indices for 'E' (2 entries).
- // CHECK-E-NEXT: 3 | E::~E() [scalar deleting]
+ // CHECK-E-NEXT: 3 | E::~E() [vector deleting]
// CHECK-E-NEXT: 4 | void E::i()
// Never used, so doesn't emit a vtable.
@@ -83,10 +83,10 @@
// CHECK-F-NEXT: 1 | void A::g()
// CHECK-F-NEXT: 2 | void A::h()
// CHECK-F-NEXT: 3 | void F::i()
- // CHECK-F-NEXT: 4 | F::~F() [scalar deleting]
+ // CHECK-F-NEXT: 4 | F::~F() [vector deleting]
// CHECK-F: VTable indices for 'F' (2 entries).
// CHECK-F-NEXT: 3 | void F::i()
- // CHECK-F-NEXT: 4 | F::~F() [scalar deleting]
+ // CHECK-F-NEXT: 4 | F::~F() [vector deleting]
// EMITS-VTABLE: @"\01??_7F@@6B@" = unnamed_addr constant [5 x i8*]
virtual void i();
virtual ~F();
@@ -98,12 +98,12 @@
// CHECK-G-NEXT: 0 | void G::f()
// CHECK-G-NEXT: 1 | void A::g()
// CHECK-G-NEXT: 2 | void A::h()
- // CHECK-G-NEXT: 3 | G::~G() [scalar deleting]
+ // CHECK-G-NEXT: 3 | G::~G() [vector deleting]
// CHECK-G-NEXT: 4 | void E::i()
// CHECK-G-NEXT: 5 | void G::j()
// CHECK-G: VTable indices for 'G' (3 entries).
// CHECK-G-NEXT: 0 | void G::f()
- // CHECK-G-NEXT: 3 | G::~G() [scalar deleting]
+ // CHECK-G-NEXT: 3 | G::~G() [vector deleting]
// CHECK-G-NEXT: 5 | void G::j()
// Never used, so doesn't emit a vtable.
virtual void f(); // overrides A::f()
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits