Skip to content

Commit 6787b6e

Browse files
authored
Merge pull request #150 from swig-fortran/address-upstream-comments
Address upstream comments
2 parents 83cb1a1 + 10a1522 commit 6787b6e

File tree

8 files changed

+51
-152
lines changed

8 files changed

+51
-152
lines changed

Doc/Manual/src/Fortran.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -895,7 +895,7 @@ specification:
895895

896896
It should be noted that a function that returns `void` cannot be overloaded
897897
with a function that returns anything else: generic interfaces must be either
898-
all subroutines or all functions:
898+
all subroutines or all functions. The pair of declarations
899899
```swig
900900
void cannot_overload(int x);
901901
int cannot_overload(int x, int y);
@@ -1452,6 +1452,8 @@ f = Foo()
14521452
call f%set_val(123)
14531453
value = f%get_val()
14541454
```
1455+
As in C++, the construction of `Foo()` default-initializes member data, so the
1456+
result of `f%get_val()` will be zero immediately after construction.
14551457

14561458
## Inheritance
14571459

Doc/Manual/src/pandoc2swigman.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def convert_link(link):
3434
return "Fortran_" + link.replace("-","_")
3535

3636
def repl_link_match(match):
37-
return r'<a href="#{}">'.format(convert_link(match.group(1)))
37+
return r'<a href="Fortran.html#{}">'.format(convert_link(match.group(1)))
3838

3939
def swiggify(path):
4040
with ReWriter(path) as rewriter:

Examples/test-suite/fortran/Makefile.in

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ C_TEST_CASES = \
3737

3838
FAILING_CPP_TESTS += \
3939
contract \
40-
friends \
4140
global_scope_types \
4241
grouping \
4342
member_funcptr_galore \
@@ -47,7 +46,6 @@ FAILING_CPP_TESTS += \
4746
nested_scope \
4847
overload_arrays \
4948
overload_complicated \
50-
overload_method \
5149
overload_return_type \
5250
overload_simple \
5351
overload_subtype \

Examples/test-suite/fortran/member_pointer_runme.F90

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ program member_pointer_runme
66
use member_pointer
77
use ISO_C_BINDING
88
implicit none
9-
type(SwigOpaqueMemFunPtr) :: area_memptr, perim_memptr
9+
type(SWIGTYPE_m_Shape__f_void__double) :: area_memptr, perim_memptr
1010
type(Square) :: s
1111
real(C_DOUBLE) :: val
1212

@@ -30,11 +30,6 @@ program member_pointer_runme
3030
call set_areavar(perim_memptr)
3131
val = do_op(s, get_areavar())
3232
ASSERT(val == 40.0d0)
33-
34-
! Try the external constants
35-
perim_memptr = PERIMPT
36-
val = do_op(s, get_areavar())
37-
ASSERT(val == 40.0d0)
3833
end program
3934

4035

Examples/test-suite/member_pointer.i

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,6 @@
55
#pragma error_messages (off, badargtype2w) /* Formal argument ... is being passed extern "C" ... */
66
#pragma error_messages (off, wbadinit) /* Using extern "C" ... to initialize ... */
77
#pragma error_messages (off, wbadasg) /* Assigning extern "C" ... */
8-
#elif __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)
9-
/* passing NULL into SWIG constant member function wrapper in Fortran raises a warning because it's an int rather than a nullptr_t */
10-
#pragma GCC diagnostic ignored "-Wconversion-null"
118
#endif
129
%}
1310

Examples/test-suite/sizeof_pointer.i

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,6 @@ This testcase tests whether the sizeof operator on a pointer is working.
44

55
%module sizeof_pointer
66

