Code::Blocks Forums

Developer forums (C::B DEVELOPMENT STRICTLY!) => Development => CodeCompletion redesign => Topic started by: killerbot on August 29, 2011, 11:34:27 pm

Title: CC no longer working for unique_ptr
Post by: killerbot on August 29, 2011, 11:34:27 pm
Consider the following code in a console app's main.cpp :

Code
#include <iostream>
#include <memory>

class Test
{
public:
void doSomething();
};

int main()
{
std::unique_ptr<int> foo(new int());

foo.

std::unique_ptr<Test> bar(new Test());

bar->

    return 0;
}

1) When the "." after foo has been typed --> no CC suggestions (at least there should be get/release/...).
This used to work.

2) When the "->" after bar has been typed --> no CC suggestions ( there should be doSomething)
This used to work.

Could this be fixed ?

Tested on rev 7439
Title: Re: CC no longer working for unique_ptr
Post by: oBFusCATed on August 30, 2011, 12:52:39 am
Hm, Are you sure this has ever worked?
As far as I know the -> operator overloading is not parsed by the CC.
Title: Re: CC no longer working for unique_ptr
Post by: Loaden on August 30, 2011, 01:24:44 am
Make sure use --std=c++0x option?
Works well here.
Title: Re: CC no longer working for unique_ptr
Post by: Jenna on August 30, 2011, 07:19:53 am
Make sure use --std=c++0x option?
Works well here.
Does not work here (latest trunk on debian 64-bit, with some modifications not related to CC) with or without the option.
Title: Re: CC no longer working for unique_ptr
Post by: ollydbg on August 30, 2011, 07:33:27 am
Make sure use --std=c++0x option?
Works well here.
@loaden
Did you think CC is respect to the compiler command option?
I don't think so.

I will test the latest trunk.

EDIT:
killerbot's test failed with both --std=c++0x or not.

Title: Re: CC no longer working for unique_ptr
Post by: killerbot on August 30, 2011, 07:45:25 am
Hm, Are you sure this has ever worked?
As far as I know the -> operator overloading is not parsed by the CC.

Yes I am sure. I remember that once I filed a request to support this, and the next day it was implemented by our CC gurus.
But I guess with all the latest modifications to CC, it got broken ?
Title: Re: CC no longer working for unique_ptr
Post by: ollydbg on August 30, 2011, 07:56:08 am
Hm, Are you sure this has ever worked?
As far as I know the -> operator overloading is not parsed by the CC.

Yes I am sure. I remember that once I filed a request to support this, and the next day it was implemented by our CC gurus.
But I guess with all the latest modifications to CC, it got broken ?
The operators "->" and "." were handled when doing the suggestion list.
But they were not handled in patch parsing stage.
The major work was done by "blueshake" to give the suggestion on templates. He is not active in this forum about one year (due to heavy work)

Yes, I guess it was broken some days later.
I'm not satisfied with those code. It was too complex and not easy to debug and trace.
Title: Re: CC no longer working for unique_ptr
Post by: Loaden on August 30, 2011, 08:38:01 am
Make sure use --std=c++0x option?
Works well here.
Does not work here (latest trunk on debian 64-bit, with some modifications not related to CC) with or without the option.
Remember reparse the project.
I am using Linux Mint 11 64-bit, it's works well.
And now I am test it on Windows 7 32-bit, And it's works too.
Title: Re: CC no longer working for unique_ptr
Post by: Loaden on August 30, 2011, 08:50:28 am
I am only test it with MinGW TDM 4.5.2 and GCC 4.5.2.
I guess it's don't work with GCC 4.6.x, In GCC 4.6.x, there has more changes with namespace.
Maybe the unique_ptr is in global namespace.

So, try:
Code
#include <iostream>
#include <memory>

class Test
{
public:
void doSomething();
};

int main()
{
unique_ptr<int> foo(new int());

// foo.

unique_ptr<Test> bar(new Test());

// bar->

    return 0;
}
Title: Re: CC no longer working for unique_ptr
Post by: ollydbg on August 30, 2011, 09:02:29 am
It's still in std namespace.
It sounds like we should add some extra macro replacement rule, look at this:
D:\code\mingw_gcc4.6.1release_static_win32\lib\gcc\i686-pc-mingw32\4.6.1\include\c++\bits\unique_ptr.h
Code
// unique_ptr implementation -*- C++ -*-

// Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library.  This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.

// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
// <http://www.gnu.org/licenses/>.

/** @file bits/unique_ptr.h
 *  This is an internal header file, included by other library headers.
 *  Do not attempt to use it directly. @headername{memory}
 */

