swig / swig

SWIG is a software development tool that connects programs written in C and C++ with a variety of high-level programming languages.
http://www.swig.org
Other
5.96k stars 1.26k forks source link

Incorrect enum qualification of typedef to anonymous enum #3012

Open ojwb opened 7 months ago

ojwb commented 7 months ago

This has been reported multiple times over the years, often conflated with related but separate issues with a superficially similar qualifying problem with C++11 enum class. Opening one issue to bring all these together in one place (and because I think I've fixed the other issue so those other issues will be closed soon).

Seems to be in generic code as it affects most (probably all) target languages.

https://sourceforge.net/p/swig/bugs/682/

Reproducer:

%module x
%inline %{
typedef enum { BAZ1 } baz;
void enumbugexample( baz const & ) { }
%}

Then:

$ swig -c++ -python simplified.i
$ grep 'enum baz' simplified_wrap.cxx
  enumbugexample((enum baz const &)*arg1);
static swig_type_info _swigt__p_baz = {"_p_baz", "baz *|enum baz *", 0, 0, (void*)0, 0};

The const & seems to be needed.

I notice the type info entry includes enum baz * which seems wrong too.

https://sourceforge.net/p/swig/bugs/923/

Reproducer:

%module test
%inline %{
class VR
{
public:
typedef enum {
Foo
} VRType;
static bool IsValid(const char *vr1, const VRType &vr2);
};
%}
$ swig -c++ -python test.i
$ g++ -Wall -W `python3-config --cflags` test_wrap.cxx -shared -o demo.so
test_wrap.cxx: In function ‘PyObject* _wrap_VR_IsValid(PyObject*, PyObject*)’:
test_wrap.cxx:3413:59: error: using typedef-name ‘VR::VRType’ after ‘enum’
 3413 |   result = (bool)VR::IsValid((char const *)arg1,(enum VR::VRType const &)*arg2);
      |                                                           ^~~~~~
test_wrap.cxx:3090:3: note: ‘VR::VRType’ has a previous declaration here
 3090 | } VRType;
      |   ^~~~~~
test_wrap.cxx:3413:50: error: expected primary-expression before ‘enum’
 3413 |   result = (bool)VR::IsValid((char const *)arg1,(enum VR::VRType const &)*arg2);
      |                                                  ^~~~
test_wrap.cxx:3413:50: error: expected ‘)’ before ‘enum’
 3413 |   result = (bool)VR::IsValid((char const *)arg1,(enum VR::VRType const &)*arg2);
      |                                                 ~^~~~
      |                                                  )

197

The original report is a different issue with C++11 class enum, but the second example there a typedef to an anonymous enum.

Reproducer:

%module y
%inline %{
template <class E, class T> struct TypedEnum {
    typedef T TargetType;
    typedef E EnumType;
    TypedEnum(): _value(E()) { }
    TypedEnum(E value) { _value = static_cast<T>(value); }
    operator E() const { return static_cast<E>(_value); }
private:
    T _value;
};

typedef enum { X } s;

typedef TypedEnum<s, int> sensor_status; 
%}

%include std_vector.i

%template(SensorStatusSet) std::vector< TypedEnum< s, int > >;

The problem here is that SWIG generates enum s but s is a typedef to an enum, not an enum itself, and GCC gives an error:

test2_wrap.cxx:4719:41: error: using typedef-name ‘s’ after ‘enum’
 4719 | SWIGINTERN std::vector< TypedEnum< enum s,int > >::size_type std_vector_Sl_TypedEnum_Sl_s_Sc_int_Sg__Sg____len__(std::vector< TypedEnum< s,int > > const *self){
      |                                         ^
ojwb commented 7 months ago

-debug-typedef for the first example above says:

SCOPES start  =======================================
-------------------------------------------------------------
Type scope '' (0x7f815ce00b10)
                                     baz -> enum baz
-------------------------------------------------------------
Type scope 'swig::SwigVar_PyObject' (0x7f815cf4bf70)
-------------------------------------------------------------
Type scope 'swig::SwigPtr_PyObject' (0x7f815cf4bd10)
-------------------------------------------------------------
Type scope 'swig' (0x7f815cf4ba30)
                        SwigPtr_PyObject -> SwigPtr_PyObject
                        SwigVar_PyObject -> SwigVar_PyObject
-------------------------------------------------------------
Type scope 'std' (0x7f815cf4b950)
                        initializer_list -> initializer_list
SCOPES finish =======================================
jschueller commented 2 months ago

can also happen with pointer (#3120):

%module example

%inline %{
typedef enum {E1, E2} enum_type1;
void foo(const enum_type1 **const bar);
%}