r232318 - MS ABI: Don't use qualified pointee types for 'catch' EH TypeDescriptors

David Majnemer david.majnemer at gmail.com
Sun Mar 15 00:10:01 PDT 2015


Author: majnemer
Date: Sun Mar 15 02:10:01 2015
New Revision: 232318

URL: http://llvm.org/viewvc/llvm-project?rev=232318&view=rev
Log:
MS ABI: Don't use qualified pointee types for 'catch' EH TypeDescriptors

Qualifiers are located next to the TypeDescriptor in order to properly
ensure that a pointer type can only be caught by a more qualified catch
handler.  This means that a catch handler of type 'const int *' requires
an RTTI object for 'int *'.  We got this correct for 'throw' but not for
'catch'.

N.B.  We don't currently have the means to store the qualifiers because
LLVM's EH strategy is tailored to the Itanium scheme.  The Itanium ABI
stores qualifiers inside the type descriptor in such a way that the
manner of qualification is stored in addition to the pointee type's
descriptor.  Perhaps the best way of modeling this for the MS ABI is
using an aggregate type to bundle the qualifiers with the descriptor?
This is tricky because we want to make it clear to the optimization
passes which catch handlers invalidate other handlers.

My current thoughts on a design for this is along the lines of:
  { { TypeDescriptor* TD, i32 QualifierFlags }, i32 MiscFlags }

The idea is that the inner most aggregate is all that is needed to
communicate that one catch handler might supercede another.  The
'MiscFlags' field would be used to hold the bitpattern for the notion
that the 'catch' handler does not need to invoke a copy-constructor
because we are catching by reference.

Modified:
    cfe/trunk/lib/CodeGen/CGCXXABI.h
    cfe/trunk/lib/CodeGen/CodeGenModule.cpp
    cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
    cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
    cfe/trunk/test/CodeGenCXX/microsoft-abi-try-throw.cpp

Modified: cfe/trunk/lib/CodeGen/CGCXXABI.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.h?rev=232318&r1=232317&r2=232318&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXXABI.h (original)
+++ cfe/trunk/lib/CodeGen/CGCXXABI.h Sun Mar 15 02:10:01 2015
@@ -224,7 +224,7 @@ public:
   emitTerminateForUnexpectedException(CodeGenFunction &CGF,
                                       llvm::Value *Exn);
 
-  virtual llvm::Constant *getAddrOfRTTIDescriptor(QualType Ty) = 0;
+  virtual llvm::Constant *getAddrOfRTTIDescriptor(QualType Ty, bool ForEH) = 0;
 
   virtual bool shouldTypeidBeNullChecked(bool IsDeref,
                                          QualType SrcRecordTy) = 0;

Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=232318&r1=232317&r2=232318&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Sun Mar 15 02:10:01 2015
@@ -3656,7 +3656,7 @@ llvm::Constant *CodeGenModule::GetAddrOf
       LangOpts.ObjCRuntime.isGNUFamily())
     return ObjCRuntime->GetEHType(Ty);
 
-  return getCXXABI().getAddrOfRTTIDescriptor(Ty);
+  return getCXXABI().getAddrOfRTTIDescriptor(Ty, ForEH);
 }
 
 void CodeGenModule::EmitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D) {

Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=232318&r1=232317&r2=232318&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Sun Mar 15 02:10:01 2015
@@ -125,7 +125,7 @@ public:
 
   void EmitFundamentalRTTIDescriptor(QualType Type);
   void EmitFundamentalRTTIDescriptors();
-  llvm::Constant *getAddrOfRTTIDescriptor(QualType Ty) override;
+  llvm::Constant *getAddrOfRTTIDescriptor(QualType Ty, bool ForEH) override;
 
   bool shouldTypeidBeNullChecked(bool IsDeref, QualType SrcRecordTy) override;
   void EmitBadTypeidCall(CodeGenFunction &CGF) override;
@@ -3101,7 +3101,8 @@ ItaniumRTTIBuilder::BuildPointerToMember
       ItaniumRTTIBuilder(CXXABI).BuildTypeInfo(QualType(ClassType, 0)));
 }
 
