From cd2085aae7e34613978b372bf554aa94d8ffa3af Mon Sep 17 00:00:00 2001 From: William S Fulton Date: Fri, 28 Mar 2014 07:54:03 +0000 Subject: [PATCH] Fixes for C enums used in an API and the definition of the enum has not been parsed. For D, this fixes a segfault in SWIG. Java, C#, D, Go now produce code that compiles, although the definition of the enum is needed in order to use the enum properly from the target language. --- CHANGES.current | 3 ++ Examples/test-suite/common.mk | 1 + Examples/test-suite/enum_missing.i | 39 +++++++++++++++++++ Source/Modules/csharp.cxx | 37 ++++++++++++------ Source/Modules/d.cxx | 61 ++++++++++++++++-------------- Source/Modules/go.cxx | 37 +++++++++++++++--- Source/Modules/java.cxx | 20 ++++++++-- 7 files changed, 149 insertions(+), 49 deletions(-) create mode 100644 Examples/test-suite/enum_missing.i diff --git a/CHANGES.current b/CHANGES.current index 5c89701fc..f6b301024 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -5,5 +5,8 @@ See the RELEASENOTES file for a summary of changes in each release. Version 3.0.1 (in progress) =========================== +2014-03-28: wsfulton + [Java C# D Go] Fix for usage of snprintf in Lua runtime which Visual Studio does not have. + 2014-03-23: v-for-vandal [Lua] Fix for usage of snprintf in Lua runtime which Visual Studio does not have. diff --git a/Examples/test-suite/common.mk b/Examples/test-suite/common.mk index 9a05c531d..67f99b0b1 100644 --- a/Examples/test-suite/common.mk +++ b/Examples/test-suite/common.mk @@ -580,6 +580,7 @@ C_TEST_CASES += \ enums \ enum_forward \ enum_macro \ + enum_missing \ extern_declaration \ funcptr \ function_typedef \ diff --git a/Examples/test-suite/enum_missing.i b/Examples/test-suite/enum_missing.i new file mode 100644 index 000000000..de71952e7 --- /dev/null +++ b/Examples/test-suite/enum_missing.i @@ -0,0 +1,39 @@ +%module enum_missing + +// Test when SWIG does not parse the enum definition +%{ +enum AVPixelFormat { + AV_PIX_FMT_NONE = -1, + AV_PIX_FMT_YUV420P +}; +enum AVPixelFormat2 { + AV_PIX_FMT_NONE2 = -1, + AV_PIX_FMT_YUV420P2 +}; + +%} + +%inline %{ +typedef struct AVCodecContext { + enum AVPixelFormat pix_fmt; + enum AVPixelFormat2 pix_fmt2; +} AVCodecContext; + +enum AVPixelFormat global_fmt; +enum AVPixelFormat2 global_fmt2; + +enum AVPixelFormat use_pixel_format(enum AVPixelFormat px) { + return px; +} +enum AVPixelFormat * use_pixel_format_ptr(enum AVPixelFormat *px) { + return px; +} + +const enum AVPixelFormat2 use_pixel_format2(const enum AVPixelFormat2 px) { + return px; +} +const enum AVPixelFormat2 * use_pixel_format_ptr2(const enum AVPixelFormat2 *px) { + return px; +} +%} + diff --git a/Source/Modules/csharp.cxx b/Source/Modules/csharp.cxx index b6e0006af..e0d4a1ab1 100644 --- a/Source/Modules/csharp.cxx +++ b/Source/Modules/csharp.cxx @@ -3165,25 +3165,37 @@ public: * ----------------------------------------------------------------------------- */ void substituteClassnameSpecialVariable(SwigType *classnametype, String *tm, const char *classnamespecialvariable) { + String *replacementname; if (SwigType_isenum(classnametype)) { String *enumname = getEnumName(classnametype); - if (enumname) - Replaceall(tm, classnamespecialvariable, enumname); - else - Replaceall(tm, classnamespecialvariable, NewStringf("int")); + if (enumname) { + replacementname = Copy(enumname); + } else { + bool anonymous_enum = (Cmp(classnametype, "enum ") == 0); + if (anonymous_enum) { + replacementname = NewString("int"); + } else { + // An unknown enum - one that has not been parsed (neither a C enum forward reference nor a definition) + replacementname = SwigType_base(classnametype); + Replace(replacementname, "enum ", "", DOH_REPLACE_ANY); + Setattr(swig_types_hash, replacementname, classnametype); + } + } } else { - String *classname = getProxyName(classnametype); + String *classname = getProxyName(classnametype); // getProxyName() works for pointers to classes too if (classname) { - Replaceall(tm, classnamespecialvariable, classname); // getProxyName() works for pointers to classes too - } else { // use $descriptor if SWIG does not know anything about this type. Note that any typedefs are resolved. - String *descriptor = NewStringf("SWIGTYPE%s", SwigType_manglestr(classnametype)); - Replaceall(tm, classnamespecialvariable, descriptor); + replacementname = Copy(classname); + } else { + // use $descriptor if SWIG does not know anything about this type. Note that any typedefs are resolved. + replacementname = NewStringf("SWIGTYPE%s", SwigType_manglestr(classnametype)); // Add to hash table so that the type wrapper classes can be created later - Setattr(swig_types_hash, descriptor, classnametype); - Delete(descriptor); + Setattr(swig_types_hash, replacementname, classnametype); } } + Replaceall(tm, classnamespecialvariable, replacementname); + + Delete(replacementname); } /* ----------------------------------------------------------------------------- @@ -3273,6 +3285,9 @@ public: Replaceall(swigtype, "$imclassname", imclass_name); Replaceall(swigtype, "$dllimport", dllimport); + // For unknown enums + Replaceall(swigtype, "$enumvalues", ""); + Printv(f_swigtype, swigtype, NIL); addCloseNamespace(0, f_swigtype); diff --git a/Source/Modules/d.cxx b/Source/Modules/d.cxx index 5d59a2e38..3387dd755 100644 --- a/Source/Modules/d.cxx +++ b/Source/Modules/d.cxx @@ -568,8 +568,7 @@ public: writeTypeWrapperClass(swig_type.key, swig_type.item); } - // Add the proxy functions (and classes, if they are not written to a - // seperate file). + // Add the proxy functions (and classes, if they are not written to a separate file). replaceModuleVariables(proxy_dmodule_code); Printv(proxy_d_file, proxy_dmodule_code, NIL); @@ -1399,7 +1398,7 @@ public: // generates a getter function (which is the same as a read only property // in D) which retrieves the value via by calling the C wrapper. // Note that this is only called for global constants, static member - // constants are already handeled in staticmemberfunctionHandler(). + // constants are already handled in staticmemberfunctionHandler(). Swig_save("constantWrapper", n, "value", NIL); Swig_save("constantWrapper", n, "tmap:ctype:out", "tmap:imtype:out", "tmap:dtype:out", "tmap:out:null", "tmap:imtype:outattributes", "tmap:dtype:outattributes", NIL); @@ -3602,7 +3601,7 @@ private: * package if one is set. * * This is only used for dependencies created in generated code, user- - * (i.e. typemap-) specified import statements are handeled seperately. + * (i.e. typemap-) specified import statements are handled separately. * --------------------------------------------------------------------------- */ void requireDType(const String *nspace, const String *symname) { String *dmodule = createModuleName(nspace, symname); @@ -4054,10 +4053,10 @@ private: // TODO: Fix const-correctness of methods called in here and make type const. // We make use of the fact that this function is called at least once for - // every type encountered which is written to a seperate file, which allows + // every type encountered which is written to a separate file, which allows // us to handle imports here. // When working in split proxy module mode, each generated proxy class/enum - // is written to a seperate module. This requires us to add a corresponding + // is written to a separate module. This requires us to add a corresponding // import when a type is used in another generated module. If we are not // working in split proxy module mode, this is not relevant and the // generated module name is discarded. @@ -4066,35 +4065,39 @@ private: if (SwigType_isenum(type)) { // RESEARCH: Make sure that we really cannot get here for anonymous enums. Node *n = enumLookup(type); - String *enum_name = Getattr(n, "sym:name"); + if (n) { + String *enum_name = Getattr(n, "sym:name"); - Node *p = parentNode(n); - if (p && !Strcmp(nodeType(p), "class")) { - // This is a nested enum. - String *parent_name = Getattr(p, "sym:name"); - String *nspace = Getattr(p, "sym:nspace"); + Node *p = parentNode(n); + if (p && !Strcmp(nodeType(p), "class")) { + // This is a nested enum. + String *parent_name = Getattr(p, "sym:name"); + String *nspace = Getattr(p, "sym:nspace"); - // An enum nested in a class is not written to a seperate module (this - // would not even be possible in D), so just import the parent. - requireDType(nspace, parent_name); + // An enum nested in a class is not written to a separate module (this + // would not even be possible in D), so just import the parent. + requireDType(nspace, parent_name); - String *module = createModuleName(nspace, parent_name); - if (inProxyModule(module)) { - type_name = NewStringf("%s.%s", parent_name, enum_name); + String *module = createModuleName(nspace, parent_name); + if (inProxyModule(module)) { + type_name = NewStringf("%s.%s", parent_name, enum_name); + } else { + type_name = NewStringf("%s%s.%s.%s", package, module, parent_name, enum_name); + } } else { - type_name = NewStringf("%s%s.%s.%s", package, module, parent_name, enum_name); + // A non-nested enum is written to a separate module, import it. + String *nspace = Getattr(n, "sym:nspace"); + requireDType(nspace, enum_name); + + String *module = createModuleName(nspace, enum_name); + if (inProxyModule(module)) { + type_name = Copy(enum_name); + } else { + type_name = NewStringf("%s%s.%s", package, module, enum_name); + } } } else { - // A non-nested enum is written to a seperate module, import it. - String *nspace = Getattr(n, "sym:nspace"); - requireDType(nspace, enum_name); - - String *module = createModuleName(nspace, enum_name); - if (inProxyModule(module)) { - type_name = Copy(enum_name); - } else { - type_name = NewStringf("%s%s.%s", package, module, enum_name); - } + type_name = NewStringf("int"); } } else { Node *n = classLookup(type); diff --git a/Source/Modules/go.cxx b/Source/Modules/go.cxx index 2f28fcb03..f94921fba 100644 --- a/Source/Modules/go.cxx +++ b/Source/Modules/go.cxx @@ -79,6 +79,9 @@ class GO:public Language { bool making_variable_wrappers; // True when working with a static member function. bool is_static_member_function; + // A hash table of enum types that we have seen but which may not have + // been defined. The index is a SwigType. + Hash *undefined_enum_types; // A hash table of types that we have seen but which may not have // been defined. The index is a SwigType. Hash *undefined_types; @@ -124,6 +127,7 @@ public: class_methods(NULL), making_variable_wrappers(false), is_static_member_function(false), + undefined_enum_types(NULL), undefined_types(NULL), defined_types(NULL), go_imports(NULL) { @@ -451,6 +455,7 @@ private: // Set up the hash table for types not defined by SWIG. + undefined_enum_types = NewHash(); undefined_types = NewHash(); defined_types = NewHash(); go_imports = NewHash(); @@ -463,6 +468,13 @@ private: // Write out definitions for the types not defined by SWIG. + if (Len(undefined_enum_types) > 0) + Printv(f_go_wrappers, "\n", NULL); + for (Iterator p = First(undefined_enum_types); p.key; p = Next(p)) { + String *name = p.item; + Printv(f_go_wrappers, "type ", name, " int\n", NULL); + } + Printv(f_go_wrappers, "\n", NULL); for (Iterator p = First(undefined_types); p.key; p = Next(p)) { String *ty = goType(NULL, p.key); @@ -481,6 +493,7 @@ private: } Delete(ty); } + Delete(undefined_enum_types); Delete(undefined_types); Delete(defined_types); @@ -4494,11 +4507,18 @@ private: SwigType *t = SwigType_typedef_resolve_all(type); - Node *e = Language::enumLookup(t); - if (e) { - ret = goEnumName(e); - } else if (Strcmp(t, "enum ") == 0) { - ret = NewString("int"); + if (SwigType_isenum(t)) { + Node *e = Language::enumLookup(t); + if (e) { + ret = goEnumName(e); + } else if (Strcmp(t, "enum ") == 0) { + ret = NewString("int"); + } else { + // An unknown enum - one that has not been parsed (neither a C enum forward reference nor a definition) + ret = SwigType_base(t); + Replace(ret, "enum ", "", DOH_REPLACE_ANY); + Setattr(undefined_enum_types, t, ret); + } } else if (SwigType_isfunctionpointer(type) || SwigType_isfunction(type)) { ret = NewString("_swig_fnptr"); } else if (SwigType_ismemberpointer(type)) { @@ -4809,8 +4829,13 @@ private: } } - if (Language::enumLookup(t) != NULL || Strcmp(t, "enum ") == 0) { + if (Language::enumLookup(t) != NULL) { is_int = true; + } else { + SwigType *tstripped = SwigType_strip_qualifiers(t); + if (SwigType_isenum(tstripped)) + is_int = true; + Delete(tstripped); } Delete(t); diff --git a/Source/Modules/java.cxx b/Source/Modules/java.cxx index e8dafbc3f..53f856749 100644 --- a/Source/Modules/java.cxx +++ b/Source/Modules/java.cxx @@ -3083,10 +3083,19 @@ public: if (SwigType_isenum(classnametype)) { String *enumname = getEnumName(classnametype, jnidescriptor); - if (enumname) + if (enumname) { replacementname = Copy(enumname); - else - replacementname = NewString("int"); + } else { + bool anonymous_enum = (Cmp(classnametype, "enum ") == 0); + if (anonymous_enum) { + replacementname = NewString("int"); + } else { + // An unknown enum - one that has not been parsed (neither a C enum forward reference nor a definition) + replacementname = SwigType_base(classnametype); + Replace(replacementname, "enum ", "", DOH_REPLACE_ANY); + Setattr(swig_types_hash, replacementname, classnametype); + } + } } else { String *classname = getProxyName(classnametype, jnidescriptor); // getProxyName() works for pointers to classes too if (classname) { @@ -3186,6 +3195,11 @@ public: Replaceall(swigtype, "$javaclassname", classname); Replaceall(swigtype, "$module", module_class_name); Replaceall(swigtype, "$imclassname", imclass_name); + + // For unknown enums + Replaceall(swigtype, "$static ", ""); + Replaceall(swigtype, "$enumvalues", ""); + Printv(f_swigtype, swigtype, NIL); Delete(f_swigtype);