Add support for thread_local when specified with other legitimate storage class specifiers - extern and static
This commit is contained in:
parent
c6bc7b881f
commit
b725625e6f
15 changed files with 145 additions and 24 deletions
|
|
@ -722,17 +722,22 @@ OutputType var3 = 3.1416_suffix;
|
|||
<H3><a name="Cpp0x_Thread_local_storage"></a>7.2.20 Thread-local storage</H3>
|
||||
|
||||
|
||||
<p>SWIG correctly parses the <tt>thread_local</tt> keyword. For example, a variable
|
||||
<p>SWIG correctly parses the <tt>thread_local</tt> keyword. For example, variable
|
||||
reachable by the current thread can be defined as:</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
struct A {
|
||||
thread_local int val;
|
||||
static thread_local int val;
|
||||
};
|
||||
thread_local int global_val;
|
||||
</pre></div>
|
||||
|
||||
<p>The new C++0x threading libraries are ignored because each SWIG target language offers
|
||||
its own threading facilities.</p>
|
||||
<p>
|
||||
The use of the <tt>thread_local</tt> storage specifier does not affect the wrapping process; it does not modify
|
||||
the wrapper code compared to when it is not specified.
|
||||
A variable will be thread local if accessed from different threads from the target language in the
|
||||
same way that it will be thread local if accessed from C++ code.
|
||||
</p>
|
||||
|
||||
<H3><a name="Cpp0x_Defaulting/deleting_of_standard_functions_on_C++_objects"></a>7.2.21 Defaulting/deleting of standard functions on C++ objects</H3>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,29 @@
|
|||
/* This testcase checks whether SWIG correctly parses the 'thread_local'
|
||||
keyword before the member type and name. */
|
||||
/* This testcase checks whether SWIG correctly parses the 'thread_local' storage specifier */
|
||||
|
||||
%module cpp0x_thread_local
|
||||
|
||||
%inline %{
|
||||
struct A {
|
||||
thread_local int val;
|
||||
struct ThreadLocals {
|
||||
// thread_local int tval; // members must also be declared static
|
||||
static thread_local int stval;
|
||||
thread_local static int tsval;
|
||||
static thread_local const int stcval88 = 88;
|
||||
thread_local static const int tscval99 = 99;
|
||||
};
|
||||
thread_local int tval;
|
||||
static thread_local int stval;
|
||||
thread_local static int tsval;
|
||||
extern thread_local int etval;
|
||||
thread_local extern int teval;
|
||||
|
||||
thread_local int ThreadLocals::stval = 11;
|
||||
thread_local int ThreadLocals::tsval = 22;
|
||||
thread_local const int ThreadLocals::stcval88;
|
||||
thread_local const int ThreadLocals::tscval99;
|
||||
%}
|
||||
|
||||
%{
|
||||
// externs
|
||||
thread_local int etval = 33;
|
||||
thread_local int teval = 44;
|
||||
%}
|
||||
|
|
|
|||
43
Examples/test-suite/java/cpp0x_thread_local_runme.java
Normal file
43
Examples/test-suite/java/cpp0x_thread_local_runme.java
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
import cpp0x_thread_local.*;
|
||||
|
||||
public class cpp0x_thread_local_runme {
|
||||
|
||||
static {
|
||||
try {
|
||||
System.loadLibrary("cpp0x_thread_local");
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
System.err.println("Native code library failed to load. See the chapter on Dynamic Linking Problems in the SWIG Java documentation for help.\n" + e);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String argv[])
|
||||
{
|
||||
if (ThreadLocals.getStval() != 11)
|
||||
throw new RuntimeException();
|
||||
if (ThreadLocals.getTsval() != 22)
|
||||
throw new RuntimeException();
|
||||
if (ThreadLocals.tscval99 != 99)
|
||||
throw new RuntimeException();
|
||||
|
||||
cpp0x_thread_local.setEtval(-11);
|
||||
if (cpp0x_thread_local.getEtval() != -11)
|
||||
throw new RuntimeException();
|
||||
|
||||
cpp0x_thread_local.setStval(-22);
|
||||
if (cpp0x_thread_local.getStval() != -22)
|
||||
throw new RuntimeException();
|
||||
|
||||
cpp0x_thread_local.setTsval(-33);
|
||||
if (cpp0x_thread_local.getTsval() != -33)
|
||||
throw new RuntimeException();
|
||||
|
||||
cpp0x_thread_local.setEtval(-44);
|
||||
if (cpp0x_thread_local.getEtval() != -44)
|
||||
throw new RuntimeException();
|
||||
|
||||
cpp0x_thread_local.setTeval(-55);
|
||||
if (cpp0x_thread_local.getTeval() != -55)
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
30
Examples/test-suite/python/cpp0x_thread_local_runme.py
Normal file
30
Examples/test-suite/python/cpp0x_thread_local_runme.py
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
from cpp0x_thread_local import *
|
||||
|
||||
t = ThreadLocals()
|
||||
if t.stval != 11:
|
||||
raise RuntimeError
|
||||
if t.tsval != 22:
|
||||
raise RuntimeError
|
||||
if t.tscval99 != 99:
|
||||
raise RuntimeError
|
||||
|
||||
cvar.etval = -11
|
||||
if cvar.etval != -11:
|
||||
raise RuntimeError
|
||||
|
||||
cvar.stval = -22
|
||||
if cvar.stval != -22:
|
||||
raise RuntimeError
|
||||
|
||||
cvar.tsval = -33
|
||||
if cvar.tsval != -33:
|
||||
raise RuntimeError
|
||||
|
||||
cvar.etval = -44
|
||||
if cvar.etval != -44:
|
||||
raise RuntimeError
|
||||
|
||||
cvar.teval = -55
|
||||
if cvar.teval != -55:
|
||||
raise RuntimeError
|
||||
|
||||
|
|
@ -5041,6 +5041,10 @@ storage_class : EXTERN { $$ = "extern"; }
|
|||
| EXPLICIT { $$ = "explicit"; }
|
||||
| CONSTEXPR { $$ = "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; }
|
||||
;
|
||||
|
||||
|
|
|
|||
|
|
@ -771,7 +771,7 @@ Allocate():
|
|||
/* Check to see if this is a static member or not. If so, we add an attribute
|
||||
cplus:staticbase that saves the current class */
|
||||
|
||||
if (checkAttribute(n, "storage", "static")) {
|
||||
if (Swig_storage_isstatic(n)) {
|
||||
Setattr(n, "cplus:staticbase", inclass);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -307,7 +307,7 @@ int Contracts::cDeclaration(Node *n) {
|
|||
return SWIG_OK;
|
||||
|
||||
if (Getattr(n, "feature:contract"))
|
||||
ret = emit_contract(n, (InClass && !checkAttribute(n, "storage", "static")));
|
||||
ret = emit_contract(n, InClass && !Swig_storage_isstatic(n));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -275,8 +275,8 @@ String *Swig_method_decl(SwigType *rettype, SwigType *decl, const_String_or_char
|
|||
void Swig_director_emit_dynamic_cast(Node *n, Wrapper *f) {
|
||||
// TODO: why is the storage element removed in staticmemberfunctionHandler ??
|
||||
if ((!is_public(n) && (is_member_director(n) || GetFlag(n, "explicitcall"))) ||
|
||||
(is_non_virtual_protected_access(n) && !(checkAttribute(n, "staticmemberfunctionHandler:storage", "static") ||
|
||||
checkAttribute(n, "storage", "static"))
|
||||
(is_non_virtual_protected_access(n) && !(Swig_storage_isstatic_custom(n, "staticmemberfunctionHandler:storage") ||
|
||||
Swig_storage_isstatic(n))
|
||||
&& !Equal(nodeType(n), "constructor"))) {
|
||||
Node *parent = Getattr(n, "parentNode");
|
||||
String *dirname;
|
||||
|
|
|
|||
|
|
@ -1611,7 +1611,7 @@ private:
|
|||
return goComplexConstant(n, type);
|
||||
}
|
||||
|
||||
if (Getattr(n, "storage") && Strcmp(Getattr(n, "storage"), "static") == 0) {
|
||||
if (Swig_storage_isstatic(n)) {
|
||||
return goComplexConstant(n, type);
|
||||
}
|
||||
|
||||
|
|
@ -4860,7 +4860,7 @@ private:
|
|||
|
||||
bool isStatic(Node *n) {
|
||||
String *storage = Getattr(n, "storage");
|
||||
return (storage && (Strcmp(storage, "static") == 0 || Strcmp(storage, "friend") == 0) && (!SmartPointer || !Getattr(n, "allocate:smartpointeraccess")));
|
||||
return (storage && (Swig_storage_isstatic(n) || Strcmp(storage, "friend") == 0) && (!SmartPointer || !Getattr(n, "allocate:smartpointeraccess")));
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -1058,7 +1058,7 @@ int Language::cDeclaration(Node *n) {
|
|||
int Language::functionHandler(Node *n) {
|
||||
String *storage = Getattr(n, "storage");
|
||||
int isfriend = CurrentClass && Cmp(storage, "friend") == 0;
|
||||
int isstatic = CurrentClass && Cmp(storage, "static") == 0 && !(SmartPointer && Getattr(n, "allocate:smartpointeraccess"));
|
||||
int isstatic = CurrentClass && Swig_storage_isstatic(n) && !(SmartPointer && Getattr(n, "allocate:smartpointeraccess"));
|
||||
Parm *p = Getattr(n, "parms");
|
||||
if (GetFlag(n, "feature:del")) {
|
||||
/* the method acts like a delete operator, ie, we need to disown the parameter */
|
||||
|
|
@ -1366,7 +1366,6 @@ int Language::variableHandler(Node *n) {
|
|||
if (!CurrentClass) {
|
||||
globalvariableHandler(n);
|
||||
} else {
|
||||
String *storage = Getattr(n, "storage");
|
||||
Swig_save("variableHandler", n, "feature:immutable", NIL);
|
||||
if (SmartPointer) {
|
||||
/* If a smart-pointer and it's a constant access, we have to set immutable */
|
||||
|
|
@ -1374,7 +1373,7 @@ int Language::variableHandler(Node *n) {
|
|||
SetFlag(n, "feature:immutable");
|
||||
}
|
||||
}
|
||||
if ((Cmp(storage, "static") == 0) && !(SmartPointer && Getattr(n, "allocate:smartpointeraccess"))) {
|
||||
if (Swig_storage_isstatic(n) && !(SmartPointer && Getattr(n, "allocate:smartpointeraccess"))) {
|
||||
staticmembervariableHandler(n);
|
||||
} else {
|
||||
membervariableHandler(n);
|
||||
|
|
@ -1428,7 +1427,7 @@ int Language::membervariableHandler(Node *n) {
|
|||
String *target = 0;
|
||||
if (!Extend) {
|
||||
if (SmartPointer) {
|
||||
if (checkAttribute(n, "storage", "static")) {
|
||||
if (Swig_storage_isstatic(n)) {
|
||||
Node *sn = Getattr(n, "cplus:staticbase");
|
||||
String *base = Getattr(sn, "name");
|
||||
target = NewStringf("%s::%s", base, name);
|
||||
|
|
|
|||
|
|
@ -995,7 +995,7 @@ class TypePass:private Dispatcher {
|
|||
String *symname = Getattr(n, "sym:name");
|
||||
while (c) {
|
||||
if (Strcmp(nodeType(c), "cdecl") == 0) {
|
||||
if (!(checkAttribute(c, "storage", "static")
|
||||
if (!(Swig_storage_isstatic(c)
|
||||
|| checkAttribute(c, "storage", "typedef")
|
||||
|| checkAttribute(c, "storage", "friend")
|
||||
|| (Getattr(c, "feature:extend") && !Getattr(c, "code"))
|
||||
|
|
|
|||
|
|
@ -922,7 +922,7 @@ int Swig_MethodToFunction(Node *n, const_String_or_char_ptr nspace, String *clas
|
|||
self = NewString("(*(this))->");
|
||||
is_smart_pointer_overload = 1;
|
||||
}
|
||||
else if (Cmp(Getattr(n, "storage"), "static") == 0) {
|
||||
else if (Swig_storage_isstatic(n)) {
|
||||
String *cname = Getattr(n, "classname") ? Getattr(n, "classname") : classname;
|
||||
String *ctname = SwigType_namestr(cname);
|
||||
self = NewStringf("(*(%s const *)this)->", ctname);
|
||||
|
|
@ -1064,7 +1064,7 @@ int Swig_MethodToFunction(Node *n, const_String_or_char_ptr nspace, String *clas
|
|||
String *func = NewStringf("%s(", mangled);
|
||||
String *cres;
|
||||
|
||||
if (Cmp(Getattr(n, "storage"), "static") != 0) {
|
||||
if (!Swig_storage_isstatic(n)) {
|
||||
String *pname = Swig_cparm_name(pp, i);
|
||||
String *ctname = SwigType_namestr(cname);
|
||||
String *fadd = 0;
|
||||
|
|
@ -1467,7 +1467,7 @@ int Swig_MembergetToFunction(Node *n, String *classname, int flags) {
|
|||
int varcref = flags & CWRAP_NATURAL_VAR;
|
||||
|
||||
if (flags & CWRAP_SMART_POINTER) {
|
||||
if (checkAttribute(n, "storage", "static")) {
|
||||
if (Swig_storage_isstatic(n)) {
|
||||
Node *sn = Getattr(n, "cplus:staticbase");
|
||||
String *base = Getattr(sn, "name");
|
||||
self = NewStringf("%s::", base);
|
||||
|
|
|
|||
|
|
@ -262,6 +262,27 @@ void Swig_filename_unescape(String *filename) {
|
|||
#endif
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Swig_storage_isstatic_custom()
|
||||
*
|
||||
* Determine if the storage class specifier is static
|
||||
* ----------------------------------------------------------------------------- */
|
||||
|
||||
int Swig_storage_isstatic_custom(Node *n, const_String_or_char_ptr storage_name) {
|
||||
const String *storage = Getattr(n, storage_name);
|
||||
return storage ? Strncmp(storage, "static", 6) == 0 : 0;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Swig_storage_isstatic()
|
||||
*
|
||||
* Determine if the storage class specifier is static
|
||||
* ----------------------------------------------------------------------------- */
|
||||
|
||||
int Swig_storage_isstatic(Node *n) {
|
||||
return Swig_storage_isstatic_custom(n, "storage");
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Swig_string_escape()
|
||||
*
|
||||
|
|
|
|||
|
|
@ -938,8 +938,7 @@ static int nodes_are_equivalent(Node *a, Node *b, int a_inclass) {
|
|||
}
|
||||
|
||||
/* static functions */
|
||||
if ((Cmp(a_storage, "static") == 0)
|
||||
|| (Cmp(b_storage, "static") == 0)) {
|
||||
if (Swig_storage_isstatic(a) || Swig_storage_isstatic(b)) {
|
||||
if (Cmp(a_storage, b_storage) != 0)
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -315,6 +315,8 @@ extern int ParmList_is_compactdefargs(ParmList *p);
|
|||
extern void Swig_filename_correct(String *filename);
|
||||
extern String *Swig_filename_escape(String *filename);
|
||||
extern void Swig_filename_unescape(String *filename);
|
||||
extern int Swig_storage_isstatic_custom(Node *n, const_String_or_char_ptr storage);
|
||||
extern int Swig_storage_isstatic(Node *n);
|
||||
extern String *Swig_string_escape(String *s);
|
||||
extern String *Swig_string_mangle(const String *s);
|
||||
extern void Swig_scopename_split(const String *s, String **prefix, String **last);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue