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_User_defined_literals">User-defined literals</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_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>
@ -739,23 +739,27 @@ 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.
</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>
keywords. For example:</p>
<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.
For example:</p>
<div class="code"><pre>
struct NonCopyable {
NonCopyable&amp; operator=(const NonCopyable&amp;) = delete; /* Removes operator= */
NonCopyable(const NonCopyable&amp;) = delete; /* Removed copy constructor */
NonCopyable() = default; /* Explicitly allows the empty constructor */
void *operator new(std::size_t) = delete; /* Removes new NonCopyable */
NonCopyable(const NonCopyable&amp;) = delete; /* Removed copy constructor */
NonCopyable() = default; /* Explicitly allows the empty constructor */
void *operator new(std::size_t) = delete; /* Removes new NonCopyable */
};
</pre></div>
<p>This feature is specific to C++ only. The defaulting/deleting is currently ignored, because SWIG
automatically produces wrappers for special constructors and operators specific to the target language.</p>
<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>

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 += \
arrays \
bom_utf8 \
c_delete \
c_delete_function \
char_constant \
const_const \
constant_expr \

View file

@ -1,9 +1,12 @@
/* This testcase checks whether SWIG correctly parses the default and delete
keywords which keep or remove default C++ object construction functions. */
/* This testcase checks whether SWIG correctly parses C++11 explicitly defaulted functions and deleted functions */
%module cpp11_default_delete
%{
#include <stdlib.h>
%warnfilter(SWIGWARN_LANG_OVERLOAD_IGNORED, SWIGWARN_LANG_OVERLOAD_SHADOW) trivial::trivial(trivial&&);
%warnfilter(SWIGWARN_LANG_OVERLOAD_IGNORED, SWIGWARN_LANG_OVERLOAD_SHADOW) trivial::operator =(trivial&&);
%rename(Assignment) *::operator=;
%inline %{
class NonCopyable {
public:
@ -14,11 +17,56 @@ public:
};
struct A1 {
void f(int i);
void f(double i) = delete; /* Don't cast double to int. Compiler returns an error */
void func(int i) {}
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 {
void f(int i);
template<class T> void f(T) = delete; /* Only accept int */
void func(int i) {}
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) {
return (DELETE_KW);
}
if (strcmp(yytext, "default") == 0) {
return (DEFAULT);
}
if (strcmp(yytext, "using") == 0) {
return (USING);
}

View file

@ -447,6 +447,14 @@ static void add_symbols(Node *n) {
n = nextSibling(n);
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")) {
/* Only add to C symbol table and continue */
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 TYPEMAP EXCEPT ECHO APPLY CLEAR SWIGTEMPLATE FRAGMENT
%token WARN
%token LESSTHAN GREATERTHAN DELETE_KW
%token LESSTHAN GREATERTHAN DELETE_KW DEFAULT
%token LESSTHANOREQUALTO GREATERTHANOREQUALTO EQUALTO NOTEQUALTO
%token ARROW
%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 <type> type rawtype type_right anon_bitfield_type decltype ;
%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 <id> ename ;
%type <id> template_decl;
@ -4696,6 +4704,8 @@ cpp_constructor_decl : storage_class type LPAREN parms RPAREN ctor_end {
Delete(code);
}
SetFlag($$,"feature:new");
if ($6.defarg)
Setattr($$,"value",$6.defarg);
} else {
$$ = 0;
}
@ -4723,6 +4733,8 @@ cpp_destructor_decl : NOT idtemplate LPAREN parms RPAREN cpp_end {
}
Setattr($$,"throws",$6.throws);
Setattr($$,"throw",$6.throwf);
if ($6.val)
Setattr($$,"value",$6.val);
add_symbols($$);
}
@ -4738,9 +4750,8 @@ cpp_destructor_decl : NOT idtemplate LPAREN parms RPAREN cpp_end {
Delete(name);
Setattr($$,"throws",$7.throws);
Setattr($$,"throw",$7.throwf);
if ($7.val) {
Setattr($$,"value","0");
}
if ($7.val)
Setattr($$,"value",$7.val);
if (Len(scanner_ccode)) {
String *code = Copy(scanner_ccode);
Setattr($$,"code",code);
@ -4982,11 +4993,19 @@ cpp_swig_directive: pragma_directive { $$ = $1; }
cpp_end : cpp_const SEMI {
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;
$$.throwf = $1.throwf;
}
| cpp_const LBRACE {
skip_balanced('{','}');
$$.val = 0;
$$.throws = $1.throws;
$$.throwf = $1.throwf;
}
@ -6143,11 +6162,15 @@ definetype : { /* scanner_check_typedef(); */ } expr {
} else if ($$.type != T_CHAR && $$.type != T_WSTRING && $$.type != T_WCHAR) {
$$.rawval = 0;
}
$$.qualifier = 0;
$$.bitfield = 0;
$$.throws = 0;
$$.throwf = 0;
scanner_ignore_typedef();
}
| default_delete {
$$ = $1;
}
/*
| string {
$$.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 */
ename : ID { $$ = $1; }
@ -6711,6 +6766,7 @@ template_decl : LESSTHAN valparms GREATERTHAN {
;
idstring : ID { $$ = $1; }
| default_delete { $$ = $1.val; }
| string { $$ = $1; }
;

View file

@ -659,7 +659,7 @@ Allocate():
}
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");
int allows_destruct = 1;
@ -676,13 +676,13 @@ Allocate():
}
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");
int allows_assign = 1;
for (int i = 0; i < Len(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")) {
allows_assign = !Getattr(n, "allocate:noassign");
}
@ -693,13 +693,13 @@ Allocate():
}
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");
int allows_new = 1;
for (int i = 0; i < Len(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")) {
allows_new = !Getattr(n, "allocate:nonew");
}
@ -779,18 +779,26 @@ Allocate():
if (cplus_mode != PUBLIC) {
if (Strcmp(name, "operator =") == 0) {
/* Look for a private assignment operator */
Setattr(inclass, "allocate:has_assign", "1");
if (!GetFlag(n, "deleted"))
Setattr(inclass, "allocate:has_assign", "1");
Setattr(inclass, "allocate:noassign", "1");
} else if (Strcmp(name, "operator new") == 0) {
/* Look for a private new operator */
Setattr(inclass, "allocate:has_new", "1");
if (!GetFlag(n, "deleted"))
Setattr(inclass, "allocate:has_new", "1");
Setattr(inclass, "allocate:nonew", "1");
}
} else {
if (Strcmp(name, "operator =") == 0) {
Setattr(inclass, "allocate:has_assign", "1");
if (!GetFlag(n, "deleted"))
Setattr(inclass, "allocate:has_assign", "1");
else
Setattr(inclass, "allocate:noassign", "1");
} else if (Strcmp(name, "operator new") == 0) {
Setattr(inclass, "allocate:has_new", "1");
if (!GetFlag(n, "deleted"))
Setattr(inclass, "allocate:has_new", "1");
else
Setattr(inclass, "allocate:nonew", "1");
}
/* Look for smart pointer operator */
if ((Strcmp(name, "operator ->") == 0) && (!GetFlag(n, "feature:ignore"))) {