]> granicus.if.org Git - clang/commitdiff
[OPENMP]Delay emission of the error messages for the exceptions.
authorAlexey Bataev <a.bataev@hotmail.com>
Fri, 8 Feb 2019 18:02:25 +0000 (18:02 +0000)
committerAlexey Bataev <a.bataev@hotmail.com>
Fri, 8 Feb 2019 18:02:25 +0000 (18:02 +0000)
Fixed diagnostic emission for the exceptions support in case of the
compilation of OpenMP code for the devices. From now on, it uses delayed
diagnostics mechanism, previously used for CUDA only. It allow to
diagnose not allowed used of exceptions only in functions that are going
to be codegen'ed.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@353542 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/LangOptions.def
include/clang/Sema/Sema.h
lib/Frontend/CompilerInvocation.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaExprCXX.cpp
lib/Sema/SemaOpenMP.cpp
lib/Sema/SemaStmt.cpp
test/OpenMP/nvptx_target_exceptions_messages.cpp

index 4e391d2562c476bf7712c958e303851b125abefd..d52f9c0b68ab5817248fb9d45e91b0a48d023673 100644 (file)
@@ -203,7 +203,6 @@ LANGOPT(OpenMPUseTLS      , 1, 0, "Use TLS for threadprivates or runtime calls")
 LANGOPT(OpenMPIsDevice    , 1, 0, "Generate code only for OpenMP target device")
 LANGOPT(OpenMPCUDAMode    , 1, 0, "Generate code for OpenMP pragmas in SIMT/SPMD mode")
 LANGOPT(OpenMPCUDAForceFullRuntime , 1, 0, "Force to use full runtime in all constructs when offloading to CUDA devices")
-LANGOPT(OpenMPHostCXXExceptions    , 1, 0, "C++ exceptions handling in the host code.")
 LANGOPT(OpenMPCUDANumSMs  , 32, 0, "Number of SMs for CUDA devices.")
 LANGOPT(OpenMPCUDABlocksPerSM  , 32, 0, "Number of blocks per SM for CUDA devices.")
 LANGOPT(OpenMPOptimisticCollapse  , 1, 0, "Use at most 32 bits to represent the collapsed loop nest counter.")
index 36b856edfa63add6749e79e19ae22a0d204dca90..0c2479a02076e9c29333d41d4d157f3c171b3061 100644 (file)
@@ -8763,6 +8763,9 @@ private:
   /// Pop OpenMP function region for non-capturing function.
   void popOpenMPFunctionRegion(const sema::FunctionScopeInfo *OldFSI);
 
+  /// Check whether we're allowed to call Callee from the current function.
+  void checkOpenMPDeviceFunction(SourceLocation Loc, FunctionDecl *Callee);
+
   /// Checks if a type or a declaration is disabled due to the owning extension
   /// being disabled, and emits diagnostic messages if it is disabled.
   /// \param D type or declaration to be checked.
@@ -10249,6 +10252,23 @@ public:
   /// Same as CUDADiagIfDeviceCode, with "host" and "device" switched.
   DeviceDiagBuilder CUDADiagIfHostCode(SourceLocation Loc, unsigned DiagID);
 
+  /// Creates a DeviceDiagBuilder that emits the diagnostic if the current
+  /// context is "used as device code".
+  ///
+  /// - If CurContext is a `declare target` function or it is known that the
+  /// function is emitted for the device, emits the diagnostics immediately.
+  /// - If CurContext is a non-`declare target` function and we are compiling
+  ///   for the device, creates a diagnostic which is emitted if and when we
+  ///   realize that the function will be codegen'ed.
+  ///
+  /// Example usage:
+  ///
+  ///  // Variable-length arrays are not allowed in NVPTX device code.
+  ///  if (diagIfOpenMPDeviceCode(Loc, diag::err_vla_unsupported))
+  ///    return ExprError();
+  ///  // Otherwise, continue parsing as normal.
+  DeviceDiagBuilder diagIfOpenMPDeviceCode(SourceLocation Loc, unsigned DiagID);
+
   enum CUDAFunctionTarget {
     CFT_Device,
     CFT_Global,
index b991a89e41b3da46e8c869a0968240224302988f..bda8427b1a1f21091af85bca699e4fece3299920 100644 (file)
@@ -2827,7 +2827,6 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
 
   // Set the flag to prevent the implementation from emitting device exception
   // handling code for those requiring so.
-  Opts.OpenMPHostCXXExceptions = Opts.Exceptions && Opts.CXXExceptions;
   if ((Opts.OpenMPIsDevice && T.isNVPTX()) || Opts.OpenCLCPlusPlus) {
     Opts.Exceptions = 0;
     Opts.CXXExceptions = 0;
index b675986f56bdc50c4ed51b6357cbfecce521b57b..4d9a8df26f4d14ef68b48ecbf2529ec9b730c3cf 100644 (file)
@@ -14896,6 +14896,9 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
   }
 
   Func->markUsed(Context);
+
+  if (LangOpts.OpenMP && LangOpts.OpenMPIsDevice)
+    checkOpenMPDeviceFunction(Loc, Func);
 }
 
 static void
