r228058 - SEH: Track users of __try so we can pick a per-func EH personality

Reid Kleckner reid at kleckner.net
Tue Feb 3 14:52:36 PST 2015


Author: rnk
Date: Tue Feb  3 16:52:35 2015
New Revision: 228058

URL: http://llvm.org/viewvc/llvm-project?rev=228058&view=rev
Log:
SEH: Track users of __try so we can pick a per-func EH personality

There are four major kinds of declarations that cause code generation:
- FunctionDecl (includes CXXMethodDecl etc)
- ObjCMethodDecl
- BlockDecl
- CapturedDecl

This patch tracks __try usage on FunctionDecls and diagnoses __try usage
in other decls. If someone wants to use __try from ObjC, they can use it
from a free function, since the ObjC code will need an ObjC-style EH
personality.

Eventually we will want to look through CapturedDecls and track SEH
usage on the parent FunctionDecl, if present.

Added:
    cfe/trunk/test/CodeGenCXX/exceptions-seh.cpp
Modified:
    cfe/trunk/include/clang/AST/Decl.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/CodeGen/CGException.cpp
    cfe/trunk/lib/Sema/SemaStmt.cpp
    cfe/trunk/test/SemaCXX/exceptions-seh.cpp

Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=228058&r1=228057&r2=228058&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Tue Feb  3 16:52:35 2015
@@ -1482,6 +1482,9 @@ private:
   bool IsLateTemplateParsed : 1;
   bool IsConstexpr : 1;
 
+  /// \brief Indicates if the function uses __try.
+  bool UsesSEHTry : 1;
+
   /// \brief Indicates if the function was a definition but its body was
   /// skipped.
   unsigned HasSkippedBody : 1;
@@ -1570,8 +1573,8 @@ protected:
       HasWrittenPrototype(true), IsDeleted(false), IsTrivial(false),
       IsDefaulted(false), IsExplicitlyDefaulted(false),
       HasImplicitReturnZero(false), IsLateTemplateParsed(false),
-      IsConstexpr(isConstexprSpecified), HasSkippedBody(false),
-      EndRangeLoc(NameInfo.getEndLoc()),
+      IsConstexpr(isConstexprSpecified), UsesSEHTry(false),
+      HasSkippedBody(false), EndRangeLoc(NameInfo.getEndLoc()),
       TemplateOrSpecialization(),
       DNLoc(NameInfo.getInfo()) {}
 
@@ -1751,6 +1754,10 @@ public:
   bool isConstexpr() const { return IsConstexpr; }
   void setConstexpr(bool IC) { IsConstexpr = IC; }
 
+  /// Whether this is a (C++11) constexpr function or constexpr constructor.
+  bool usesSEHTry() const { return UsesSEHTry; }
+  void setUsesSEHTry(bool UST) { UsesSEHTry = UST; }
+
   /// \brief Whether this function has been deleted.
   ///
   /// A function that is "deleted" (via the C++0x "= delete" syntax)

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=228058&r1=228057&r2=228058&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Feb  3 16:52:35 2015
@@ -5466,6 +5466,8 @@ def err_exceptions_disabled : Error<
   "cannot use '%0' with exceptions disabled">;
 def err_objc_exceptions_disabled : Error<
   "cannot use '%0' with Objective-C exceptions disabled">;
+def err_seh_try_outside_functions : Error<
+  "cannot use SEH '__try' in blocks, captured regions, or Obj-C method decls">;
 def err_mixing_cxx_try_seh_try : Error<
   "cannot use C++ 'try' in the same function as SEH '__try'">;
 def note_conflicting_try_here : Note<

Modified: cfe/trunk/lib/CodeGen/CGException.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGException.cpp?rev=228058&r1=228057&r2=228058&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGException.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGException.cpp Tue Feb  3 16:52:35 2015
@@ -128,7 +128,12 @@ namespace {
     // This function must have prototype void(void*).
     const char *CatchallRethrowFn;
 
-    static const EHPersonality &get(CodeGenModule &CGM);
+    static const EHPersonality &get(CodeGenModule &CGM,
+                                    const FunctionDecl *FD);
+    static const EHPersonality &get(CodeGenFunction &CGF) {
+      return get(CGF.CGM, dyn_cast_or_null<FunctionDecl>(CGF.CurCodeDecl));
+    }
+
     static const EHPersonality GNU_C;
     static const EHPersonality GNU_C_SJLJ;
     static const EHPersonality GNU_C_SEH;
@@ -141,6 +146,7 @@ namespace {
     static const EHPersonality GNU_CPlusPlus_SEH;
     static const EHPersonality MSVC_except_handler;
     static const EHPersonality MSVC_C_specific_handler;
+    static const EHPersonality MSVC_CxxFrameHandler3;
   };
 }
 
