Menu

#1310 std::pair referenced in wrong namespace

None
closed-fixed
nobody
python (260)
5
2022-01-06
2013-03-28
Dave Vitek
No

The test below seems to cause swig some namespace confusion. I am using the 2.0.9 release built from source on cygwin.

// swig -Wall -python -includeall -c++ -outdir python -o python/m_wrap.cpp m.i

%module m
%{
#include <utility>
%}
%include "std_pair.i"
namespace ns{
    %template(int_pair) std::pair<int,int>;
};

Here is the offending procedure:

SWIGINTERN PyObject *_wrap_new_int_pair__SWIG_2(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
  PyObject *resultobj = 0;
  pair< int,int > *arg1 = 0 ;
  void *argp1 = 0 ;
  int res1 = 0 ;
  PyObject * obj0 = 0 ;
  std::pair< int,int > *result = 0 ;

  if (!PyArg_ParseTuple(args,(char *)"O:new_int_pair",&obj0)) SWIG_fail;
  res1 = SWIG_ConvertPtr(obj0, &argp1, SWIGTYPE_p_pairT_int_int_t,  0  | 0);
  if (!SWIG_IsOK(res1)) {
    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "new_int_pair" "', argument " "1"" of type '" "pair< int,int > const &""'"); 
  }
  if (!argp1) {
    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "new_int_pair" "', argument " "1"" of type '" "pair< int,int > const &""'"); 
  }
  arg1 = reinterpret_cast< pair< int,int > * >(argp1);
  result = (std::pair< int,int > *)new std::pair< int,int >((pair< int,int > const &)*arg1);
  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_std__pairT_int_int_t, SWIG_POINTER_NEW |  0 );
  return resultobj;
fail:
  return NULL;
}

The problem is that it keeps referencing pair instead of std::pair. Furthermore, on a larger input that reuses pair more later, it ends up creating a number of references like ns::std::pair.

Discussion

  • Kris Thielemans

    Kris Thielemans - 2013-07-20

    Duplicate of [#1238]

     

    Related

    Bugs: #1238

  • Olly Betts

    Olly Betts - 2022-01-06
    • status: open --> closed-fixed
    • Group: -->
     
  • Olly Betts

    Olly Betts - 2022-01-06

    This example now gives an error:

    m.i:9: Error: 'std::pair' resolves to 'std::pair' and was incorrectly instantiated in scope 'ns' instead of within scope 'std'.
    m.i:9: Error: Template 'pair' undefined.
    

    If changed to explicitly reference std from the root by prefixing :: like so

    // swig -Wall -python -includeall -c++ -outdir python -o python/m_wrap.cpp m.i
    
    %module m
    %{
    #include <utility>
    %}
    %include "std_pair.i"
    namespace ns{
        %template(int_pair) ::std::pair<int,int>;
    };
    

    then the file processing and the generated code doesn't reference pair unqualified.

    git log -S"and was incorrectly instantiated in scope" points to 959e6272082e416303d80d7326430d1fd0b4c432 which has commit message:

    commit 959e6272082e416303d80d7326430d1fd0b4c432
    Author: William S Fulton <wsf@fultondesigns.co.uk>
    Date:   Wed Aug 9 00:06:24 2017 +0100
    
        %template scope enforcement and class definition fixes
    
        The scoping rules around %template have been specified and enforced.
        The %template directive for a class template is the equivalent to an
        explicit instantiation of a C++ class template. The scope for a valid
        %template instantiation is now the same as the scope required for a
        valid explicit instantiation of a C++ template. A definition of the
        template for the explicit instantiation must be in scope where the
        instantiation is declared and must not be enclosed within a different
        namespace.
    
        For example, a few %template and explicit instantiations of std::vector
        are shown below:
    
          // valid
          namespace std {
            %template(vin) vector<int>;
            template class vector<int>;
          }
    
          // valid
          using namespace std;
          %template(vin) vector<int>;
          template class vector<int>;
    
          // valid
          using std::vector;
          %template(vin) vector<int>;
          template class vector<int>;
    
          // ill-formed
          namespace unrelated {
            using std::vector;
            %template(vin) vector<int>;
            template class vector<int>;
          }
    
          // ill-formed
          namespace unrelated {
            using namespace std;
            %template(vin) vector<int>;
            template class vector<int>;
          }
    
          // ill-formed
          namespace unrelated {
            namespace std {
              %template(vin) vector<int>;
              template class vector<int>;
            }
          }
    
          // ill-formed
          namespace unrelated {
            %template(vin) std::vector<int>;
            template class std::vector<int>;
          }
    

    The example above is essentially the same as yours, so the error is deliberate, There's a working alternative above, so closing.

        When the scope is incorrect, an error now occurs such as:
    
        cpp_template_scope.i:34: Error: 'vector' resolves to 'std::vector' and
        was incorrectly instantiated in scope 'unrelated' instead of within scope 'std'.
    
        Previously SWIG accepted the ill-formed examples above but this led to
        numerous subtle template scope problems especially in the presence of
        using declarations and using directives as well as with %feature and %typemap.
    
        Actually, a valid instantiation is one which conforms to the C++03
        standard as C++11 made a change to disallow using declarations and
        using directives to find a template.
    
          // valid C++03, ill-formed C++11
          using std::vector;
          template class vector<int>;
    
        Similar fixes for defining classes using forward class references have
        also been put in place. For example:
    
        namespace Space1 {
          struct A;
        }
        namespace Space2 {
          struct Space1::A {
            void x();
          }
        }
    
        will now error out with:
    
        cpp_class_definition.i:5: Error: 'Space1::A' resolves to 'Space1::A' and
        was incorrectly instantiated in scope 'Space2' instead of within scope 'Space1'.
    
     

Log in to post a comment.