#ifndef _UNIQUE_PTR_H
#define _UNIQUE_PTR_H 1

#include <bits/c++config.h>
#include <debug/debug.h>
#include <type_traits>
#include <utility>
#include <tuple>

namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION

  /**
   * @addtogroup pointer_abstractions
   * @{
   */

  /// Primary template, default_delete.
  template<typename _Tp>
    struct default_delete
    {
      constexpr default_delete() = default;

      template<typename _Up, typename = typename
       std::enable_if<std::is_convertible<_Up*, _Tp*>::value>::type>
        default_delete(const default_delete<_Up>&) { }

      void
      operator()(_Tp* __ptr) const
      {
static_assert(sizeof(_Tp)>0,
      "can't delete pointer to incomplete type");
delete __ptr;
      }
    };

  // _GLIBCXX_RESOLVE_LIB_DEFECTS
  // DR 740 - omit specialization for array objects with a compile time length
  /// Specialization, default_delete.
  template<typename _Tp>
    struct default_delete<_Tp[]>
    {
      constexpr default_delete() = default;

      void
      operator()(_Tp* __ptr) const
      {
static_assert(sizeof(_Tp)>0,
      "can't delete pointer to incomplete type");
delete [] __ptr;
      }

      template<typename _Up> void operator()(_Up*) const = delete;
    };

  /// 20.7.12.2 unique_ptr for single objects.
  template <typename _Tp, typename _Dp = default_delete<_Tp> >
    class unique_ptr
    {
      // use SFINAE to determine whether _Del::pointer exists
      class _Pointer
      {
template<typename _Up>
  static typename _Up::pointer __test(typename _Up::pointer*);

template<typename _Up>
  static _Tp* __test(...);

typedef typename remove_reference<_Dp>::type _Del;

      public:
typedef decltype( __test<_Del>(0)) type;
      };

      typedef std::tuple<typename _Pointer::type, _Dp>  __tuple_type;
      __tuple_type                                      _M_t;

    public:
      typedef typename _Pointer::type   pointer;
      typedef _Tp                       element_type;
      typedef _Dp                       deleter_type;

      // Constructors.
      constexpr unique_ptr()
      : _M_t()
      { static_assert(!std::is_pointer<deleter_type>::value,
     "constructed with null function pointer deleter"); }

      explicit
      unique_ptr(pointer __p)
      : _M_t(__p, deleter_type())
      { static_assert(!std::is_pointer<deleter_type>::value,
     "constructed with null function pointer deleter"); }

      unique_ptr(pointer __p,
  typename std::conditional<std::is_reference<deleter_type>::value,
    deleter_type, const deleter_type&>::type __d)
      : _M_t(__p, __d) { }

      unique_ptr(pointer __p,
  typename std::remove_reference<deleter_type>::type&& __d)
      : _M_t(std::move(__p), std::move(__d))
      { static_assert(!std::is_reference<deleter_type>::value,
      "rvalue deleter bound to reference"); }

      constexpr unique_ptr(nullptr_t)
      : _M_t()
      { static_assert(!std::is_pointer<deleter_type>::value,
     "constructed with null function pointer deleter"); }

      // Move constructors.
      unique_ptr(unique_ptr&& __u)
      : _M_t(__u.release(), std::forward<deleter_type>(__u.get_deleter())) { }

      template<typename _Up, typename _Ep, typename = typename
std::enable_if
  <std::is_convertible<typename unique_ptr<_Up, _Ep>::pointer,
       pointer>::value
   && !std::is_array<_Up>::value
   && ((std::is_reference<_Dp>::value
&& std::is_same<_Ep, _Dp>::value)
       || (!std::is_reference<_Dp>::value
   && std::is_convertible<_Ep, _Dp>::value))>
     ::type>
unique_ptr(unique_ptr<_Up, _Ep>&& __u)
: _M_t(__u.release(), std::forward<_Ep>(__u.get_deleter()))
{ }

#if _GLIBCXX_USE_DEPRECATED
      template<typename _Up, typename = typename
std::enable_if<std::is_convertible<_Up*, _Tp*>::value
       && std::is_same<_Dp,
       default_delete<_Tp>>::value>::type>
unique_ptr(auto_ptr<_Up>&& __u)
: _M_t(__u.release(), deleter_type()) { }
#endif

      // Destructor.
      ~unique_ptr() { reset(); }

      // Assignment.
      unique_ptr&
      operator=(unique_ptr&& __u)
      {
reset(__u.release());
get_deleter() = std::forward<deleter_type>(__u.get_deleter());
return *this;
      }

      template<typename _Up, typename _Ep, typename = typename
std::enable_if
  <std::is_convertible<typename unique_ptr<_Up, _Ep>::pointer,
       pointer>::value
   && !std::is_array<_Up>::value>::type>
unique_ptr&
operator=(unique_ptr<_Up, _Ep>&& __u)
{
  reset(__u.release());
  get_deleter() = std::forward<_Ep>(__u.get_deleter());
  return *this;
}

      unique_ptr&
      operator=(nullptr_t)
      {
reset();
return *this;
      }

      // Observers.
      typename std::add_lvalue_reference<element_type>::type
      operator*() const
      {
_GLIBCXX_DEBUG_ASSERT(get() != pointer());
return *get();
      }

      pointer
      operator->() const
      {
_GLIBCXX_DEBUG_ASSERT(get() != pointer());
return get();
      }

      pointer
      get() const
      { return std::get<0>(_M_t); }

      deleter_type&
      get_deleter()
      { return std::get<1>(_M_t); }

      const deleter_type&
      get_deleter() const
      { return std::get<1>(_M_t); }

      explicit operator bool() const
      { return get() == pointer() ? false : true; }

      // Modifiers.
      pointer
      release()
      {
pointer __p = get();
std::get<0>(_M_t) = pointer();
return __p;
      }

      void
      reset(pointer __p = pointer())
      {
using std::swap;
swap(std::get<0>(_M_t), __p);
if (__p != pointer())
  get_deleter()(__p);
      }

      void
      swap(unique_ptr& __u)
      {
using std::swap;
swap(_M_t, __u._M_t);
      }

      // Disable copy from lvalue.
      unique_ptr(const unique_ptr&) = delete;
      unique_ptr& operator=(const unique_ptr&) = delete;
  };

  /// 20.7.12.3 unique_ptr for array objects with a runtime length
  // [unique.ptr.runtime]
  // _GLIBCXX_RESOLVE_LIB_DEFECTS
  // DR 740 - omit specialization for array objects with a compile time length
  template<typename _Tp, typename _Dp>
    class unique_ptr<_Tp[], _Dp>
    {
      typedef std::tuple<_Tp*, _Dp>  __tuple_type;
      __tuple_type _M_t;

    public:
      typedef _Tp* pointer;
      typedef _Tp element_type;
      typedef _Dp                       deleter_type;

      // Constructors.
      constexpr unique_ptr()
      : _M_t()
      { static_assert(!std::is_pointer<deleter_type>::value,
     "constructed with null function pointer deleter"); }

      explicit
      unique_ptr(pointer __p)
      : _M_t(__p, deleter_type())
      { static_assert(!std::is_pointer<deleter_type>::value,
     "constructed with null function pointer deleter"); }

      unique_ptr(pointer __p,
  typename std::conditional<std::is_reference<deleter_type>::value,
      deleter_type, const deleter_type&>::type __d)
      : _M_t(__p, __d) { }

      unique_ptr(pointer __p,
typename std::remove_reference<deleter_type>::type && __d)
      : _M_t(std::move(__p), std::move(__d))
      { static_assert(!std::is_reference<deleter_type>::value,
      "rvalue deleter bound to reference"); }

      constexpr unique_ptr(nullptr_t)
      : _M_t()
      { static_assert(!std::is_pointer<deleter_type>::value,
     "constructed with null function pointer deleter"); }

      // Move constructors.
      unique_ptr(unique_ptr&& __u)
      : _M_t(__u.release(), std::forward<deleter_type>(__u.get_deleter())) { }

      template<typename _Up, typename _Ep>
unique_ptr(unique_ptr<_Up, _Ep>&& __u)
: _M_t(__u.release(), std::forward<_Ep>(__u.get_deleter()))
{ }

      // Destructor.
      ~unique_ptr() { reset(); }

      // Assignment.
      unique_ptr&
      operator=(unique_ptr&& __u)
      {
reset(__u.release());
get_deleter() = std::forward<deleter_type>(__u.get_deleter());
return *this;
      }

      template<typename _Up, typename _Ep>
unique_ptr&
operator=(unique_ptr<_Up, _Ep>&& __u)
{
  reset(__u.release());
  get_deleter() = std::forward<_Ep>(__u.get_deleter());
  return *this;
}

      unique_ptr&
      operator=(nullptr_t)
      {
reset();
return *this;
      }

      // Observers.
      typename std::add_lvalue_reference<element_type>::type
      operator[](size_t __i) const
      {
_GLIBCXX_DEBUG_ASSERT(get() != pointer());
return get()[__i];
      }

      pointer
      get() const
      { return std::get<0>(_M_t); }

      deleter_type&
      get_deleter()
      { return std::get<1>(_M_t); }

      const deleter_type&
      get_deleter() const
      { return std::get<1>(_M_t); }

      explicit operator bool() const
      { return get() == pointer() ? false : true; }

      // Modifiers.
      pointer
      release()
      {
pointer __p = get();
std::get<0>(_M_t) = pointer();
return __p;
      }

      void
      reset(pointer __p = pointer())
      {
using std::swap;
swap(std::get<0>(_M_t), __p);
if (__p != nullptr)
  get_deleter()(__p);
      }

      void
      reset(nullptr_t)
      {
pointer __p = get();
std::get<0>(_M_t) = pointer();
if (__p != nullptr)
  get_deleter()(__p);
      }

      // DR 821.
      template<typename _Up>
void reset(_Up) = delete;

      void
      swap(unique_ptr& __u)
      {
using std::swap;
swap(_M_t, __u._M_t);
      }

      // Disable copy from lvalue.
      unique_ptr(const unique_ptr&) = delete;
      unique_ptr& operator=(const unique_ptr&) = delete;

      // Disable construction from convertible pointer types.
      // (N2315 - 20.6.5.3.1)
      template<typename _Up>
unique_ptr(_Up*, typename
   std::conditional<std::is_reference<deleter_type>::value,
   deleter_type, const deleter_type&>::type,
   typename std::enable_if<std::is_convertible<_Up*,
   pointer>::value>::type* = 0) = delete;

      template<typename _Up>
unique_ptr(_Up*, typename std::remove_reference<deleter_type>::type&&,
   typename std::enable_if<std::is_convertible<_Up*,
   pointer>::value>::type* = 0) = delete;

      template<typename _Up>
explicit
unique_ptr(_Up*, typename std::enable_if<std::is_convertible<_Up*,
   pointer>::value>::type* = 0) = delete;
  };

  template<typename _Tp, typename _Dp>
    inline void
    swap(unique_ptr<_Tp, _Dp>& __x,
unique_ptr<_Tp, _Dp>& __y)
    { __x.swap(__y); }

  template<typename _Tp, typename _Dp,
   typename _Up, typename _Ep>
    inline bool
    operator==(const unique_ptr<_Tp, _Dp>& __x,
       const unique_ptr<_Up, _Ep>& __y)
    { return __x.get() == __y.get(); }

  template<typename _Tp, typename _Dp>
    inline bool
    operator==(const unique_ptr<_Tp, _Dp>& __x, nullptr_t)
    { return __x.get() == nullptr; }

  template<typename _Tp, typename _Dp>
    inline bool
    operator==(nullptr_t, const unique_ptr<_Tp, _Dp>& __y)
    { return nullptr == __y.get(); }

  template<typename _Tp, typename _Dp,
   typename _Up, typename _Ep>
    inline bool
    operator!=(const unique_ptr<_Tp, _Dp>& __x,
       const unique_ptr<_Up, _Ep>& __y)
    { return !(__x.get() == __y.get()); }

  template<typename _Tp, typename _Dp>
    inline bool
    operator!=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t)
    { return __x.get() != nullptr; }

  template<typename _Tp, typename _Dp>
    inline bool
    operator!=(nullptr_t, const unique_ptr<_Tp, _Dp>& __y)
    { return nullptr != __y.get(); }

  template<typename _Tp, typename _Dp,
   typename _Up, typename _Ep>
    inline bool
    operator<(const unique_ptr<_Tp, _Dp>& __x,
      const unique_ptr<_Up, _Ep>& __y)
    { return __x.get() < __y.get(); }

  template<typename _Tp, typename _Dp,
   typename _Up, typename _Ep>
    inline bool
    operator<=(const unique_ptr<_Tp, _Dp>& __x,
       const unique_ptr<_Up, _Ep>& __y)
    { return !(__y.get() < __x.get()); }

  template<typename _Tp, typename _Dp,
   typename _Up, typename _Ep>
    inline bool
    operator>(const unique_ptr<_Tp, _Dp>& __x,
      const unique_ptr<_Up, _Ep>& __y)
    { return __y.get() < __x.get(); }

  template<typename _Tp, typename _Dp,
   typename _Up, typename _Ep>
    inline bool
    operator>=(const unique_ptr<_Tp, _Dp>& __x,
       const unique_ptr<_Up, _Ep>& __y)
    { return !(__x.get() < __y.get()); }

  /// std::hash specialization for unique_ptr.
  template<typename _Tp, typename _Dp>
    struct hash<unique_ptr<_Tp, _Dp>>
    : public std::unary_function<unique_ptr<_Tp, _Dp>, size_t>
    {
      size_t
      operator()(const unique_ptr<_Tp, _Dp>& __u) const
      {
typedef unique_ptr<_Tp, _Dp> _UP;
return std::hash<typename _UP::pointer>()(__u.get());
      }
    };

  // @} group pointer_abstractions

