[flang] Limits C++ implementation behaviors
authorJean Perier <jperier@nvidia.com>
Fri, 1 Mar 2019 12:27:10 +0000 (04:27 -0800)
committerGitHub <noreply@github.com>
Wed, 27 Mar 2019 17:16:07 +0000 (10:16 -0700)
The issue addressed here is the use of cast between object pointers
and function pointers. It is implementation defined because C++,
just like C, does not mandate that function and object pointers
must have the same size.
It is needed to have such cast because it is a will to ba able to
call inside F18 numerical function from libraries linked during
a Fortran program compilation in order to perform folding.
dlopen returns function pointers as void* that need to be cast to
pointer before use.
This change limits the usage of such cast inside ifdefs where POSIX
is required. In POSIX context, such cast is defined. Dlopen is
anyway used only if the environment is POSIX compliant.
In the rest of the code, opaque function pointers have been changed
from void* to void*(*)(). reinterpret_cast from function pointer to
function pointer are standard compliant.

Original-commit: flang-compiler/f18@4b2f29a1289e955469c9b9778a7db0034b0fce70
Tree-same-pre-rewrite: false

flang/lib/evaluate/rte-interface.h
flang/lib/evaluate/rte.cc
flang/lib/evaluate/rte.h

index 8b21d7d..bacaa2e 100644 (file)
@@ -60,7 +60,7 @@ struct RteProcedureSymbol {
   const std::vector<TypeCode> argumentsType;
   const std::vector<PassBy> argumentsPassedBy;
   const bool isElemental;
-  const void *callable;
+  const FuncPointer<void *> callable;
   // callable only usable by HostRteProcedureSymbol but need to be created in
   // case TargetRteProcedureSymbol is dynamically loaded because creating it
   // dynamically would be too complex
@@ -98,9 +98,10 @@ struct HostRteProcedureSymbol : RteProcedureSymbol {
   template<typename HostTR, typename... HostTA>
   HostRteProcedureSymbol(const std::string &name,
       FuncPointer<HostTR, HostTA...> func, bool isElemental = false);
-  HostRteProcedureSymbol(const RteProcedureSymbol &rteProc, const void *handle)
+  HostRteProcedureSymbol(
+      const RteProcedureSymbol &rteProc, FuncPointer<void *> handle)
     : RteProcedureSymbol{rteProc}, handle{handle} {}
-  const void *handle;
+  const FuncPointer<void *> handle;
 };
 
 // valid ConstantContainer are Scalar (only for elementals) and Constant
index 0569ac6..ed350f2 100644 (file)
@@ -22,7 +22,7 @@
 #include <cfenv>
 #include <sstream>
 #if defined(__APPLE__) || defined(__unix__)
-#define HAS_DLOPEN
+#define IS_POSIX_COMPLIANT
 #include <dlfcn.h>
 #endif
 
@@ -58,7 +58,7 @@ void HostRte::LoadTargetRteLibrary(const TargetRteLibrary &lib) {
       dynamicallyLoadedLibraries.end()) {
     return;  // already loaded
   }
-#ifdef HAS_DLOPEN
+#ifdef IS_POSIX_COMPLIANT
   void *handle = dlopen((lib.name + std::string{".so"}).c_str(), RTLD_LAZY);
   if (!handle) {
     return;
@@ -69,7 +69,13 @@ void HostRte::LoadTargetRteLibrary(const TargetRteLibrary &lib) {
     auto error{dlerror()};
     if (error) {
     } else {
-      AddProcedure(HostRteProcedureSymbol{sym.second, func});
+      // Note: below is the only reinterpret_cast from an object pointer to
+      // function pointer As per C++11 and later rules on reinterpret_cast, it is
+      // implementation defined whether this is supported. POSIX mandates that
+      // such cast from function pointers to void* are defined. Hence this
+      // reinterpret_cast is and MUST REMAIN inside ifdef related to POSIX.
+      AddProcedure(HostRteProcedureSymbol{
+          sym.second, reinterpret_cast<FuncPointer<void *>>(func)});
     }
   }
 #else
@@ -80,7 +86,7 @@ void HostRte::LoadTargetRteLibrary(const TargetRteLibrary &lib) {
 HostRte::~HostRte() {
   for (auto iter{dynamicallyLoadedLibraries.begin()};
        iter != dynamicallyLoadedLibraries.end(); ++iter) {
-#ifdef HAS_DLOPEN
+#ifdef IS_POSIX_COMPLIANT
     (void)dlclose(iter->second);
 #endif
   }
index a5c74ab..f50c76a 100644 (file)
@@ -98,7 +98,7 @@ RteProcedureSymbol::RteProcedureSymbol(
   : name{signature.name}, returnType{typeCodeOf<TR>},
     argumentsType{typeCodeOf<typename ArgInfo::Type>...},
     argumentsPassedBy{ArgInfo::pass...}, isElemental{isElemental},
-    callable{reinterpret_cast<const void *>(
+    callable{reinterpret_cast<FuncPointer<void *>>(
         CallableHostWrapper<TR, ArgInfo...>::MakeScalarCallable())} {}
 
 template<typename HostTA> static constexpr inline PassBy PassByMethod() {
@@ -123,7 +123,7 @@ HostRteProcedureSymbol::HostRteProcedureSymbol(const std::string &name,
     FuncPointer<HostTR, HostTA...> func, bool isElemental)
   : RteProcedureSymbol(
         SignatureFromHostFuncPointer<HostTR, HostTA...>{name}, isElemental),
-    handle{reinterpret_cast<const void *>(func)} {}
+    handle{reinterpret_cast<FuncPointer<void *>>(func)} {}
 
 template<template<typename> typename ConstantContainer, typename TR,
     typename... TA>
@@ -153,7 +153,7 @@ HostRte::GetHostProcedureWrapper(const std::string &name) {
                   const ConstantContainer<TA> &... args) {
                 auto callable{reinterpret_cast<
                     FuncPointer<ConstantContainer<TR>, FoldingContext &,
-                        const void *, const ConstantContainer<TA> &...>>(
+                        FuncPointer<void *>, const ConstantContainer<TA> &...>>(
                     iter->second.callable)};
                 return callable(context, iter->second.handle, args...);
               }}};