[flang] Limits C++ implementation behaviors

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@4b2f29a128
Tree-same-pre-rewrite: false
This commit is contained in:
Jean Perier 2019-03-01 04:27:10 -08:00 committed by GitHub
parent dd2c2d5798
commit 4fdf4fa18d
3 changed files with 17 additions and 10 deletions

View 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

View 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
}

View 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...);
}}};