index 5ac248d36b413c60b93874b2504a9953e4aed5df..b8431ce36ec6a58da73975adef1508954c28e9ec 100644 (file)
@@ -750,12 +750,13 @@ ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex,
                                bool IsThrownVarInScope) {
   // Don't report an error if 'throw' is used in system headers.
   if (!getLangOpts().CXXExceptions &&
-      !getSourceManager().isInSystemHeader(OpLoc) &&
-      (!getLangOpts().OpenMPIsDevice ||
-       !getLangOpts().OpenMPHostCXXExceptions ||
-       isInOpenMPTargetExecutionDirective() ||
-       isInOpenMPDeclareTargetContext()))
-    Diag(OpLoc, diag::err_exceptions_disabled) << "throw";
+      !getSourceManager().isInSystemHeader(OpLoc)) {
+    // Delay error emission for the OpenMP device code.
+    if (LangOpts.OpenMP && LangOpts.OpenMPIsDevice)
+      diagIfOpenMPDeviceCode(OpLoc, diag::err_exceptions_disabled) << "throw";
+    else
+      Diag(OpLoc, diag::err_exceptions_disabled) << "throw";
+  }
 
   // Exceptions aren't allowed in CUDA device code.
   if (getLangOpts().CUDA)
index 6fa98b437640589658c1d3aa04326fcfea1cace3..203de2a57a4eda05bde7176fe7e43d4e3d4eb2cd 100644 (file)
@@ -1393,6 +1393,56 @@ void Sema::popOpenMPFunctionRegion(const FunctionScopeInfo *OldFSI) {
   DSAStack->popFunction(OldFSI);
 }
 
+static bool isOpenMPDeviceDelayedContext(Sema &S) {
+  assert(S.LangOpts.OpenMP && S.LangOpts.OpenMPIsDevice &&
+         "Expected OpenMP device compilation.");
+  return !S.isInOpenMPTargetExecutionDirective() &&
+         !S.isInOpenMPDeclareTargetContext();
+}
+
+/// Do we know that we will eventually codegen the given function?
+static bool isKnownEmitted(Sema &S, FunctionDecl *FD) {
+  assert(S.LangOpts.OpenMP && S.LangOpts.OpenMPIsDevice &&
+         "Expected OpenMP device compilation.");
+  // Templates are emitted when they're instantiated.
+  if (FD->isDependentContext())
+    return false;
+
+  if (OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(
+          FD->getCanonicalDecl()))
+    return true;
+
+  // Otherwise, the function is known-emitted if it's in our set of
+  // known-emitted functions.
+  return S.DeviceKnownEmittedFns.count(FD) > 0;
+}
+
+Sema::DeviceDiagBuilder Sema::diagIfOpenMPDeviceCode(SourceLocation Loc,
+                                                     unsigned DiagID) {
+  assert(LangOpts.OpenMP && LangOpts.OpenMPIsDevice &&
+         "Expected OpenMP device compilation.");
+  return DeviceDiagBuilder((isOpenMPDeviceDelayedContext(*this) &&
+                            !isKnownEmitted(*this, getCurFunctionDecl()))
+                               ? DeviceDiagBuilder::K_Deferred
+                               : DeviceDiagBuilder::K_Immediate,
+                           Loc, DiagID, getCurFunctionDecl(), *this);
+}
+
+void Sema::checkOpenMPDeviceFunction(SourceLocation Loc, FunctionDecl *Callee) {
+  assert(LangOpts.OpenMP && LangOpts.OpenMPIsDevice &&
+         "Expected OpenMP device compilation.");
+  assert(Callee && "Callee may not be null.");
+  FunctionDecl *Caller = getCurFunctionDecl();
+
+  // If the caller is known-emitted, mark the callee as known-emitted.
+  // Otherwise, mark the call in our call graph so we can traverse it later.
+  if (!isOpenMPDeviceDelayedContext(*this) ||
+      (Caller && isKnownEmitted(*this, Caller)))
+    markKnownEmitted(*this, Caller, Callee, Loc, isKnownEmitted);
+  else if (Caller)
+    DeviceCallGraph[Caller].insert({Callee, Loc});
+}
+
 bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level) const {
   assert(LangOpts.OpenMP && "OpenMP is not allowed");
 
index d19383e41a8c6a8e51f249535ddfa9b414287dfb..e4b43576538846714079a390f4a304b95c824f33 100644 (file)
@@ -3997,12 +3997,13 @@ StmtResult Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock,
                                   ArrayRef<Stmt *> Handlers) {
   // Don't report an error if 'try' is used in system headers.
   if (!getLangOpts().CXXExceptions &&
-      !getSourceManager().isInSystemHeader(TryLoc) &&
-      (!getLangOpts().OpenMPIsDevice ||
-       !getLangOpts().OpenMPHostCXXExceptions ||
-       isInOpenMPTargetExecutionDirective() ||
-       isInOpenMPDeclareTargetContext()))
-    Diag(TryLoc, diag::err_exceptions_disabled) << "try";
+      !getSourceManager().isInSystemHeader(TryLoc)) {
+    // Delay error emission for the OpenMP device code.
+    if (LangOpts.OpenMP && LangOpts.OpenMPIsDevice)
+      diagIfOpenMPDeviceCode(TryLoc, diag::err_exceptions_disabled) << "try";
+    else
+      Diag(TryLoc, diag::err_exceptions_disabled) << "try";
+  }
 
   // Exceptions aren't allowed in CUDA device code.
   if (getLangOpts().CUDA)
index 15c9522540fc67dc2e6bc360b7255384e132f969..433ba13f73d6091659540065825e28e3240c5641 100644 (file)
@@ -68,4 +68,17 @@ int baz2() {
   return 2 + baz3();
 }
 
+int baz1() { throw 1; } // expected-error {{cannot use 'throw' with exceptions disabled}}
+
+int foobar1();
+int foobar2();
+
+int (*A)() = &foobar1;
+#pragma omp declare target
+int (*B)() = &foobar2;
+#pragma omp end declare target
+
+int foobar1() { throw 1; }
+int foobar2() { throw 1; } // expected-error {{cannot use 'throw' with exceptions disabled}}
+
 #endif // HEADER