Add support for parsing C++11 =delete and =default

Although this was documented as working, it wasn't implemented
%typemap(default) failed without the idstring changes
Add some C tests using the C++ keyword delete
This commit is contained in:
William S Fulton 2013-11-16 00:13:38 +00:00
commit e566c5fa7f
8 changed files with 173 additions and 31 deletions

View file

@ -33,7 +33,7 @@
<li><a href="#CPlusPlus11_New_string_literals">New string literals</a> <li><a href="#CPlusPlus11_New_string_literals">New string literals</a>
<li><a href="#CPlusPlus11_User_defined_literals">User-defined literals</a> <li><a href="#CPlusPlus11_User_defined_literals">User-defined literals</a>
<li><a href="#CPlusPlus11_Thread_local_storage">Thread-local storage</a> <li><a href="#CPlusPlus11_Thread_local_storage">Thread-local storage</a>
<li><a href="#CPlusPlus11_Defaulting/deleting_of_standard_functions_on_C++_objects">Defaulting/deleting of standard functions on C++ objects</a> <li><a href="#CPlusPlus11_Defaulted_deleted">Defaulting/deleting of standard functions on C++ objects</a>
<li><a href="#CPlusPlus11_Type_long_long_int">Type long long int</a> <li><a href="#CPlusPlus11_Type_long_long_int">Type long long int</a>
<li><a href="#CPlusPlus11_Static_assertions">Static assertions</a> <li><a href="#CPlusPlus11_Static_assertions">Static assertions</a>
<li><a href="#CPlusPlus11_Allow_sizeof_to_work_on_members_of_classes_without_an_explicit_object">Allow sizeof to work on members of classes without an explicit object</a> <li><a href="#CPlusPlus11_Allow_sizeof_to_work_on_members_of_classes_without_an_explicit_object">Allow sizeof to work on members of classes without an explicit object</a>
@ -739,11 +739,11 @@ A variable will be thread local if accessed from different threads from the targ
same way that it will be thread local if accessed from C++ code. same way that it will be thread local if accessed from C++ code.
</p> </p>
<H3><a name="CPlusPlus11_Defaulting/deleting_of_standard_functions_on_C++_objects"></a>7.2.21 Defaulting/deleting of standard functions on C++ objects</H3> <H3><a name="CPlusPlus11_defaulted_deleted"></a>7.2.21 Explicitly defaulted functions and deleted functions</H3>
<p>SWIG correctly parses the <tt>= delete</tt> and <tt>= default</tt> <p>SWIG handles explicitly defaulted functions, that is, <tt>= default</tt> added to a function declaration. Deleted definitions, which are also called deleted functions, have <tt>= delete</tt> added to the function declaration.
keywords. For example:</p> For example:</p>
<div class="code"><pre> <div class="code"><pre>
struct NonCopyable { struct NonCopyable {
@ -754,8 +754,12 @@ struct NonCopyable {
}; };
</pre></div> </pre></div>
<p>This feature is specific to C++ only. The defaulting/deleting is currently ignored, because SWIG <p>
automatically produces wrappers for special constructors and operators specific to the target language.</p> Wrappers for deleted functions will not be available in the target language.
Wrappers for defaulted functions will of course be available in the target language.
Explicitly defaulted functions have no direct effect for SWIG wrapping as the declaration is handled
much like any other method declaration parsed by SWIG.
</p>
<H3><a name="CPlusPlus11_Type_long_long_int"></a>7.2.22 Type long long int</H3> <H3><a name="CPlusPlus11_Type_long_long_int"></a>7.2.22 Type long long int</H3>

View file

@ -0,0 +1,14 @@
%module c_delete
/* check C++ delete keyword is okay in C wrappers */
%inline %{
struct delete {
int delete;
};
%}
%rename(DeleteGlobalVariable) delete;
%inline %{
int delete = 0;
%}

View file

@ -0,0 +1,7 @@
%module c_delete_function
/* check C++ delete keyword is okay in C wrappers */
%inline %{
double delete(double d) { return d; }
%}

View file

@ -552,6 +552,8 @@ endif
C_TEST_CASES += \ C_TEST_CASES += \
arrays \ arrays \
bom_utf8 \ bom_utf8 \
c_delete \
c_delete_function \
char_constant \ char_constant \
const_const \ const_const \
constant_expr \ constant_expr \

View file

@ -1,9 +1,12 @@
/* This testcase checks whether SWIG correctly parses the default and delete /* This testcase checks whether SWIG correctly parses C++11 explicitly defaulted functions and deleted functions */
keywords which keep or remove default C++ object construction functions. */
%module cpp11_default_delete %module cpp11_default_delete
%{ %warnfilter(SWIGWARN_LANG_OVERLOAD_IGNORED, SWIGWARN_LANG_OVERLOAD_SHADOW) trivial::trivial(trivial&&);
#include <stdlib.h> %warnfilter(SWIGWARN_LANG_OVERLOAD_IGNORED, SWIGWARN_LANG_OVERLOAD_SHADOW) trivial::operator =(trivial&&);
%rename(Assignment) *::operator=;
%inline %{
class NonCopyable { class NonCopyable {
public: public:
@ -14,11 +17,56 @@ public:
}; };
struct A1 { struct A1 {
void f(int i); void func(int i) {}
void f(double i) = delete; /* Don't cast double to int. Compiler returns an error */ A1() = default;
~A1() = default;
void func(double i) = delete; /* Don't cast double to int. Compiler returns an error */
private:
A1(const A1&);
}; };
A1::A1(const A1&) = default;
struct A2 { struct A2 {
void f(int i); void func(int i) {}
template<class T> void f(T) = delete; /* Only accept int */ virtual void fff(int) = delete;
virtual ~A2() = default;
template<class T> void func(T) = delete;
};
struct trivial {
trivial() = default;
trivial(const trivial&) = default;
trivial(trivial&&) = default;
trivial& operator=(const trivial&) = default;
trivial& operator=(trivial&&) = default;
~trivial() = default;
};
struct nontrivial1 {
nontrivial1();
};
nontrivial1::nontrivial1() = default;
struct sometype {
sometype() = delete;
sometype(int) = delete;
sometype(double);
};
sometype::sometype(double) {}
/* Not working with prerelease of gcc-4.8
struct nonew {
void *operator new(std::size_t) = delete;
void *operator new[](std::size_t) = delete;
};
*/
struct moveonly {
moveonly() = default;
moveonly(const moveonly&) = delete;
moveonly(moveonly&&) = default;
moveonly& operator=(const moveonly&) = delete;
moveonly& operator=(moveonly&&) = default;
~moveonly() = default;
}; };
%} %}

View file

@ -728,6 +728,9 @@ int yylex(void) {
if (strcmp(yytext, "delete") == 0) { if (strcmp(yytext, "delete") == 0) {
return (DELETE_KW); return (DELETE_KW);
} }
if (strcmp(yytext, "default") == 0) {
return (DEFAULT);
}
if (strcmp(yytext, "using") == 0) { if (strcmp(yytext, "using") == 0) {
return (USING); return (USING);
} }

View file

@ -447,6 +447,14 @@ static void add_symbols(Node *n) {
n = nextSibling(n); n = nextSibling(n);
continue; continue;
} }
if (cparse_cplusplus) {
String *value = Getattr(n, "value");
if (value && Strcmp(value, "delete") == 0) {
/* C++11 deleted definition / deleted function */
SetFlag(n,"deleted");
SetFlag(n,"feature:ignore");
}
}
if (only_csymbol || GetFlag(n,"feature:ignore")) { if (only_csymbol || GetFlag(n,"feature:ignore")) {
/* Only add to C symbol table and continue */ /* Only add to C symbol table and continue */
Swig_symbol_add(0, n); Swig_symbol_add(0, n);
@ -1715,7 +1723,7 @@ static void tag_nodes(Node *n, const_String_or_char_ptr attrname, DOH *value) {
%token NATIVE INLINE %token NATIVE INLINE
%token TYPEMAP EXCEPT ECHO APPLY CLEAR SWIGTEMPLATE FRAGMENT %token TYPEMAP EXCEPT ECHO APPLY CLEAR SWIGTEMPLATE FRAGMENT
%token WARN %token WARN
%token LESSTHAN GREATERTHAN DELETE_KW %token LESSTHAN GREATERTHAN DELETE_KW DEFAULT
%token LESSTHANOREQUALTO GREATERTHANOREQUALTO EQUALTO NOTEQUALTO %token LESSTHANOREQUALTO GREATERTHANOREQUALTO EQUALTO NOTEQUALTO
%token ARROW %token ARROW
%token QUESTIONMARK %token QUESTIONMARK
@ -1775,7 +1783,7 @@ static void tag_nodes(Node *n, const_String_or_char_ptr attrname, DOH *value) {
%type <str> ellipsis variadic; %type <str> ellipsis variadic;
%type <type> type rawtype type_right anon_bitfield_type decltype ; %type <type> type rawtype type_right anon_bitfield_type decltype ;
%type <bases> base_list inherit raw_inherit; %type <bases> base_list inherit raw_inherit;
%type <dtype> definetype def_args etype; %type <dtype> definetype def_args etype default_delete deleted_definition explicit_default;
%type <dtype> expr exprnum exprcompound valexpr; %type <dtype> expr exprnum exprcompound valexpr;
%type <id> ename ; %type <id> ename ;
%type <id> template_decl; %type <id> template_decl;
@ -4696,6 +4704,8 @@ cpp_constructor_decl : storage_class type LPAREN parms RPAREN ctor_end {
Delete(code); Delete(code);
} }
SetFlag($$,"feature:new"); SetFlag($$,"feature:new");
if ($6.defarg)
Setattr($$,"value",$6.defarg);
} else { } else {
$$ = 0; $$ = 0;
} }
@ -4723,6 +4733,8 @@ cpp_destructor_decl : NOT idtemplate LPAREN parms RPAREN cpp_end {
} }
Setattr($$,"throws",$6.throws); Setattr($$,"throws",$6.throws);
Setattr($$,"throw",$6.throwf); Setattr($$,"throw",$6.throwf);
if ($6.val)
Setattr($$,"value",$6.val);
add_symbols($$); add_symbols($$);
} }
@ -4738,9 +4750,8 @@ cpp_destructor_decl : NOT idtemplate LPAREN parms RPAREN cpp_end {
Delete(name); Delete(name);
Setattr($$,"throws",$7.throws); Setattr($$,"throws",$7.throws);
Setattr($$,"throw",$7.throwf); Setattr($$,"throw",$7.throwf);
if ($7.val) { if ($7.val)
Setattr($$,"value","0"); Setattr($$,"value",$7.val);
}
if (Len(scanner_ccode)) { if (Len(scanner_ccode)) {
String *code = Copy(scanner_ccode); String *code = Copy(scanner_ccode);
Setattr($$,"code",code); Setattr($$,"code",code);
@ -4982,11 +4993,19 @@ cpp_swig_directive: pragma_directive { $$ = $1; }
cpp_end : cpp_const SEMI { cpp_end : cpp_const SEMI {
Clear(scanner_ccode); Clear(scanner_ccode);
$$.val = 0;
$$.throws = $1.throws;
$$.throwf = $1.throwf;
}
| cpp_const EQUAL default_delete SEMI {
Clear(scanner_ccode);
$$.val = $3.val;
$$.throws = $1.throws; $$.throws = $1.throws;
$$.throwf = $1.throwf; $$.throwf = $1.throwf;
} }
| cpp_const LBRACE { | cpp_const LBRACE {
skip_balanced('{','}'); skip_balanced('{','}');
$$.val = 0;
$$.throws = $1.throws; $$.throws = $1.throws;
$$.throwf = $1.throwf; $$.throwf = $1.throwf;
} }
@ -6143,11 +6162,15 @@ definetype : { /* scanner_check_typedef(); */ } expr {
} else if ($$.type != T_CHAR && $$.type != T_WSTRING && $$.type != T_WCHAR) { } else if ($$.type != T_CHAR && $$.type != T_WSTRING && $$.type != T_WCHAR) {
$$.rawval = 0; $$.rawval = 0;
} }
$$.qualifier = 0;
$$.bitfield = 0; $$.bitfield = 0;
$$.throws = 0; $$.throws = 0;
$$.throwf = 0; $$.throwf = 0;
scanner_ignore_typedef(); scanner_ignore_typedef();
} }
| default_delete {
$$ = $1;
}
/* /*
| string { | string {
$$.val = NewString($1); $$.val = NewString($1);
@ -6160,6 +6183,38 @@ definetype : { /* scanner_check_typedef(); */ } expr {
*/ */
; ;
default_delete : deleted_definition {
$$ = $1;
}
| explicit_default {
$$ = $1;
}
;
/* For C++ deleted definition '= delete' */
deleted_definition : DELETE_KW {
$$.val = NewString("delete");
$$.rawval = 0;
$$.type = T_STRING;
$$.qualifier = 0;
$$.bitfield = 0;
$$.throws = 0;
$$.throwf = 0;
}
;
/* For C++ explicitly defaulted functions '= default' */
explicit_default : DEFAULT {
$$.val = NewString("default");
$$.rawval = 0;
$$.type = T_STRING;
$$.qualifier = 0;
$$.bitfield = 0;
$$.throws = 0;
$$.throwf = 0;
}
;
/* Some stuff for handling enums */ /* Some stuff for handling enums */
ename : ID { $$ = $1; } ename : ID { $$ = $1; }
@ -6711,6 +6766,7 @@ template_decl : LESSTHAN valparms GREATERTHAN {
; ;
idstring : ID { $$ = $1; } idstring : ID { $$ = $1; }
| default_delete { $$ = $1.val; }
| string { $$ = $1; } | string { $$ = $1; }
; ;

View file

@ -659,7 +659,7 @@ Allocate():
} }
if (!Getattr(n, "allocate:has_destructor")) { if (!Getattr(n, "allocate:has_destructor")) {
/* No destructor was defined. We need to check a few things here too */ /* No destructor was defined */
List *bases = Getattr(n, "allbases"); List *bases = Getattr(n, "allbases");
int allows_destruct = 1; int allows_destruct = 1;
@ -676,13 +676,13 @@ Allocate():
} }
if (!Getattr(n, "allocate:has_assign")) { if (!Getattr(n, "allocate:has_assign")) {
/* No destructor was defined. We need to check a few things here too */ /* No assignment operator was defined */
List *bases = Getattr(n, "allbases"); List *bases = Getattr(n, "allbases");
int allows_assign = 1; int allows_assign = 1;
for (int i = 0; i < Len(bases); i++) { for (int i = 0; i < Len(bases); i++) {
Node *n = Getitem(bases, i); Node *n = Getitem(bases, i);
/* If base class does not allow default destructor, we don't allow it either */ /* If base class does not allow assignment, we don't allow it either */
if (Getattr(n, "allocate:has_assign")) { if (Getattr(n, "allocate:has_assign")) {
allows_assign = !Getattr(n, "allocate:noassign"); allows_assign = !Getattr(n, "allocate:noassign");
} }
@ -693,13 +693,13 @@ Allocate():
} }
if (!Getattr(n, "allocate:has_new")) { if (!Getattr(n, "allocate:has_new")) {
/* No destructor was defined. We need to check a few things here too */ /* No new operator was defined */
List *bases = Getattr(n, "allbases"); List *bases = Getattr(n, "allbases");
int allows_new = 1; int allows_new = 1;
for (int i = 0; i < Len(bases); i++) { for (int i = 0; i < Len(bases); i++) {
Node *n = Getitem(bases, i); Node *n = Getitem(bases, i);
/* If base class does not allow default destructor, we don't allow it either */ /* If base class does not allow new operator, we don't allow it either */
if (Getattr(n, "allocate:has_new")) { if (Getattr(n, "allocate:has_new")) {
allows_new = !Getattr(n, "allocate:nonew"); allows_new = !Getattr(n, "allocate:nonew");
} }
@ -779,18 +779,26 @@ Allocate():
if (cplus_mode != PUBLIC) { if (cplus_mode != PUBLIC) {
if (Strcmp(name, "operator =") == 0) { if (Strcmp(name, "operator =") == 0) {
/* Look for a private assignment operator */ /* Look for a private assignment operator */
if (!GetFlag(n, "deleted"))
Setattr(inclass, "allocate:has_assign", "1"); Setattr(inclass, "allocate:has_assign", "1");
Setattr(inclass, "allocate:noassign", "1"); Setattr(inclass, "allocate:noassign", "1");
} else if (Strcmp(name, "operator new") == 0) { } else if (Strcmp(name, "operator new") == 0) {
/* Look for a private new operator */ /* Look for a private new operator */
if (!GetFlag(n, "deleted"))
Setattr(inclass, "allocate:has_new", "1"); Setattr(inclass, "allocate:has_new", "1");
Setattr(inclass, "allocate:nonew", "1"); Setattr(inclass, "allocate:nonew", "1");
} }
} else { } else {
if (Strcmp(name, "operator =") == 0) { if (Strcmp(name, "operator =") == 0) {
if (!GetFlag(n, "deleted"))
Setattr(inclass, "allocate:has_assign", "1"); Setattr(inclass, "allocate:has_assign", "1");
else
Setattr(inclass, "allocate:noassign", "1");
} else if (Strcmp(name, "operator new") == 0) { } else if (Strcmp(name, "operator new") == 0) {
if (!GetFlag(n, "deleted"))
Setattr(inclass, "allocate:has_new", "1"); Setattr(inclass, "allocate:has_new", "1");
else
Setattr(inclass, "allocate:nonew", "1");
} }
/* Look for smart pointer operator */ /* Look for smart pointer operator */
if ((Strcmp(name, "operator ->") == 0) && (!GetFlag(n, "feature:ignore"))) { if ((Strcmp(name, "operator ->") == 0) && (!GetFlag(n, "feature:ignore"))) {