_GLIBCXX_END_NAMESPACE_VERSION
} // namespace

#endif /* _UNIQUE_PTR_H */


Code
_GLIBCXX_VISIBILITY(default)
should be replaced to none.

Unfortunately, I think we do not currently have such replacement rule.

My idea is: we should write such replacement rule like the macro definition. That need some code rewrite.

Title: Re: CC no longer working for unique_ptr
Post by: killerbot on August 30, 2011, 01:05:38 pm
fyi : I discovered the issue yesterday on linux with gcc 4.6
Title: Re: CC no longer working for unique_ptr
Post by: Jenna on August 30, 2011, 02:10:07 pm
fyi : I discovered the issue yesterday on linux with gcc 4.6
I also tested with gcc 4.6, but can test with 4.5 this evening.
Title: Re: CC no longer working for unique_ptr
Post by: oBFusCATed on August 30, 2011, 05:00:55 pm
Code
Tokenizer::SetReplacementString(_T("_GLIBCXX_VISIBILITY"), _T("+"));
Is this '+' character correct?
What does it do?
Explanation please and maybe a commit with a comment about it:)
Title: Re: CC no longer working for unique_ptr
Post by: Loaden on August 30, 2011, 05:04:16 pm
Code
Tokenizer::SetReplacementString(_T("_GLIBCXX_VISIBILITY"), _T("+"));
Is this '+' character correct?
What does it do?
Explanation please and maybe a commit with a comment about it:)
Sorry for my poor english. I think I can't explain clear.
The "+" is a flag for macro replace.
And the replace result is:
_GLIBCXX_VISIBILITY(...any...thing...) -> none
See test.h for more information.
Title: Re: CC no longer working for unique_ptr
Post by: oBFusCATed on August 30, 2011, 06:24:32 pm
Understood  :lol:
Title: Re: CC no longer working for unique_ptr
Post by: killerbot on August 30, 2011, 08:25:59 pm
I can confirm that the first problem is solved : foo.