-llvm::Constant *ItaniumCXXABI::getAddrOfRTTIDescriptor(QualType Ty) {
+llvm::Constant *ItaniumCXXABI::getAddrOfRTTIDescriptor(QualType Ty,
+                                                       bool ForEH) {
   return ItaniumRTTIBuilder(*this).BuildTypeInfo(Ty);
 }
 

Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=232318&r1=232317&r2=232318&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Sun Mar 15 02:10:01 2015
@@ -83,7 +83,7 @@ public:
   llvm::GlobalVariable *getMSCompleteObjectLocator(const CXXRecordDecl *RD,
                                                    const VPtrInfo *Info);
 
-  llvm::Constant *getAddrOfRTTIDescriptor(QualType Ty) override;
+  llvm::Constant *getAddrOfRTTIDescriptor(QualType Ty, bool ForEH) override;
 
   bool shouldTypeidBeNullChecked(bool IsDeref, QualType SrcRecordTy) override;
   void EmitBadTypeidCall(CodeGenFunction &CGF) override;
@@ -3094,7 +3094,8 @@ MSRTTIBuilder::getBaseClassDescriptor(co
   // Initialize the BaseClassDescriptor.
   llvm::Constant *Fields[] = {
       ABI.getImageRelativeConstant(
-          ABI.getAddrOfRTTIDescriptor(Context.getTypeDeclType(Class.RD))),
+          ABI.getAddrOfRTTIDescriptor(Context.getTypeDeclType(Class.RD),
+                                      /*ForEH=*/false)),
       llvm::ConstantInt::get(CGM.IntTy, Class.NumBases),
       llvm::ConstantInt::get(CGM.IntTy, Class.OffsetInVBase),
       llvm::ConstantInt::get(CGM.IntTy, VBPtrOffset),
@@ -3154,11 +3155,53 @@ MSRTTIBuilder::getCompleteObjectLocator(
   return COL;
 }
 
+static QualType decomposeTypeForEH(ASTContext &Context, QualType T,
+                                   bool &IsConst, bool &IsVolatile) {
+  T = Context.getExceptionObjectType(T);
+
+  // C++14 [except.handle]p3:
+  //   A handler is a match for an exception object of type E if [...]
+  //     - the handler is of type cv T or const T& where T is a pointer type and
+  //       E is a pointer type that can be converted to T by [...]
+  //         - a qualification conversion
+  IsConst = false;
+  IsVolatile = false;
+  QualType PointeeType = T->getPointeeType();
+  if (!PointeeType.isNull()) {
+    IsConst = PointeeType.isConstQualified();
+    IsVolatile = PointeeType.isVolatileQualified();
+  }
+
+  // Member pointer types like "const int A::*" are represented by having RTTI
+  // for "int A::*" and separately storing the const qualifier.
+  if (const auto *MPTy = T->getAs<MemberPointerType>())
+    T = Context.getMemberPointerType(PointeeType.getUnqualifiedType(),
+                                     MPTy->getClass());
+
+  // Pointer types like "const int * const *" are represented by having RTTI
+  // for "const int **" and separately storing the const qualifier.
+  if (T->isPointerType())
+    T = Context.getPointerType(PointeeType.getUnqualifiedType());
+
+  return T;
+}
+
 /// \brief Gets a TypeDescriptor.  Returns a llvm::Constant * rather than a
 /// llvm::GlobalVariable * because different type descriptors have different
 /// types, and need to be abstracted.  They are abstracting by casting the
 /// address to an Int8PtrTy.
-llvm::Constant *MicrosoftCXXABI::getAddrOfRTTIDescriptor(QualType Type) {
+llvm::Constant *MicrosoftCXXABI::getAddrOfRTTIDescriptor(QualType Type,
+                                                         bool ForEH) {
+  // TypeDescriptors for exceptions never has qualified pointer types,
+  // qualifiers are stored seperately in order to support qualification
+  // conversions.
+  if (ForEH) {
+    // FIXME: This is only a 50% solution, we need to actually do something with
+    // these qualifiers.
+    bool IsConst, IsVolatile;
+    Type = decomposeTypeForEH(getContext(), Type, IsConst, IsVolatile);
+  }
+
   SmallString<256> MangledName, TypeInfoString;
   {
     llvm::raw_svector_ostream Out(MangledName);
@@ -3374,7 +3417,8 @@ llvm::Constant *MicrosoftCXXABI::getCatc
 
   // The TypeDescriptor is used by the runtime to determine if a catch handler
   // is appropriate for the exception object.
-  llvm::Constant *TD = getImageRelativeConstant(getAddrOfRTTIDescriptor(T));
+  llvm::Constant *TD =
+      getImageRelativeConstant(getAddrOfRTTIDescriptor(T, /*ForEH=*/true));
 
   // The runtime is responsible for calling the copy constructor if the
   // exception is caught by value.
@@ -3551,30 +3595,8 @@ llvm::GlobalVariable *MicrosoftCXXABI::g
 }
 
 llvm::GlobalVariable *MicrosoftCXXABI::getThrowInfo(QualType T) {
-  T = getContext().getExceptionObjectType(T);
-
-  // C++14 [except.handle]p3:
-  //   A handler is a match for an exception object of type E if [...]
-  //     - the handler is of type cv T or const T& where T is a pointer type and
-  //       E is a pointer type that can be converted to T by [...]
-  //         - a qualification conversion
-  bool IsConst = false, IsVolatile = false;
-  QualType PointeeType = T->getPointeeType();
-  if (!PointeeType.isNull()) {
-    IsConst = PointeeType.isConstQualified();
-    IsVolatile = PointeeType.isVolatileQualified();
-  }
-
-  // Member pointer types like "const int A::*" are represented by having RTTI
-  // for "int A::*" and separately storing the const qualifier.
-  if (const auto *MPTy = T->getAs<MemberPointerType>())
-    T = getContext().getMemberPointerType(PointeeType.getUnqualifiedType(),
-                                          MPTy->getClass());
-
-  // Pointer types like "const int * const *" are represented by having RTTI
-  // for "const int **" and separately storing the const qualifier.
-  if (T->isPointerType())
-    T = getContext().getPointerType(PointeeType.getUnqualifiedType());
+  bool IsConst, IsVolatile;
+  T = decomposeTypeForEH(getContext(), T, IsConst, IsVolatile);
 
   // The CatchableTypeArray enumerates the various (CV-unqualified) types that
   // the exception object may be caught as.

Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-try-throw.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-try-throw.cpp?rev=232318&r1=232317&r2=232318&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-try-throw.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-try-throw.cpp Sun Mar 15 02:10:01 2015
@@ -31,3 +31,15 @@ int main() {
 #endif
   return rv;
 }
+
+#ifdef TRY
+// TRY-LABEL: define void @"\01?qual_catch@@YAXXZ"
+void qual_catch() {
+  try {
+    external();
+  } catch (const int *) {
+  }
+  // TRY: catch i8* bitcast (%rtti.TypeDescriptor4* @"\01??_R0PAH at 8" to i8*)
+  // TRY: call i32 @llvm.eh.typeid.for(i8* bitcast (%rtti.TypeDescriptor4* @"\01??_R0PAH at 8" to i8*))
+}
+#endif





More information about the cfe-commits mailing list