summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOlly Betts <olly@survex.com>2023-01-05 16:54:16 +1300
committerOlly Betts <olly@survex.com>2023-05-11 13:11:22 +1200
commit9c8d6563498bbfd22d05b225930409236834b867 (patch)
tree197887f358073c65a911882674c874ee4e17cd9a
parent38f8f15fcd4747cb1db136de74874dd779a75c6f (diff)
downloadswig-parse-storage-class-flexibly.tar.gz
Parse storage class more flexiblyparse-storage-class-flexibly
Previously we had a hard-coded list of allowed combinations in the grammar, but this suffers from combinatorial explosion, and results in a vague `Syntax error in input` error for invalid combinations. This means we now support a number of cases which are valid C++ but weren't supported. Fixes #302 Fixes #2079 (friend constexpr) Fixes #2474 (virtual explicit)
-rw-r--r--Examples/test-suite/cpp11_constexpr.i3
-rw-r--r--Examples/test-suite/cpp11_noexcept.i6
-rw-r--r--Source/CParse/parser.y177
-rw-r--r--Source/CParse/templ.c2
-rw-r--r--Source/Modules/allocate.cxx2
-rw-r--r--Source/Modules/go.cxx6
-rw-r--r--Source/Modules/lang.cxx4
-rw-r--r--Source/Modules/php.cxx14
-rw-r--r--Source/Modules/typepass.cxx2
-rw-r--r--Source/Swig/naming.c4
10 files changed, 158 insertions, 62 deletions
diff --git a/Examples/test-suite/cpp11_constexpr.i b/Examples/test-suite/cpp11_constexpr.i
index 5ba9ff243..d830d984a 100644
--- a/Examples/test-suite/cpp11_constexpr.i
+++ b/Examples/test-suite/cpp11_constexpr.i
@@ -39,6 +39,9 @@ struct ConstExpressions {
// Regression tests for https://github.com/swig/swig/issues/284 :
explicit constexpr ConstExpressions(int) { }
constexpr explicit ConstExpressions(double) { }
+ // Regression tests for https://github.com/swig/swig/issues/2079 :
+ constexpr friend bool operator==(ConstExpressions,ConstExpressions) { return true; }
+ friend constexpr bool operator!=(ConstExpressions,ConstExpressions) { return false; }
};
%}
diff --git a/Examples/test-suite/cpp11_noexcept.i b/Examples/test-suite/cpp11_noexcept.i
index 8aa0baa5a..6b0584473 100644
--- a/Examples/test-suite/cpp11_noexcept.i
+++ b/Examples/test-suite/cpp11_noexcept.i
@@ -1,5 +1,7 @@
%module cpp11_noexcept
+%ignore NoExceptAbstract::operator std::string;
+%ignore NoExceptAbstract::operator int;
%ignore NoExceptClass(NoExceptClass&&);
%rename(Assignment) NoExceptClass::operator=;
@@ -7,6 +9,7 @@
extern "C" void global_noexcept(int, bool) noexcept {}
%}
%inline %{
+#include <string>
extern "C" void global_noexcept(int, bool) noexcept;
extern "C" void global_noexcept2(int, bool) noexcept {}
@@ -43,6 +46,9 @@ struct NoExceptClass {
struct NoExceptAbstract {
virtual void noo4() const noexcept = 0;
virtual ~NoExceptAbstract() noexcept = 0;
+ // Regression test for https://github.com/swig/swig/issues/2474
+ virtual explicit operator std::string() const noexcept = 0;
+ explicit virtual operator int() const noexcept = 0;
};
struct NoExceptDefaultDelete {
diff --git a/Source/CParse/parser.y b/Source/CParse/parser.y
index 325856074..7a9cefe7b 100644
--- a/Source/CParse/parser.y
+++ b/Source/CParse/parser.y
@@ -231,6 +231,49 @@ static int cplus_mode = 0;
#define CPLUS_PRIVATE 2
#define CPLUS_PROTECTED 3
+/* storage classes */
+
+#define SWIG_STORAGE_CLASS_EXTERNC 0x0001
+#define SWIG_STORAGE_CLASS_EXTERNCPP 0x0002
+#define SWIG_STORAGE_CLASS_EXTERN 0x0004
+#define SWIG_STORAGE_CLASS_STATIC 0x0008
+#define SWIG_STORAGE_CLASS_TYPEDEF 0x0010
+#define SWIG_STORAGE_CLASS_VIRTUAL 0x0020
+#define SWIG_STORAGE_CLASS_FRIEND 0x0040
+#define SWIG_STORAGE_CLASS_EXPLICIT 0x0080
+#define SWIG_STORAGE_CLASS_CONSTEXPR 0x0100
+#define SWIG_STORAGE_CLASS_THREAD_LOCAL 0x0200
+
+/* Test if multiple bits are set in x. */
+static int multiple_bits_set(unsigned x) { return (x & (x - 1)) != 0; }
+
+static const char* storage_class_string(int c) {
+ switch (c) {
+ case SWIG_STORAGE_CLASS_EXTERNC:
+ return "extern \"C\"";
+ case SWIG_STORAGE_CLASS_EXTERNCPP:
+ return "extern \"C++\"";
+ case SWIG_STORAGE_CLASS_EXTERN:
+ return "extern";
+ case SWIG_STORAGE_CLASS_STATIC:
+ return "static";
+ case SWIG_STORAGE_CLASS_TYPEDEF:
+ return "typedef";
+ case SWIG_STORAGE_CLASS_VIRTUAL:
+ return "virtual";
+ case SWIG_STORAGE_CLASS_FRIEND:
+ return "friend";
+ case SWIG_STORAGE_CLASS_EXPLICIT:
+ return "explicit";
+ case SWIG_STORAGE_CLASS_CONSTEXPR:
+ return "constexpr";
+ case SWIG_STORAGE_CLASS_THREAD_LOCAL:
+ return "thread_local";
+ }
+ assert(0);
+ return "<unknown>";
+}
+
/* include types */
static int import_mode = 0;
@@ -352,7 +395,7 @@ static String *make_unnamed(void) {
/* Return if the node is a friend declaration */
static int is_friend(Node *n) {
- return Cmp(Getattr(n,"storage"),"friend") == 0;
+ return (Strstr(Getattr(n, "storage"), "friend") != NULL);
}
static int is_operator(String *name) {
@@ -1150,10 +1193,10 @@ Printf(stdout, "comparing current: [%s] found: [%s]\n", current_scopename, found
}
/* look for simple typedef name in typedef list */
-static String *try_to_find_a_name_for_unnamed_structure(const char *storage, Node *decls) {
+static String *try_to_find_a_name_for_unnamed_structure(const String *storage, Node *decls) {
String *name = 0;
Node *n = decls;
- if (storage && (strcmp(storage, "typedef") == 0)) {
+ if (storage && Equal(storage, "typedef")) {
for (; n; n = nextSibling(n)) {
if (!Len(Getattr(n, "decl"))) {
name = Copy(Getattr(n, "name"));
@@ -1183,7 +1226,7 @@ static void update_nested_classes(Node *n)
* Create the nested class/struct/union as a forward declaration.
* ----------------------------------------------------------------------------- */
-static Node *nested_forward_declaration(const char *storage, const String *kind, String *sname, String *name, Node *cpp_opt_declarators) {
+static Node *nested_forward_declaration(const String *storage, const String *kind, String *sname, String *name, Node *cpp_opt_declarators) {
Node *nn = 0;
if (sname) {
@@ -1200,10 +1243,10 @@ static Node *nested_forward_declaration(const char *storage, const String *kind,
/* Add any variable instances. Also add in any further typedefs of the nested type.
Note that anonymous typedefs (eg typedef struct {...} a, b;) are treated as class forward declarations */
if (cpp_opt_declarators) {
- int storage_typedef = (storage && (strcmp(storage, "typedef") == 0));
+ int storage_typedef = (storage && Equal(storage, "typedef"));
int variable_of_anonymous_type = !sname && !storage_typedef;
if (!variable_of_anonymous_type) {
- int anonymous_typedef = !sname && (storage && (strcmp(storage, "typedef") == 0));
+ int anonymous_typedef = !sname && storage_typedef;
Node *n = cpp_opt_declarators;
SwigType *type = name;
while (n) {
@@ -1680,7 +1723,8 @@ static String *add_qualifier_to_declarator(SwigType *type, SwigType *qualifier)
/* Misc */
%type <id> identifier;
%type <dtype> initializer cpp_const exception_specification cv_ref_qualifier qualifiers_exception_specification;
-%type <id> storage_class extern_string;
+%type <str> storage_class;
+%type <intvalue> storage_class_raw storage_class_list;
%type <pl> parms rawparms varargs_parms ;
%type <pl> templateparameterstail;
%type <p> parm_no_dox parm valparm rawvalparms valparms valptail ;
@@ -2373,6 +2417,7 @@ native_directive : NATIVE LPAREN identifier RPAREN storage_class identifier SEMI
$$ = new_node("native");
Setattr($$,"name",$3);
Setattr($$,"wrap:name",$6);
+ Delete($5);
add_symbols($$);
}
| NATIVE LPAREN identifier RPAREN storage_class type declarator SEMI {
@@ -2390,6 +2435,7 @@ native_directive : NATIVE LPAREN identifier RPAREN storage_class identifier SEMI
Setattr($$,"parms",$7.parms);
Setattr($$,"decl",$7.type);
}
+ Delete($5);
add_symbols($$);
}
;
@@ -3361,16 +3407,19 @@ cpp_alternate_rettype : primitive_type { $$ = $1; }
cpp_lambda_decl : storage_class AUTO idcolon EQUAL lambda_introducer lambda_template LPAREN parms RPAREN cpp_const lambda_body lambda_tail {
$$ = new_node("lambda");
Setattr($$,"name",$3);
+ Delete($1);
add_symbols($$);
}
| storage_class AUTO idcolon EQUAL lambda_introducer lambda_template LPAREN parms RPAREN cpp_const ARROW type lambda_body lambda_tail {
$$ = new_node("lambda");
Setattr($$,"name",$3);
+ Delete($1);
add_symbols($$);
}
| storage_class AUTO idcolon EQUAL lambda_introducer lambda_template lambda_body lambda_tail {
$$ = new_node("lambda");
Setattr($$,"name",$3);
+ Delete($1);
add_symbols($$);
}
;
@@ -3624,6 +3673,8 @@ c_constructor_decl : storage_class type LPAREN parms RPAREN ctor_end {
Setattr($$,"final",$6.final);
err = 0;
}
+ } else {
+ Delete($1);
}
if (err) {
Swig_error(cparse_file,cparse_line,"Syntax error in input(2).\n");
@@ -4061,7 +4112,7 @@ cpp_opt_declarators : SEMI { $$ = 0; }
------------------------------------------------------------ */
cpp_forward_class_decl : storage_class cpptype idcolon SEMI {
- if ($1 && (Strcmp($1,"friend") == 0)) {
+ if ($1 && Strstr($1, "friend")) {
/* Ignore */
$$ = 0;
} else {
@@ -4071,6 +4122,7 @@ cpp_forward_class_decl : storage_class cpptype idcolon SEMI {
Setattr($$,"sym:weak", "1");
add_symbols($$);
}
+ Delete($1);
}
;
@@ -4575,7 +4627,7 @@ cpp_members : cpp_member cpp_members {
Exit(EXIT_FAILURE);
} cpp_members {
$$ = $3;
- }
+ }
;
/* ======================================================================
@@ -4608,7 +4660,7 @@ cpp_member_no_dox : c_declaration { $$ = $1; }
| cpp_conversion_operator { $$ = $1; }
| cpp_forward_class_decl { $$ = $1; }
| cpp_class_decl { $$ = $1; }
- | storage_class idcolon SEMI { $$ = 0; }
+ | storage_class idcolon SEMI { $$ = 0; Delete($1); }
| cpp_using_decl { $$ = $1; }
| cpp_template_decl { $$ = $1; }
| cpp_catch_decl { $$ = 0; }
@@ -4661,6 +4713,7 @@ cpp_constructor_decl : storage_class type LPAREN parms RPAREN ctor_end {
Setattr($$,"value",$6.defarg);
} else {
$$ = 0;
+ Delete($1);
}
}
;
@@ -4967,7 +5020,7 @@ cpp_vend : cpp_const SEMI {
;
-anonymous_bitfield : storage_class anon_bitfield_type COLON expr SEMI { };
+anonymous_bitfield : storage_class anon_bitfield_type COLON expr SEMI { Delete($1); };
/* Equals type_right without the ENUM keyword and cpptype (templates etc.): */
anon_bitfield_type : primitive_type { $$ = $1;
@@ -4988,45 +5041,79 @@ anon_bitfield_type : primitive_type { $$ = $1;
/* ======================================================================
* PRIMITIVES
* ====================================================================== */
-extern_string : EXTERN string {
- if (Strcmp($2,"C") == 0) {
- $$ = "externc";
- } else if (Strcmp($2,"C++") == 0) {
- $$ = "extern";
+storage_class : storage_class_list {
+ String *r = NewStringEmpty();
+
+ /* Check for invalid combinations. */
+ if (multiple_bits_set($1 & (SWIG_STORAGE_CLASS_EXTERN |
+ SWIG_STORAGE_CLASS_STATIC))) {
+ Swig_error(cparse_file, cparse_line, "Storage class can't be both 'static' and 'extern'");
+ }
+ if (multiple_bits_set($1 & (SWIG_STORAGE_CLASS_EXTERNC |
+ SWIG_STORAGE_CLASS_EXTERN |
+ SWIG_STORAGE_CLASS_EXTERNCPP))) {
+ Swig_error(cparse_file, cparse_line, "Declaration can only be one of 'extern', 'extern \"C\"' and 'extern \"C++\"'");
+ }
+
+ if ($1 & SWIG_STORAGE_CLASS_TYPEDEF) {
+ Append(r, "typedef ");
+ } else {
+ if ($1 & SWIG_STORAGE_CLASS_EXTERNC)
+ Append(r, "externc ");
+ if ($1 & (SWIG_STORAGE_CLASS_EXTERN|SWIG_STORAGE_CLASS_EXTERNCPP))
+ Append(r, "extern ");
+ if ($1 & SWIG_STORAGE_CLASS_STATIC)
+ Append(r, "static ");
+ }
+ if ($1 & SWIG_STORAGE_CLASS_VIRTUAL)
+ Append(r, "virtual ");
+ if ($1 & SWIG_STORAGE_CLASS_FRIEND)
+ Append(r, "friend ");
+ if ($1 & SWIG_STORAGE_CLASS_EXPLICIT)
+ Append(r, "explicit ");
+ if ($1 & SWIG_STORAGE_CLASS_CONSTEXPR)
+ Append(r, "constexpr ");
+ if ($1 & SWIG_STORAGE_CLASS_THREAD_LOCAL)
+ Append(r, "thread_local ");
+ if (Len(r) == 0) {
+ Delete(r);
+ $$ = 0;
+ } else {
+ Chop(r);
+ $$ = r;
+ }
+ }
+ | empty { $$ = 0; }
+ ;
+
+storage_class_list: storage_class_raw { $$ = $1; }
+ | storage_class_list storage_class_raw {
+ if ($1 & $2) {
+ Swig_error(cparse_file, cparse_line, "Repeated storage class or type specifier '%s'\n", storage_class_string($2));
+ }
+ $$ = $1 | $2;
+ }
+ ;
+
+storage_class_raw : EXTERN { $$ = SWIG_STORAGE_CLASS_EXTERN; }
+ | EXTERN string {
+ if (Strcmp($2,"C") == 0) {
+ $$ = SWIG_STORAGE_CLASS_EXTERNC;
+ } else if (Strcmp($2,"C++") == 0) {
+ $$ = SWIG_STORAGE_CLASS_EXTERNCPP;
} else {
Swig_warning(WARN_PARSE_UNDEFINED_EXTERN,cparse_file, cparse_line,"Unrecognized extern type \"%s\".\n", $2);
$$ = 0;
}
- }
- ;
-
-storage_class : EXTERN { $$ = "extern"; }
- | extern_string { $$ = $1; }
- | extern_string THREAD_LOCAL {
- if (Equal($1, "extern")) {
- $$ = "extern thread_local";
- } else {
- $$ = "externc thread_local";
- }
}
- | extern_string TYPEDEF { $$ = "typedef"; }
- | STATIC { $$ = "static"; }
- | TYPEDEF { $$ = "typedef"; }
- | VIRTUAL { $$ = "virtual"; }
- | FRIEND { $$ = "friend"; }
- | EXPLICIT { $$ = "explicit"; }
- | CONSTEXPR { $$ = "constexpr"; }
- | EXPLICIT CONSTEXPR { $$ = "explicit constexpr"; }
- | CONSTEXPR EXPLICIT { $$ = "explicit constexpr"; }
- | STATIC CONSTEXPR { $$ = "static constexpr"; }
- | CONSTEXPR STATIC { $$ = "static constexpr"; }
- | THREAD_LOCAL { $$ = "thread_local"; }
- | THREAD_LOCAL STATIC { $$ = "static thread_local"; }
- | STATIC THREAD_LOCAL { $$ = "static thread_local"; }
- | EXTERN THREAD_LOCAL { $$ = "extern thread_local"; }
- | THREAD_LOCAL EXTERN { $$ = "extern thread_local"; }
- | empty { $$ = 0; }
- ;
+ | STATIC { $$ = SWIG_STORAGE_CLASS_STATIC; }
+ | TYPEDEF { $$ = SWIG_STORAGE_CLASS_TYPEDEF; }
+ | VIRTUAL { $$ = SWIG_STORAGE_CLASS_VIRTUAL; }
+ | FRIEND { $$ = SWIG_STORAGE_CLASS_FRIEND; }
+ | EXPLICIT { $$ = SWIG_STORAGE_CLASS_EXPLICIT; }
+ | CONSTEXPR { $$ = SWIG_STORAGE_CLASS_CONSTEXPR; }
+ | THREAD_LOCAL { $$ = SWIG_STORAGE_CLASS_THREAD_LOCAL; }
+ ;
/* ------------------------------------------------------------------------------
Function parameter lists
diff --git a/Source/CParse/templ.c b/Source/CParse/templ.c
index 4037cbf86..3ef0e9d5f 100644
--- a/Source/CParse/templ.c
+++ b/Source/CParse/templ.c
@@ -166,7 +166,7 @@ static void cparse_template_expand(Node *templnode, Node *n, String *tname, Stri
Append(cpatchlist, Getattr(n, "sym:name"));
}
}
- if (checkAttribute(n, "storage", "friend")) {
+ if (Strstr(Getattr(n, "storage"), "friend")) {
String *symname = Getattr(n, "sym:name");
if (symname) {
String *stripped_name = SwigType_templateprefix(symname);
diff --git a/Source/Modules/allocate.cxx b/Source/Modules/allocate.cxx
index 0e1262f83..233830791 100644
--- a/Source/Modules/allocate.cxx
+++ b/Source/Modules/allocate.cxx
@@ -396,7 +396,7 @@ class Allocate:public Dispatcher {
if (!GetFlag(c, "feature:ignore")) {
String *storage = Getattr(c, "storage");
if (!((Cmp(storage, "typedef") == 0))
- && !((Cmp(storage, "friend") == 0))) {
+ && !Strstr(storage, "friend")) {
String *name = Getattr(c, "name");
String *symname = Getattr(c, "sym:name");
Node *e = Swig_symbol_clookup_local(name, 0);
diff --git a/Source/Modules/go.cxx b/Source/Modules/go.cxx
index 27e3060bf..6339cc15d 100644
--- a/Source/Modules/go.cxx
+++ b/Source/Modules/go.cxx
@@ -2271,7 +2271,7 @@ private:
}
String *storage = Getattr(entry, "storage");
- if (storage && (Strcmp(storage, "typedef") == 0 || Strcmp(storage, "friend") == 0)) {
+ if (storage && (Strcmp(storage, "typedef") == 0 || Strstr(storage, "friend"))) {
return SWIG_OK;
}
@@ -5620,7 +5620,7 @@ private:
bool isStatic(Node *n) {
String *storage = Getattr(n, "storage");
- return (storage && (Swig_storage_isstatic(n) || Strcmp(storage, "friend") == 0) && (!SmartPointer || !Getattr(n, "allocate:smartpointeraccess")));
+ return (storage && (Swig_storage_isstatic(n) || Strstr(storage, "friend")) && (!SmartPointer || !Getattr(n, "allocate:smartpointeraccess")));
}
/* ----------------------------------------------------------------------
@@ -5631,7 +5631,7 @@ private:
bool isFriend(Node *n) {
String *storage = Getattr(n, "storage");
- return storage && Strcmp(storage, "friend") == 0;
+ return storage && Strstr(storage, "friend");
}
/* ----------------------------------------------------------------------
diff --git a/Source/Modules/lang.cxx b/Source/Modules/lang.cxx
index 7a85c2d63..ba52e265c 100644
--- a/Source/Modules/lang.cxx
+++ b/Source/Modules/lang.cxx
@@ -882,7 +882,7 @@ int Language::cDeclaration(Node *n) {
/* discards nodes following the access control rules */
if (cplus_mode != PUBLIC || !is_public(n)) {
/* except for friends, they are not affected by access control */
- int isfriend = Cmp(storage, "friend") == 0;
+ int isfriend = (Strstr(storage, "friend") != NULL);
if (!isfriend) {
/* Check what the director needs. If the method is pure virtual, it is always needed.
* Also wrap non-virtual protected members if asked for (allprotected mode). */
@@ -1061,7 +1061,7 @@ int Language::cDeclaration(Node *n) {
int Language::functionHandler(Node *n) {
String *storage = Getattr(n, "storage");
- int isfriend = CurrentClass && Cmp(storage, "friend") == 0;
+ int isfriend = CurrentClass && Strstr(storage, "friend");
int isstatic = CurrentClass && Swig_storage_isstatic(n) && !(SmartPointer && Getattr(n, "allocate:smartpointeraccess"));
Parm *p = Getattr(n, "parms");
if (GetFlag(n, "feature:del")) {
diff --git a/Source/Modules/php.cxx b/Source/Modules/php.cxx
index 8e16c6969..67c73aa6b 100644
--- a/Source/Modules/php.cxx
+++ b/Source/Modules/php.cxx
@@ -951,7 +951,7 @@ public:
void create_command(String *cname, String *fname, Node *n, bool dispatch, String *modes) {
// This is for the single main zend_function_entry record
ParmList *l = Getattr(n, "parms");
- if (cname && !Equal(Getattr(n, "storage"), "friend")) {
+ if (cname && !Strstr(Getattr(n, "storage"), "friend")) {
Printf(f_h, "static PHP_METHOD(%s%s,%s);\n", prefix, cname, fname);
if (wrapperType != staticmemberfn &&
wrapperType != staticmembervar &&
@@ -973,7 +973,7 @@ public:
String *arginfo_id = phptypes->get_arginfo_id();
String *s = cs_entry;
if (!s) s = s_entry;
- if (cname && !Equal(Getattr(n, "storage"), "friend")) {
+ if (cname && !Strstr(Getattr(n, "storage"), "friend")) {
Printf(all_cs_entry, " PHP_ME(%s%s,%s,swig_arginfo_%s,%s)\n", prefix, cname, fname, arginfo_id, modes);
} else {
if (dispatch) {
@@ -1043,7 +1043,7 @@ public:
create_command(class_name, wname, n, true, modes);
- if (class_name && !Equal(Getattr(n, "storage"), "friend")) {
+ if (class_name && !Strstr(Getattr(n, "storage"), "friend")) {
Printv(f->def, "static PHP_METHOD(", prefix, class_name, ",", wname, ") {\n", NIL);
} else {
Printv(f->def, "static ZEND_NAMED_FUNCTION(", wname, ") {\n", NIL);
@@ -1340,7 +1340,7 @@ public:
wname = Getattr(n, "staticmemberfunctionHandler:sym:name");
} else {
if (class_name) {
- if (Cmp(Getattr(n, "storage"), "friend") == 0 && Cmp(Getattr(n, "view"), "globalfunctionHandler") == 0) {
+ if (Strstr(Getattr(n, "storage"), "friend") && Cmp(Getattr(n, "view"), "globalfunctionHandler") == 0) {
wname = iname;
} else {
wname = Getattr(n, "destructorHandler:sym:name");
@@ -1364,7 +1364,7 @@ public:
phptypes = NULL;
String *key;
- if (class_name && !Equal(Getattr(n, "storage"), "friend")) {
+ if (class_name && !Strstr(Getattr(n, "storage"), "friend")) {
key = NewStringf("%s:%s", class_name, wname);
} else {
key = NewStringf(":%s", wname);
@@ -1395,7 +1395,7 @@ public:
if (!overloaded) {
if (!static_getter) {
- if (class_name && !Equal(Getattr(n, "storage"), "friend")) {
+ if (class_name && !Strstr(Getattr(n, "storage"), "friend")) {
Printv(f->def, "static PHP_METHOD(", prefix, class_name, ",", wname, ") {\n", NIL);
} else {
if (wrap_nonclass_global) {
@@ -1589,7 +1589,7 @@ public:
List *return_types = phptypes->process_phptype(n, 0, "tmap:out:phptype");
- if (class_name && !Equal(Getattr(n, "storage"), "friend")) {
+ if (class_name && !Strstr(Getattr(n, "storage"), "friend")) {
if (is_member_director(n)) {
String *parent = class_name;
while ((parent = Getattr(php_parent_class, parent)) != NULL) {
diff --git a/Source/Modules/typepass.cxx b/Source/Modules/typepass.cxx
index 83ec8ad72..01949b2ba 100644
--- a/Source/Modules/typepass.cxx
+++ b/Source/Modules/typepass.cxx
@@ -1043,7 +1043,7 @@ class TypePass:private Dispatcher {
if (Strcmp(nodeType(c), "cdecl") == 0) {
if (!(Swig_storage_isstatic(c)
|| checkAttribute(c, "storage", "typedef")
- || checkAttribute(c, "storage", "friend")
+ || Strstr(Getattr(c, "storage"), "friend")
|| (Getattr(c, "feature:extend") && !Getattr(c, "code"))
|| GetFlag(c, "feature:ignore"))) {
diff --git a/Source/Swig/naming.c b/Source/Swig/naming.c
index 517b056a7..4d7d89340 100644
--- a/Source/Swig/naming.c
+++ b/Source/Swig/naming.c
@@ -997,7 +997,7 @@ static int nodes_are_equivalent(Node *a, Node *b, int a_inclass) {
/* friend methods */
- if (!a_inclass || (Cmp(a_storage, "friend") == 0)) {
+ if (!a_inclass || Strstr(a_storage, "friend")) {
/* check declaration */
String *a_decl = (Getattr(a, "decl"));
@@ -1056,7 +1056,7 @@ static int nodes_are_equivalent(Node *a, Node *b, int a_inclass) {
return 0;
}
if (Equal(ta, "template") && Equal(tb, "template")) {
- if (Cmp(a_storage, "friend") == 0 || Cmp(b_storage, "friend") == 0)
+ if (Strstr(a_storage, "friend") || Strstr(b_storage, "friend"))
return 1;
}
}