7-
#ifdef SWIGFORTRAN
8-
%warnfilter(SWIGWARN_LANG_IDENTIFIER); /* incompatible array expressions */
9-
#endif
10-
117
%inline %{
128

139
#define NO_PROBLEM sizeof(char)

Lib/fortran/memfunptr.swg

Lines changed: 25 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -2,141 +2,46 @@
22
* memfunptr.swg
33
* ------------------------------------------------------------------------- */
44

5-
/* The size of the opaque object that stores the member function pointer.
6-
*
7-
* This could be overridden by generating a config.h file with the actual
8-
* maximum function pointer size and %include-ing that configure file in
9-
* a local fortranfragments.swg file. */
10-
#ifndef SWIG_MEMFUNPTR_SIZE
11-
%define SWIG_MEMFUNPTR_SIZE 32 %enddef
12-
#endif
13-
14-
/* -------------------------------------------------------------------------
15-
* BRUTE CAST
16-
* ------------------------------------------------------------------------- */
17-
18-
// This fragment allows making an opaque datatype from C++ member function
19-
// pointers (which according to the standard CANNOT be converted to a pointer).
20-
// encountered. Its syntax is exactly like static_cast.
21-
// Note that the <string.h> fragment imports size_t into the global namespace.
22-
%fragment("swig::brute_cast", "header", fragment="<string.h>") %{
23-
template<typename Dst, typename Src>
24-
SWIGINTERN void SWIG_opaque_memcpy(Dst *dst, const Src *src) {
25-
const size_t MINSIZE
26-
= (sizeof(Dst) < sizeof(Src) ? sizeof(Dst) : sizeof(Src));
27-
const size_t MAXSIZE
28-
= (sizeof(Dst) > sizeof(Src) ? sizeof(Dst) : sizeof(Src));
29-
memcpy(dst, src, MINSIZE);
30-
if (MAXSIZE > MINSIZE)
31-
{
32-
memset(static_cast<char*>(static_cast<void*>(dst)) + MINSIZE,
33-
0,
34-
MAXSIZE - MINSIZE);
35-
}
36-
}
37-
38-
namespace swig {
39-
template<typename Target>
40-
class brute_cast_impl {
41-
public:
42-
template<typename Source>
43-
brute_cast_impl(const Source &src_fwd) {
44-
SWIG_opaque_memcpy(&d_result, &src_fwd);
45-
}
46-
Target operator() () const { return d_result; }
5+
%fragment("SwigFortranPackedData", "header",
6+
fragment="<string.h>", fragment="<stdlib.h>") %{
7+
class SwigFortranPackedData {
478
private:
48-
Target d_result;
49-
};
9+
char* packed_;
5010

51-
template<typename Target>
52-
class brute_cast_impl<Target&> {
5311
public:
54-
template<typename Source>
55-
brute_cast_impl(Source& src_ref) {
56-
Source *src_ptr = &src_ref;
57-
SWIG_opaque_memcpy(&d_result, &src_ptr);
58-
}
59-
Target &operator() () const { return *d_result; }
60-
private:
61-
Target *d_result;
62-
};
63-
64-
template<class Target, class Source>
65-
SWIGINTERN Target brute_cast(const Source& src) {
66-
return brute_cast_impl<Target>(src)();
67-
}
68-
} // end namespace swig
69-
70-
using swig::brute_cast;
71-
%}
12+
template<class T>
13+
SwigFortranPackedData(const T* data) {
14+
packed_ = (char *)malloc(sizeof(T));
15+
memcpy(packed_, data, sizeof(T));
16+
}
7217

73-
/* -------------------------------------------------------------------------
74-
* MEMBER FUNCTION POINTERS
75-
*
76-
* We memcpy the member function pointer to an opaque data class using
77-
* brute_cast.
78-
* ------------------------------------------------------------------------- */
18+
~SwigFortranPackedData() { free(packed_); }
7919

80-
// Add array wrapper to C++ code when used by Fortran fragment
81-
%fragment("SwigOpaqueMemFunPtr", "header", noblock=1, fragment="<string.h>") {
82-
%#if __cplusplus >= 201103L
83-
namespace detail { class UndefinedClass; }
84-
%#endif
20+
template<class T>
21+
void unpack(T* data) const {
22+
memcpy(data, packed_, sizeof(T));
23+
}
8524

86-
struct SwigOpaqueMemFunPtr {
87-
char data[SWIG_MEMFUNPTR_SIZE];
88-
%#if __cplusplus >= 201103L
89-
static_assert(sizeof(void (detail::UndefinedClass::*)()) <= SWIG_MEMFUNPTR_SIZE,
90-
"Member pointer buffer isn't large enough");
91-
%#endif
25+
private:
26+
SwigFortranPackedData& operator=(const SwigFortranPackedData& other);
9227
};
93-
94-
SWIGINTERN SwigOpaqueMemFunPtr SwigOpaqueMemFunPtr_uninitialized() {
95-
SwigOpaqueMemFunPtr result;
96-
memset(result.data, 0, sizeof(result.data));
97-
return result;
98-
}
99-
}
100-
101-
// This fragment is inserted by the fortran.cxx code when an unknown class is
102-
// encountered. Note for this to compile and not crash, the size of 'data' should
103-
// be the same size as in SwigOpaqueMemFunPtr.
104-
%fragment("SwigOpaqueMemFunPtr_f", "fdecl", noblock=1, fragment="SwigOpaqueMemFunPtr")
105-
{ type, public, bind(C) :: SwigOpaqueMemFunPtr
106-
integer(C_SIGNED_CHAR), dimension(SWIG_MEMFUNPTR_SIZE), public :: data
107-
end type}
28+
%}
10829

10930
/* -------------------------------------------------------------------------
11031
* TYPEMAPS
11132
* ------------------------------------------------------------------------- */
11233

113-
%typemap(ctype, fragment="SwigOpaqueMemFunPtr",
114-
null="SwigOpaqueMemFunPtr_uninitialized()") SWIGTYPE (CLASS::*)
115-
"SwigOpaqueMemFunPtr"
116-
%typemap(imtype, in="type(SwigOpaqueMemFunPtr), intent(in), value",
117-
fragment="SwigOpaqueMemFunPtr_f") SWIGTYPE (CLASS::*)
118-
"type(SwigOpaqueMemFunPtr)"
119-
%typemap(ftype, in="type(SwigOpaqueMemFunPtr), intent(in), value",
120-
fragment="SwigOpaqueMemFunPtr_f") SWIGTYPE (CLASS::*)
121-
"type(SwigOpaqueMemFunPtr)"
122-
123-
%typemap(in, noblock=1, fragment="swig::brute_cast") SWIGTYPE (CLASS::*) {
124-
$1 = brute_cast<$1_ltype>($input);
125-
}
126-
%typemap(out, noblock=1, fragment="swig::brute_cast") SWIGTYPE (CLASS::*) {
127-
$result = brute_cast<SwigOpaqueMemFunPtr>($1);
34+
%typemap(in, noblock=1, fragment="SwigFortranPackedData") SWIGTYPE (CLASS::*) {
35+
((SwigFortranPackedData*)($input->cptr))->unpack<$1_ltype>(&$1);
12836
}
129-
%typemap(fin) SWIGTYPE (CLASS::*)
130-
"$1 = $input"
131-
%typemap(fout) SWIGTYPE (CLASS::*)
132-
"$result = $1"
13337

134-
%typemap(bindc, in="type(C_FUNPTR), value",
135-
fragment="SwigOpaqueMemFunPtr_f") SWIGTYPE (CLASS::*)
136-
"type(SwigOpaqueMemFunPtr)"
38+
%typemap(out, noblock=1, fragment="SwigFortranPackedData") SWIGTYPE (CLASS::*) {
39+
$result.cptr = new SwigFortranPackedData(&$1);
40+
$result.cmemflags = SWIG_MEM_RVALUE | SWIG_MEM_OWN;
41+
}
13742

13843
// The SWIG type system does not check the non-const memfunptr when looking for a const memfunptr. Also apply
13944
%apply SWIGTYPE (CLASS::*) { SWIGTYPE (CLASS::* const) };
14045

141-
// I'm not sure this is correct, but it allows member_funcptr_galore to pass.
142-
%apply SWIGTYPE (CLASS::*) { SWIGTYPE (CLASS::* const &)};
46+
// References to member function pointers will look like regular class references
47+
%apply SWIGTYPE & { SWIGTYPE (CLASS::*const&) }

Source/Modules/fortran.cxx

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,16 @@ bool is_wrapped_enum(Node *n) {
188188
return !GetFlag(n, "enumMissing") && GetFlag(n, "fortran:declared");
189189
}
190190

191+
/* -------------------------------------------------------------------------
192+
* \brief Get the special string value corresponding to whether a function is
193+
* a void return type (subroutine)
194+
*/
195+
String *subroutine_flag_str(bool is_subroutine) {
196+
static String *is_subroutine_flag = NewString("is subroutine");
197+
static String *not_subroutine_flag = NewString("is function");
198+
return is_subroutine ? is_subroutine_flag : not_subroutine_flag;
199+
}
200+
191201
/* -------------------------------------------------------------------------
192202
* \brief Whether an SWIG type can be rendered as TYPE VAR.
193203
*
@@ -1592,14 +1602,10 @@ Wrapper *FORTRAN::proxyfuncWrapper(Node *n) {
15921602
Node *conflicting_subroutine = NULL;
15931603

15941604
Node *overridden = Getattr(n, "fortran:override");
1595-
if (overridden) {
1596-
bool is_parent_subroutine = Getattr(overridden, "fortran:subroutine");
1597-
if (Getattr(n, "fortran:variable") && Getattr(overridden, "fortran:variable")) {
1598-
// Since variables can get wrapped twice (for getters and setters), pretend
1599-
// that the parent procedure is like this one
1600-
is_parent_subroutine = is_fsubroutine;
1601-
}
1602-
if (is_parent_subroutine != is_fsubroutine) {
1605+
if (overridden && !(Getattr(n, "fortran:variable") && Getattr(overridden, "fortran:variable"))) {
1606+
// Overridden, but *not* a variable, which can get wrapped twice (for getters and setters)
1607+
String *is_parent_subroutine = Getattr(overridden, "fortran:subroutine");
1608+
if (is_parent_subroutine != NULL && is_parent_subroutine != subroutine_flag_str(is_fsubroutine)) {
16031609
// The parent procedure's return value conflicts with this one. (Perhaps the
16041610
// conversion feature was applied only to the parent class, or a weird
16051611
// typemap is in play?)
@@ -1608,12 +1614,14 @@ Wrapper *FORTRAN::proxyfuncWrapper(Node *n) {
16081614
}
16091615

16101616
if (Node *overload = Getattr(n, "sym:overloaded")) {
1611-
while (overload && GetFlag(overload, "fortran:ignore")) {
1617+
// Skip ignored overloads or uninstantiated overloads (friend functions implicitly instantiated
1618+
// in a templated struct, see friends.i)
1619+
while (overload && (GetFlag(overload, "fortran:ignore") || !Getattr(overload, "fortran:subroutine"))) {
16121620
overload = Getattr(overload, "sym:nextSibling");
16131621
}
16141622
if (overload && overload != n) {
1615-
bool is_sibling_fsubroutine = Getattr(overload, "fortran:subroutine");
1616-
if (is_sibling_fsubroutine != is_fsubroutine) {
1623+
String *is_sibling_fsubroutine = Getattr(overload, "fortran:subroutine");
1624+
if (!Equal(is_sibling_fsubroutine, subroutine_flag_str(is_fsubroutine))) {
16171625
// The parent procedure's return value conflicts with this one. (Perhaps the
16181626
// conversion feature was applied only to the parent class, or a weird
16191627
// typemap is in play?)
@@ -1628,10 +1636,8 @@ Wrapper *FORTRAN::proxyfuncWrapper(Node *n) {
16281636
// functions.
16291637
is_fsubroutine = (is_fsubroutine || func_to_subroutine) && !conflicting_subroutine;
16301638

1631-
if (is_fsubroutine) {
1632-
// Before possibly returning, save whether we're a subroutine in case of other overloads
1633-
Setattr(n, "fortran:subroutine", n);
1634-
}
1639+
// Before possibly returning, save whether we're a subroutine in case of other overloads
1640+
Setattr(n, "fortran:subroutine", subroutine_flag_str(is_fsubroutine));
16351641

16361642
if (conflicting_subroutine) {
16371643
// An already-wrapped overloaded function already has been declared as

0 commit comments

Comments
 (0)