mirror of https://github.com/swig/swig
Wrap friend functions that are defined or declared within a namespace
Previously unqualified friend definitions/declarations in a namespace were ignored.
This commit is contained in:
parent
77210e13af
commit
0a16044a27
|
@ -7,6 +7,15 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
|
|||
Version 4.2.1 (in progress)
|
||||
===========================
|
||||
|
||||
2024-01-15: wsfulton
|
||||
https://sourceforge.net/p/swig/bugs/807/
|
||||
Wrap friend functions that are defined or declared within a namespace.
|
||||
Previously unqualified friend definitions/declarations in a namespace were
|
||||
ignored.
|
||||
|
||||
The visibility of unqualified friend functions in C++ is somewhat quirky
|
||||
and the documentation has been enhanced to aid wrapping of friends.
|
||||
|
||||
2024-01-12: wsfulton
|
||||
#2749 Fix seg fault handling friend constructor/destructor declarations.
|
||||
|
||||
|
|
|
@ -2,6 +2,11 @@ using System;
|
|||
using friendsNamespace;
|
||||
|
||||
public class friends_runme {
|
||||
private static void check_equal(int a, int b) {
|
||||
if (a != b)
|
||||
throw new Exception("Not equal " + a + " != " + b);
|
||||
}
|
||||
|
||||
public static void Main() {
|
||||
A a = new A(2);
|
||||
|
||||
|
@ -43,6 +48,17 @@ public class friends_runme {
|
|||
throw new Exception("failed");
|
||||
if (friends.mate_blah() != 4321)
|
||||
throw new Exception("failed");
|
||||
|
||||
Foe foe = new Foe(111);
|
||||
check_equal(friends.friend_definition(), 10);
|
||||
check_equal(friends.friend_declaration(), 11);
|
||||
check_equal(friends.friend_args_definition(foe), 111);
|
||||
check_equal(friends.friend_args_declaration(foe), 111);
|
||||
|
||||
check_equal(friends.friend_definition_compiler(), 20);
|
||||
check_equal(friends.friend_declaration_compiler(), 21);
|
||||
check_equal(friends.friend_args_definition_compiler(foe), 111);
|
||||
check_equal(friends.friend_args_declaration_compiler(foe), 111);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
%warnfilter(SWIGWARN_LANG_IDENTIFIER) operator<<;
|
||||
%warnfilter(SWIGWARN_LANG_IDENTIFIER) operator>>;
|
||||
%warnfilter(SWIGWARN_LANG_IDENTIFIER) ns1::ns2::bar; // This warning suppression is hiding a bug when using namespaces and friends, warning should not be issued
|
||||
|
||||
#if defined(SWIGOCTAVE)
|
||||
%warnfilter(SWIGWARN_IGNORE_OPERATOR_LSHIFT_MSG) operator<<;
|
||||
|
@ -141,9 +140,7 @@
|
|||
};
|
||||
|
||||
namespace ns1 {
|
||||
|
||||
void bas() {}
|
||||
|
||||
void baz() {}
|
||||
}
|
||||
}
|
||||
|
@ -208,16 +205,45 @@ void Mate::private_function() { this->val = 4321; }
|
|||
%}
|
||||
|
||||
|
||||
// Foe class tests friend definitions/declarations in a namespace
|
||||
%inline %{
|
||||
namespace ns1 {
|
||||
namespace ns2 {
|
||||
class Foo {
|
||||
class Foe {
|
||||
int val;
|
||||
public:
|
||||
Foo() {}
|
||||
friend void bar();
|
||||
friend void ns1::baz();
|
||||
Foe() : val() {}
|
||||
Foe(int val) : val(val) {}
|
||||
// Unqualified friends visible to SWIG in outer scope
|
||||
friend int friend_definition() { return Foe(10).val; }
|
||||
friend int friend_declaration();
|
||||
friend int friend_args_definition(Foe &foe) { return foe.val; }
|
||||
friend int friend_args_declaration(Foe &foe);
|
||||
|
||||
// Unqualified friends only visible to C++ compiler in outer scope
|
||||
friend int friend_definition_compiler() { return Foe(20).val; }
|
||||
friend int friend_declaration_compiler();
|
||||
friend int friend_args_definition_compiler(Foe &foe) { return foe.val; }
|
||||
friend int friend_args_declaration_compiler(Foe &foe);
|
||||
|
||||
// Qualified friend (silently ignored)
|
||||
friend void ns1::baz();
|
||||
};
|
||||
void bar() {}
|
||||
int friend_definition();
|
||||
int friend_declaration() { return Foe(11).val; }
|
||||
int friend_args_definition(Foe &foe);
|
||||
int friend_args_declaration(Foe &foe) { return foe.val; }
|
||||
}
|
||||
}
|
||||
%}
|
||||
|
||||
%{
|
||||
namespace ns1 {
|
||||
namespace ns2 {
|
||||
int friend_definition_compiler();
|
||||
int friend_declaration_compiler() { return Foe(21).val; }
|
||||
// int friend_args_definition_compiler(Foe &foe); // ADL is used to find this, so no declaration is needed
|
||||
int friend_args_declaration_compiler(Foe &foe) { return foe.val; }
|
||||
}
|
||||
}
|
||||
%}
|
||||
|
|
|
@ -11,6 +11,11 @@ public class friends_runme {
|
|||
}
|
||||
}
|
||||
|
||||
private static void check_equal(int a, int b) {
|
||||
if (a != b)
|
||||
throw new RuntimeException("Not equal " + a + " != " + b);
|
||||
}
|
||||
|
||||
public static void main(String argv[]) throws Throwable
|
||||
{
|
||||
A a = new A(2);
|
||||
|
@ -53,6 +58,17 @@ public class friends_runme {
|
|||
throw new RuntimeException("failed");
|
||||
if (friends.mate_blah() != 4321)
|
||||
throw new RuntimeException("failed");
|
||||
|
||||
Foe foe = new Foe(111);
|
||||
check_equal(friends.friend_definition(), 10);
|
||||
check_equal(friends.friend_declaration(), 11);
|
||||
check_equal(friends.friend_args_definition(foe), 111);
|
||||
check_equal(friends.friend_args_declaration(foe), 111);
|
||||
|
||||
check_equal(friends.friend_definition_compiler(), 20);
|
||||
check_equal(friends.friend_declaration_compiler(), 21);
|
||||
check_equal(friends.friend_args_definition_compiler(foe), 111);
|
||||
check_equal(friends.friend_args_declaration_compiler(foe), 111);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
require "tests.php";
|
||||
|
||||
check::functions(array('globalscope','mix','get_val2','get_val3','bas','baz','bar','get_val1','set','chum_blah','mate_blah'));
|
||||
check::classes(array('friends','Foo','A','B','D_i','D_d','CModelParameterCompartment','CModelParameterSpecies','Chum','Mate'));
|
||||
check::functions(array('globalscope','mix','get_val2','get_val3','bas','baz','get_val1','set','chum_blah','mate_blah','friend_definition','friend_declaration','friend_args_definition','friend_args_declaration','friend_definition_compiler','friend_declaration_compiler','friend_args_definition_compiler','friend_args_declaration_compiler'));
|
||||
check::classes(array('friends','Foe','A','B','D_i','D_d','CModelParameterCompartment','CModelParameterSpecies','Chum','Mate'));
|
||||
// No new vars
|
||||
check::globals(array());
|
||||
|
||||
|
@ -37,4 +37,15 @@ check::equal(get_val1($dd), 1.3);
|
|||
check::equal(chum_blah(), 1234);
|
||||
check::equal(mate_blah(), 4321);
|
||||
|
||||
$foe = new Foe(111);
|
||||
check::equal(friend_definition(), 10);
|
||||
check::equal(friend_declaration(), 11);
|
||||
check::equal(friend_args_definition($foe), 111);
|
||||
check::equal(friend_args_declaration($foe), 111);
|
||||
|
||||
check::equal(friend_definition_compiler(), 20);
|
||||
check::equal(friend_declaration_compiler(), 21);
|
||||
check::equal(friend_args_definition_compiler($foe), 111);
|
||||
check::equal(friend_args_declaration_compiler($foe), 111);
|
||||
|
||||
check::done();
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
import friends
|
||||
|
||||
def check_equal(a, b):
|
||||
if a != b:
|
||||
raise RuntimeError("Not equal {} != {}".format(a, b))
|
||||
|
||||
a = friends.A(2)
|
||||
|
||||
if friends.get_val1(a) != 2:
|
||||
|
@ -40,3 +44,14 @@ if friends.chum_blah() != 1234:
|
|||
raise RuntimeError("failed")
|
||||
if friends.mate_blah() != 4321:
|
||||
raise RuntimeError("failed")
|
||||
|
||||
foe = friends.Foe(111)
|
||||
check_equal(friends.friend_definition(), 10)
|
||||
check_equal(friends.friend_declaration(), 11)
|
||||
check_equal(friends.friend_args_definition(foe), 111)
|
||||
check_equal(friends.friend_args_declaration(foe), 111)
|
||||
|
||||
check_equal(friends.friend_definition_compiler(), 20)
|
||||
check_equal(friends.friend_declaration_compiler(), 21)
|
||||
check_equal(friends.friend_args_definition_compiler(foe), 111)
|
||||
check_equal(friends.friend_args_declaration_compiler(foe), 111)
|
||||
|
|
|
@ -411,7 +411,6 @@ static void add_symbols(Node *n) {
|
|||
}
|
||||
while (n) {
|
||||
String *symname = 0;
|
||||
/* for friends, we need to pop the scope once */
|
||||
String *old_prefix = 0;
|
||||
Symtab *old_scope = 0;
|
||||
int isfriend = inclass && Checkattr(n, "storage", "friend");
|
||||
|
@ -421,26 +420,17 @@ static void add_symbols(Node *n) {
|
|||
if (inclass) {
|
||||
String *name = Getattr(n, "name");
|
||||
if (isfriend) {
|
||||
/* for friends, we need to add the scopename if needed */
|
||||
/* For friends, set the scope to the same as the class that the friend is defined/declared in, that is, pop scope once */
|
||||
String *prefix = name ? Swig_scopename_prefix(name) : 0;
|
||||
old_prefix = Namespaceprefix;
|
||||
old_scope = Swig_symbol_popscope();
|
||||
Namespaceprefix = Swig_symbol_qualifiedscopename(0);
|
||||
if (!prefix) {
|
||||
if (name && !is_operator(name) && Namespaceprefix) {
|
||||
String *nname = NewStringf("%s::%s", Namespaceprefix, name);
|
||||
Setattr(n,"name",nname);
|
||||
Delete(nname);
|
||||
String *friendusing = NewStringf("using namespace %s;", Namespaceprefix);
|
||||
Setattr(n, "friendusing", friendusing);
|
||||
Delete(friendusing);
|
||||
}
|
||||
} else {
|
||||
Symtab *st = Swig_symbol_getscope(prefix);
|
||||
String *ns = st ? Getattr(st,"name") : prefix;
|
||||
String *base = Swig_scopename_last(name);
|
||||
String *nname = NewStringf("%s::%s", ns, base);
|
||||
Setattr(n,"name",nname);
|
||||
Delete(nname);
|
||||
Delete(base);
|
||||
Delete(prefix);
|
||||
}
|
||||
Namespaceprefix = 0;
|
||||
} else if (Equal(nodeType(n), "using")) {
|
||||
|
|
|
@ -1166,7 +1166,20 @@ int Language::globalfunctionHandler(Node *n) {
|
|||
String *extendname = Getattr(n, "extendname");
|
||||
String *call = Swig_cfunction_call(extendname ? extendname : name, parms);
|
||||
String *cres = Swig_cresult(type, Swig_cresult_name(), call);
|
||||
Setattr(n, "wrap:action", cres);
|
||||
String *friendusing = Getattr(n, "friendusing");
|
||||
if (friendusing) {
|
||||
// Add a using directive to avoid having to possibly fully qualify the call to the friend function.
|
||||
// Unconventional for SWIG generation, but the alternative is to implement Argument Dependent Lookup
|
||||
// as friend functions are quirky and not visible, except for ADL. An ADL implementation would be needed
|
||||
// in order to work out when the friend function is visible or not, in order to determine whether to
|
||||
// rely on ADL (with no qualification) or to fully qualify the call to the friend function made
|
||||
// visible via a matching declaration at namespace scope.
|
||||
String *action = NewStringf("%s\n%s", friendusing, cres);
|
||||
Setattr(n, "wrap:action", action);
|
||||
Delete(action);
|
||||
} else {
|
||||
Setattr(n, "wrap:action", cres);
|
||||
}
|
||||
Delete(cres);
|
||||
Delete(call);
|
||||
functionWrapper(n);
|
||||
|
|
Loading…
Reference in New Issue