But the second one still fails : bar->

Title: Re: CC no longer working for unique_ptr
Post by: Loaden on August 31, 2011, 01:54:25 am
I can confirm that the first problem is solved : foo.

But the second one still fails : bar->
About the second issue: shared_ptr<Test> and auto_ptr<Test> works well.
So, There should has some thing changed with unique_ptr.
Title: Re: CC no longer working for unique_ptr
Post by: Loaden on August 31, 2011, 02:42:11 am
I can't solved this issue. It's too complex.

Code
/// 20.7.12.2 unique_ptr for single objects.
  template <typename _Tp, typename _Dp = default_delete<_Tp> >
    class unique_ptr
    {
      // use SFINAE to determine whether _Del::pointer exists
      class _Pointer
      {
template<typename _Up>
 static typename _Up::pointer __test(typename _Up::pointer*);

template<typename _Up>
 static _Tp* __test(...);

typedef typename remove_reference<_Dp>::type _Del;

      public:
typedef decltype( __test<_Del>(0)) type;
      };

      typedef std::tuple<typename _Pointer::type, _Dp>  __tuple_type;
      __tuple_type                                      _M_t;

    public:
      typedef typename _Pointer::type   pointer;
...
      pointer
      operator->() const
      {

_GLIBCXX_DEBUG_ASSERT(get() != pointer());
return get();
      }

See: typedef typename _Pointer::type   pointer;

I don't understood what's the meaning.

If change to:
Code
      _Tp*
      operator->() const
      {

_GLIBCXX_DEBUG_ASSERT(get() != pointer());
return get();
      }

Every thing will works fine.
Title: Re: CC no longer working for unique_ptr
Post by: ollydbg on September 01, 2011, 07:47:55 am
Code
typedef typename _Pointer::type   pointer;
we should resolve the actual type of the string "_Pointer::type".

As the definition of the embedded class _Pointer, "_Pointer::type" is actually a type from the "decltype operator" deduced from the expression "__test<_Del>(0)".

Then "__test<_Del>(0)" is a function calling expression defined by
Code
template<typename _Up>
 static _Tp* __test(...);

So, it's actual type is "_Tp*".

As a conclusion: C++'s type-deduction mechanism is heaven for programmer, but it is the hell for compiler/parser writer. :D, each step should involve the symbol table check and semantics check.
I don't think it can be implemented in CC, it was too complex.