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
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
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
#include <cfenv>
#include <sstream>
#if defined(__APPLE__) || defined(__unix__)
-#define HAS_DLOPEN
+#define IS_POSIX_COMPLIANT
#include <dlfcn.h>
#endif
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;
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
HostRte::~HostRte() {
for (auto iter{dynamicallyLoadedLibraries.begin()};
iter != dynamicallyLoadedLibraries.end(); ++iter) {
-#ifdef HAS_DLOPEN
+#ifdef IS_POSIX_COMPLIANT
(void)dlclose(iter->second);
#endif
}
: 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() {
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>
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...);
}}};