diff options
-rw-r--r-- | Doc/Manual/CPlusPlus11.html | 22 | ||||
-rw-r--r-- | Examples/test-suite/c_delete.i | 14 | ||||
-rw-r--r-- | Examples/test-suite/c_delete_function.i | 7 | ||||
-rw-r--r-- | Examples/test-suite/common.mk | 2 | ||||
-rw-r--r-- | Examples/test-suite/cpp11_default_delete.i | 64 | ||||
-rw-r--r-- | Source/CParse/cscanner.c | 3 | ||||
-rw-r--r-- | Source/CParse/parser.y | 66 | ||||
-rw-r--r-- | Source/Modules/allocate.cxx | 26 |
8 files changed, 173 insertions, 31 deletions
diff --git a/Doc/Manual/CPlusPlus11.html b/Doc/Manual/CPlusPlus11.html index 3caec748e..95d748791 100644 --- a/Doc/Manual/CPlusPlus11.html +++ b/Doc/Manual/CPlusPlus11.html @@ -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& operator=(const NonCopyable&) = delete; /* Removes operator= */ - NonCopyable(const NonCopyable&) = delete; /* Removed copy constructor */ - NonCopyable() = default; /* Explicitly allows the empty constructor */ - void *operator new(std::size_t) = delete; /* Removes new NonCopyable */ + NonCopyable(const NonCopyable&) = 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> diff --git a/Examples/test-suite/c_delete.i b/Examples/test-suite/c_delete.i new file mode 100644 index 000000000..d47032095 --- /dev/null +++ b/Examples/test-suite/c_delete.i @@ -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; +%} diff --git a/Examples/test-suite/c_delete_function.i b/Examples/test-suite/c_delete_function.i new file mode 100644 index 000000000..e1fba7495 --- /dev/null +++ b/Examples/test-suite/c_delete_function.i @@ -0,0 +1,7 @@ +%module c_delete_function + +/* check C++ delete keyword is okay in C wrappers */ + +%inline %{ +double delete(double d) { return d; } +%} diff --git a/Examples/test-suite/common.mk b/Examples/test-suite/common.mk index e25d36715..0d360830d 100644 --- a/Examples/test-suite/common.mk +++ b/Examples/test-suite/common.mk @@ -552,6 +552,8 @@ endif C_TEST_CASES += \ arrays \ bom_utf8 \ + c_delete \ + c_delete_function \ char_constant \ const_const \ constant_expr \ diff --git a/Examples/test-suite/cpp11_default_delete.i b/Examples/test-suite/cpp11_default_delete.i index be4cc6cc9..49a677060 100644 --- a/Examples/test-suite/cpp11_default_delete.i +++ b/Examples/test-suite/cpp11_default_delete.i @@ -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; }; %} diff --git a/Source/CParse/cscanner.c b/Source/CParse/cscanner.c index e91dfb3d3..8b484f8a7 100644 --- a/Source/CParse/cscanner.c +++ b/Source/CParse/cscanner.c @@ -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); } diff --git a/Source/CParse/parser.y b/Source/CParse/parser.y index ce0c91c43..1328d6e0d 100644 --- a/Source/CParse/parser.y +++ b/Source/CParse/parser.y @@ -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; } ; diff --git a/Source/Modules/allocate.cxx b/Source/Modules/allocate.cxx index dee044bf3..b7daae59c 100644 --- a/Source/Modules/allocate.cxx +++ b/Source/Modules/allocate.cxx @@ -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"))) { |