@@ -167,6 +173,8 @@ const EHPersonality
 EHPersonality::MSVC_except_handler = { "_except_handler3", nullptr };
 const EHPersonality
 EHPersonality::MSVC_C_specific_handler = { "__C_specific_handler", nullptr };
+const EHPersonality
+EHPersonality::MSVC_CxxFrameHandler3 = { "__CxxFrameHandler3", nullptr };
 
 /// On Win64, use libgcc's SEH personality function. We fall back to dwarf on
 /// other platforms, unless the user asked for SjLj exceptions.
@@ -239,35 +247,27 @@ static const EHPersonality &getObjCXXPer
   llvm_unreachable("bad runtime kind");
 }
 
-static const EHPersonality &getCPersonalityMSVC(const llvm::Triple &T,
-                                                const LangOptions &L) {
-  if (L.SjLjExceptions)
-    return EHPersonality::GNU_C_SJLJ;
-
+static const EHPersonality &getSEHPersonalityMSVC(const llvm::Triple &T) {
   if (T.getArch() == llvm::Triple::x86)
     return EHPersonality::MSVC_except_handler;
   return EHPersonality::MSVC_C_specific_handler;
 }
 
-static const EHPersonality &getCXXPersonalityMSVC(const llvm::Triple &T,
-                                                  const LangOptions &L) {
-  if (L.SjLjExceptions)
-    return EHPersonality::GNU_CPlusPlus_SJLJ;
-  // FIXME: Implement C++ exceptions.
-  return getCPersonalityMSVC(T, L);
-}
-
-const EHPersonality &EHPersonality::get(CodeGenModule &CGM) {
+const EHPersonality &EHPersonality::get(CodeGenModule &CGM,
+                                        const FunctionDecl *FD) {
   const llvm::Triple &T = CGM.getTarget().getTriple();
   const LangOptions &L = CGM.getLangOpts();
+
   // Try to pick a personality function that is compatible with MSVC if we're
   // not compiling Obj-C. Obj-C users better have an Obj-C runtime that supports
   // the GCC-style personality function.
   if (T.isWindowsMSVCEnvironment() && !L.ObjC1) {
-    if (L.CPlusPlus)
-      return getCXXPersonalityMSVC(T, L);
+    if (L.SjLjExceptions)
+      return EHPersonality::GNU_CPlusPlus_SJLJ;
+    else if (FD && FD->usesSEHTry())
+      return getSEHPersonalityMSVC(T);
     else
-      return getCPersonalityMSVC(T, L);
+      return EHPersonality::MSVC_CxxFrameHandler3;
   }
 
   if (L.CPlusPlus && L.ObjC1)
@@ -354,7 +354,7 @@ void CodeGenModule::SimplifyPersonality(
   if (!LangOpts.ObjCRuntime.isNeXTFamily())
     return;
 
-  const EHPersonality &ObjCXX = EHPersonality::get(*this);
+  const EHPersonality &ObjCXX = EHPersonality::get(*this, /*FD=*/nullptr);
   const EHPersonality &CXX =
       getCXXPersonality(getTarget().getTriple(), LangOpts);
   if (&ObjCXX == &CXX)
@@ -772,7 +772,7 @@ llvm::BasicBlock *CodeGenFunction::EmitL
   CGBuilderTy::InsertPoint savedIP = Builder.saveAndClearIP();
   auto DL = ApplyDebugLocation::CreateDefaultArtificial(*this, CurEHLocation);
 
-  const EHPersonality &personality = EHPersonality::get(CGM);
+  const EHPersonality &personality = EHPersonality::get(*this);
 
   // Create and configure the landing pad.
   llvm::BasicBlock *lpad = createBasicBlock("lpad");
@@ -1589,7 +1589,7 @@ llvm::BasicBlock *CodeGenFunction::getTe
   Builder.SetInsertPoint(TerminateLandingPad);
 
   // Tell the backend that this is a landing pad.
-  const EHPersonality &Personality = EHPersonality::get(CGM);
+  const EHPersonality &Personality = EHPersonality::get(*this);
   llvm::LandingPadInst *LPadInst =
     Builder.CreateLandingPad(llvm::StructType::get(Int8PtrTy, Int32Ty, nullptr),
                              getOpaquePersonalityFn(CGM, Personality), 0);
@@ -1648,7 +1648,7 @@ llvm::BasicBlock *CodeGenFunction::getEH
   EHResumeBlock = createBasicBlock("eh.resume");
   Builder.SetInsertPoint(EHResumeBlock);
 
-  const EHPersonality &Personality = EHPersonality::get(CGM);
+  const EHPersonality &Personality = EHPersonality::get(*this);
 
   // This can always be a call because we necessarily didn't find
   // anything on the EH stack which needs our help.

Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=228058&r1=228057&r2=228058&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Tue Feb  3 16:52:35 2015
@@ -3303,11 +3303,12 @@ StmtResult Sema::ActOnCXXTryBlock(Source
   if (getCurScope() && getCurScope()->isOpenMPSimdDirectiveScope())
     Diag(TryLoc, diag::err_omp_simd_region_cannot_use_stmt) << "try";
 
+  sema::FunctionScopeInfo *FSI = getCurFunction();
+
   // C++ try is incompatible with SEH __try.
-  if (!getLangOpts().Borland && getCurFunction()->FirstSEHTryLoc.isValid()) {
+  if (!getLangOpts().Borland && FSI->FirstSEHTryLoc.isValid()) {
     Diag(TryLoc, diag::err_mixing_cxx_try_seh_try);
-    Diag(getCurFunction()->FirstSEHTryLoc, diag::note_conflicting_try_here)
-        << "'__try'";
+    Diag(FSI->FirstSEHTryLoc, diag::note_conflicting_try_here) << "'__try'";
   }
 
   const unsigned NumHandlers = Handlers.size();
@@ -3352,7 +3353,7 @@ StmtResult Sema::ActOnCXXTryBlock(Source
     }
   }
 
-  getCurFunction()->setHasCXXTry(TryLoc);
+  FSI->setHasCXXTry(TryLoc);
 
   // FIXME: We should detect handlers that cannot catch anything because an
   // earlier handler catches a superclass. Need to find a method that is not
@@ -3367,15 +3368,29 @@ StmtResult Sema::ActOnSEHTryBlock(bool I
                                   Stmt *TryBlock, Stmt *Handler) {
   assert(TryBlock && Handler);
 
+  sema::FunctionScopeInfo *FSI = getCurFunction();
+
   // SEH __try is incompatible with C++ try. Borland appears to support this,
   // however.
-  if (!getLangOpts().Borland && getCurFunction()->FirstCXXTryLoc.isValid()) {
-    Diag(TryLoc, diag::err_mixing_cxx_try_seh_try);
-    Diag(getCurFunction()->FirstCXXTryLoc, diag::note_conflicting_try_here)
-        << "'try'";
+  if (!getLangOpts().Borland) {
+    if (FSI->FirstCXXTryLoc.isValid()) {
+      Diag(TryLoc, diag::err_mixing_cxx_try_seh_try);
+      Diag(FSI->FirstCXXTryLoc, diag::note_conflicting_try_here) << "'try'";
+    }
   }
 
-  getCurFunction()->setHasSEHTry(TryLoc);
+  FSI->setHasSEHTry(TryLoc);
+
+  // Reject __try in Obj-C methods, blocks, and captured decls, since we don't
+  // track if they use SEH.
+  DeclContext *DC = CurContext;
+  while (DC && !DC->isFunctionOrMethod())
+    DC = DC->getParent();
+  FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(DC);
+  if (FD)
+    FD->setUsesSEHTry(true);
+  else
+    Diag(TryLoc, diag::err_seh_try_outside_functions);
 
   return SEHTryStmt::Create(Context, IsCXXTry, TryLoc, TryBlock, Handler);
 }

Added: cfe/trunk/test/CodeGenCXX/exceptions-seh.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/exceptions-seh.cpp?rev=228058&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/exceptions-seh.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/exceptions-seh.cpp Tue Feb  3 16:52:35 2015
@@ -0,0 +1,76 @@
+// RUN: %clang_cc1 -std=c++11 -fblocks -fms-extensions %s -triple=x86_64-windows-msvc -emit-llvm -o - -fcxx-exceptions -fexceptions -mconstructor-aliases | FileCheck %s
+
+extern "C" void might_throw();
+
+struct HasCleanup {
+  HasCleanup();
+  ~HasCleanup();
+  int padding;
+};
+
+extern "C" void use_cxx() {
+  HasCleanup x;
+  might_throw();
+}
+
+// Make sure we use __CxxFrameHandler3 for C++ EH.
+
+// CHECK-LABEL: define void @use_cxx()
+// CHECK: call %struct.HasCleanup* @"\01??0HasCleanup@@QEAA at XZ"(%struct.HasCleanup* %{{.*}})
+// CHECK: invoke void @might_throw()
+// CHECK:       to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
+//
+// CHECK: [[cont]]
+// CHECK: call void @"\01??1HasCleanup@@QEAA at XZ"(%struct.HasCleanup* %{{.*}})
+// CHECK: ret void
+//
+// CHECK: [[lpad]]
+// CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*)
+// CHECK-NEXT: cleanup
+// CHECK: call void @"\01??1HasCleanup@@QEAA at XZ"(%struct.HasCleanup* %{{.*}})
+// CHECK: br label %[[resume:[^ ]*]]
+//
+// CHECK: [[resume]]
+// CHECK: resume
+
+extern "C" void use_seh() {
+  __try {
+    might_throw();
+  } __except(1) {
+  }
+}
+
+// Make sure we use __C_specific_handler for SEH.
+
+// CHECK-LABEL: define void @use_seh()
+// CHECK: invoke void @might_throw()
+// CHECK:       to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
+//
+// CHECK: [[cont]]
+// CHECK: br label %[[ret:[^ ]*]]
+//
+// CHECK: [[lpad]]
+// CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
+// CHECK-NEXT: catch i8*
+//
+// CHECK: br label %[[ret]]
+//
+// CHECK: [[ret]]
+// CHECK: ret void
+
+void use_seh_in_lambda() {
+  ([]() {
+    __try {
+      might_throw();
+    } __except(1) {
+    }
+  })();
+  HasCleanup x;
+  might_throw();
+}
+
+// CHECK-LABEL: define void @"\01?use_seh_in_lambda@@YAXXZ"()
+// CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*)
+
+// CHECK-LABEL: define internal void @"\01??R<lambda_0>@?use_seh_in_lambda@@YAXXZ at QEBAXXZ"(%class.anon* %this)
+// CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)

Modified: cfe/trunk/test/SemaCXX/exceptions-seh.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/exceptions-seh.cpp?rev=228058&r1=228057&r2=228058&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/exceptions-seh.cpp (original)
+++ cfe/trunk/test/SemaCXX/exceptions-seh.cpp Tue Feb  3 16:52:35 2015
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-windows-msvc -fms-extensions -fsyntax-only -fexceptions -fcxx-exceptions -verify %s
+// RUN: %clang_cc1 -std=c++03 -fblocks -triple x86_64-windows-msvc -fms-extensions -fsyntax-only -fexceptions -fcxx-exceptions -verify %s
+// RUN: %clang_cc1 -std=c++11 -fblocks -triple x86_64-windows-msvc -fms-extensions -fsyntax-only -fexceptions -fcxx-exceptions -verify %s
 
 // Basic usage should work.
 int safe_div(int n, int d) {
@@ -37,6 +38,7 @@ void instantiate_bad_scope_tmpl() {
   bad_builtin_scope_template<might_crash>();
 }
 
+#if __cplusplus < 201103L
 // FIXME: Diagnose this case. For now we produce undef in codegen.
 template <typename T, T FN()>
 T func_template() {
@@ -46,6 +48,7 @@ void inject_builtins() {
   func_template<void *, __exception_info>();
   func_template<unsigned long, __exception_code>();
 }
+#endif
 
 void use_seh_after_cxx() {
   try { // expected-note {{conflicting 'try' here}}
@@ -68,3 +71,45 @@ void use_cxx_after_seh() {
   } catch (int) {
   }
 }
+
+#if __cplusplus >= 201103L
+void use_seh_in_lambda() {
+  ([]() {
+    __try {
+      might_crash();
+    } __except(1) {
+    }
+  })();
+  try {
+    might_crash();
+  } catch (int) {
+  }
+}
+#endif
+
+void use_seh_in_block() {
+  void (^b)() = ^{
+    __try { // expected-error {{cannot use SEH '__try' in blocks, captured regions, or Obj-C method decls}}
+      might_crash();
+    } __except(1) {
+    }
+  };
+  try {
+    b();
+  } catch (int) {
+  }
+}
+
+void (^use_seh_in_global_block)() = ^{
+  __try { // expected-error {{cannot use SEH '__try' in blocks, captured regions, or Obj-C method decls}}
+    might_crash();
+  } __except(1) {
+  }
+};
+
+void (^use_cxx_in_global_block)() = ^{
+  try {
+    might_crash();
+  } catch(int) {
+  }
+};





More information about the cfe-commits mailing list