Clang bug?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
12 messages Options
Reply | Threaded
Open this post in threaded view
|

Clang bug?

Adam Peterson
Is this a relevant location to provide information about what I
believe is a compiler bug in clang?  If not, please forgive me for
posting it here.  (Perhaps you can redirect me to some place more
appropriate.)  If so, here are the details:

I have a short 15-line C++ program using only one standard header that
clang fails to compile properly under C++11 with the new standard
library (although the code itself doesn't use any C++11-specific
syntax), but G++ (4.6-Ubuntu and 4.2-Darwin) compiles it fine:

    #include <map>
    using std::map;

    template<typename K>
    struct Templ8 {
        struct Member {
            typename map<K,Member*>::iterator it;
        };
        typedef typename map<K,Member*>::iterator iterator_type;
    };

    int main() {
        Templ8<int> test;
    }



This is the command-line:
    clang++ -stdlib=libc++ -std=c++11 main_bug.cpp
If either of the flags are removed (to compile in C++03 mode, or to
use the non-clang standard library), the code compiles.  If the
typedef is removed or commented out, clang++ compiles the code fine.
If the typedef is moved inside the "Member" inner class, the code
compiles fine (even if a second typedef pulls the symbol back into the
main template scope).

My clang version information:
    Apple clang version 4.1 (tags/Apple/clang-421.11.65) (based on LLVM 3.1svn)
    Target: x86_64-apple-darwin12.2.0
    Thread model: posix

The error output:

main_bug.cpp:7:34: error: no type named 'iterator' in
'std::__1::map<int, Templ8<int>::Member *, std::__1::less<int>,
std::__1::allocator<std::__1::pair<const int, Templ8<int>::Member
*>>>'
        typename map<K,Member*>::iterator it;
        ~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~
/usr/bin/../lib/c++/v1/type_traits:1184:57: note: in instantiation of
member class 'Templ8<int>::Member' requested here
decltype((_VSTD::declval<_Tp>() = _VSTD::declval<_Arg>(), true_type()))
                                                        ^
/usr/bin/../lib/c++/v1/type_traits:1186:1: note: while substituting
deduced template arguments into function template
'__is_assignable_test' [with _Tp = Templ8<int>::Member *&, _Arg = <no
value>]
__is_assignable_test(_Tp&&, _Arg&&);
^
/usr/bin/../lib/c++/v1/type_traits:1214:14: note: in instantiation of
template class 'std::__1::__is_assignable_imp<Templ8<int>::Member *&,
Templ8<int>::Member *&, false>' requested here
    : public __is_assignable_imp<_Tp, _Arg> {};
             ^
/usr/bin/../lib/c++/v1/type_traits:2616:38: note: in instantiation of
template class 'std::__1::is_assignable<Templ8<int>::Member *&,
Templ8<int>::Member *&>' requested here
    : public __is_nothrow_assignable<is_assignable<_Tp, _Arg>::value,
_Tp, _Arg>
                                     ^
/usr/bin/../lib/c++/v1/type_traits:2667:14: note: in instantiation of
template class 'std::__1::is_nothrow_assignable<Templ8<int>::Member
*&, Templ8<int>::Member *&>' requested here
    : public is_nothrow_assignable<typename add_lvalue_reference<_Tp>::type,
             ^
/usr/bin/../lib/c++/v1/utility:250:20: note: (skipping 9 contexts in
backtrace; use -ftemplate-backtrace-limit=0 to see all)
                   is_nothrow_copy_assignable<second_type>::value)
                   ^
/usr/bin/../lib/c++/v1/__config:253:34: note: expanded from macro '_NOEXCEPT_'
#  define _NOEXCEPT_(x) noexcept(x)
                                 ^
/usr/bin/../lib/c++/v1/memory:2386:15: note: in instantiation of
template class 'std::__1::__libcpp_compressed_pair_imp<std::__1::__tree_end_node<std::__1::__tree_node_base<void
*> *>,
      std::__1::allocator<std::__1::__tree_node<std::__1::pair<int,
Templ8<int>::Member *>, void *>>, 2>' requested here
    : private __libcpp_compressed_pair_imp<_T1, _T2>
              ^
/usr/bin/../lib/c++/v1/__tree:813:56: note: in instantiation of
template class 'std::__1::__compressed_pair<std::__1::__tree_end_node<std::__1::__tree_node_base<void
*> *>,
      std::__1::allocator<std::__1::__tree_node<std::__1::pair<int,
Templ8<int>::Member *>, void *>>>' requested here
    __compressed_pair<__end_node_t, __node_allocator>  __pair1_;
                                                       ^
/usr/bin/../lib/c++/v1/map:711:22: note: in instantiation of template
class 'std::__1::__tree<std::__1::pair<int, Templ8<int>::Member *>,
std::__1::__map_value_compare<int, Templ8<int>::Member *,
      std::__1::less<int>, true>,
std::__1::allocator<std::__1::pair<int, Templ8<int>::Member *>>>'
requested here
    typedef typename __base::__node_traits                 __node_traits;
                     ^
main_bug.cpp:9:22: note: in instantiation of template class
'std::__1::map<int, Templ8<int>::Member *, std::__1::less<int>,
std::__1::allocator<std::__1::pair<const int, Templ8<int>::Member
*>>>'
      requested here
    typedef typename map<K,Member*>::iterator iterator_type;
                     ^
main_bug.cpp:13:17: note: in instantiation of template class
'Templ8<int>' requested here
    Templ8<int> test;
                ^
1 error generated.
_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
Reply | Threaded
Open this post in threaded view
|

Re: Clang bug?

Rao, Prashantha
I think you should send a mail to [hidden email]; clang mailing alias.

-Prashantha

-----Original Message-----
From: [hidden email] [mailto:[hidden email]] On Behalf Of Adam Peterson
Sent: Friday, September 28, 2012 4:47 AM
To: [hidden email]
Subject: [LLVMdev] Clang bug?

Is this a relevant location to provide information about what I
believe is a compiler bug in clang?  If not, please forgive me for
posting it here.  (Perhaps you can redirect me to some place more
appropriate.)  If so, here are the details:

I have a short 15-line C++ program using only one standard header that
clang fails to compile properly under C++11 with the new standard
library (although the code itself doesn't use any C++11-specific
syntax), but G++ (4.6-Ubuntu and 4.2-Darwin) compiles it fine:

    #include <map>
    using std::map;

    template<typename K>
    struct Templ8 {
        struct Member {
            typename map<K,Member*>::iterator it;
        };
        typedef typename map<K,Member*>::iterator iterator_type;
    };

    int main() {
        Templ8<int> test;
    }



This is the command-line:
    clang++ -stdlib=libc++ -std=c++11 main_bug.cpp
If either of the flags are removed (to compile in C++03 mode, or to
use the non-clang standard library), the code compiles.  If the
typedef is removed or commented out, clang++ compiles the code fine.
If the typedef is moved inside the "Member" inner class, the code
compiles fine (even if a second typedef pulls the symbol back into the
main template scope).

My clang version information:
    Apple clang version 4.1 (tags/Apple/clang-421.11.65) (based on LLVM 3.1svn)
    Target: x86_64-apple-darwin12.2.0
    Thread model: posix

The error output:

main_bug.cpp:7:34: error: no type named 'iterator' in
'std::__1::map<int, Templ8<int>::Member *, std::__1::less<int>,
std::__1::allocator<std::__1::pair<const int, Templ8<int>::Member
*>>>'
        typename map<K,Member*>::iterator it;
        ~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~
/usr/bin/../lib/c++/v1/type_traits:1184:57: note: in instantiation of
member class 'Templ8<int>::Member' requested here
decltype((_VSTD::declval<_Tp>() = _VSTD::declval<_Arg>(), true_type()))
                                                        ^
/usr/bin/../lib/c++/v1/type_traits:1186:1: note: while substituting
deduced template arguments into function template
'__is_assignable_test' [with _Tp = Templ8<int>::Member *&, _Arg = <no
value>]
__is_assignable_test(_Tp&&, _Arg&&);
^
/usr/bin/../lib/c++/v1/type_traits:1214:14: note: in instantiation of
template class 'std::__1::__is_assignable_imp<Templ8<int>::Member *&,
Templ8<int>::Member *&, false>' requested here
    : public __is_assignable_imp<_Tp, _Arg> {};
             ^
/usr/bin/../lib/c++/v1/type_traits:2616:38: note: in instantiation of
template class 'std::__1::is_assignable<Templ8<int>::Member *&,
Templ8<int>::Member *&>' requested here
    : public __is_nothrow_assignable<is_assignable<_Tp, _Arg>::value,
_Tp, _Arg>
                                     ^
/usr/bin/../lib/c++/v1/type_traits:2667:14: note: in instantiation of
template class 'std::__1::is_nothrow_assignable<Templ8<int>::Member
*&, Templ8<int>::Member *&>' requested here
    : public is_nothrow_assignable<typename add_lvalue_reference<_Tp>::type,
             ^
/usr/bin/../lib/c++/v1/utility:250:20: note: (skipping 9 contexts in
backtrace; use -ftemplate-backtrace-limit=0 to see all)
                   is_nothrow_copy_assignable<second_type>::value)
                   ^
/usr/bin/../lib/c++/v1/__config:253:34: note: expanded from macro '_NOEXCEPT_'
#  define _NOEXCEPT_(x) noexcept(x)
                                 ^
/usr/bin/../lib/c++/v1/memory:2386:15: note: in instantiation of
template class 'std::__1::__libcpp_compressed_pair_imp<std::__1::__tree_end_node<std::__1::__tree_node_base<void
*> *>,
      std::__1::allocator<std::__1::__tree_node<std::__1::pair<int,
Templ8<int>::Member *>, void *>>, 2>' requested here
    : private __libcpp_compressed_pair_imp<_T1, _T2>
              ^
/usr/bin/../lib/c++/v1/__tree:813:56: note: in instantiation of
template class 'std::__1::__compressed_pair<std::__1::__tree_end_node<std::__1::__tree_node_base<void
*> *>,
      std::__1::allocator<std::__1::__tree_node<std::__1::pair<int,
Templ8<int>::Member *>, void *>>>' requested here
    __compressed_pair<__end_node_t, __node_allocator>  __pair1_;
                                                       ^
/usr/bin/../lib/c++/v1/map:711:22: note: in instantiation of template
class 'std::__1::__tree<std::__1::pair<int, Templ8<int>::Member *>,
std::__1::__map_value_compare<int, Templ8<int>::Member *,
      std::__1::less<int>, true>,
std::__1::allocator<std::__1::pair<int, Templ8<int>::Member *>>>'
requested here
    typedef typename __base::__node_traits                 __node_traits;
                     ^
main_bug.cpp:9:22: note: in instantiation of template class
'std::__1::map<int, Templ8<int>::Member *, std::__1::less<int>,
std::__1::allocator<std::__1::pair<const int, Templ8<int>::Member
*>>>'
      requested here
    typedef typename map<K,Member*>::iterator iterator_type;
                     ^
main_bug.cpp:13:17: note: in instantiation of template class
'Templ8<int>' requested here
    Templ8<int> test;
                ^
1 error generated.
_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev



_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
Reply | Threaded
Open this post in threaded view
|

Re: Clang bug?

Óscar Fuentes
In reply to this post by Adam Peterson
Adam Peterson <[hidden email]> writes:

> Is this a relevant location to provide information about what I
> believe is a compiler bug in clang?  If not, please forgive me for
> posting it here.  (Perhaps you can redirect me to some place more
> appropriate.)

For reporting bugs on Clang use the Bugzilla bug reporting service. For
discussing topics related to Clang use the cfe-dev mailing list. Both
are available from http://clang.llvm.org

[snip]
_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
Reply | Threaded
Open this post in threaded view
|

Re: Clang bug?

Howard Hinnant-2
In reply to this post by Adam Peterson
That is one evil bug!

I just tested it against tip-of-trunk clang and it appears to be fixed there (just fyi for everyone).

Howard

On Sep 27, 2012, at 7:17 PM, Adam Peterson <[hidden email]> wrote:

> Is this a relevant location to provide information about what I
> believe is a compiler bug in clang?  If not, please forgive me for
> posting it here.  (Perhaps you can redirect me to some place more
> appropriate.)  If so, here are the details:
>
> I have a short 15-line C++ program using only one standard header that
> clang fails to compile properly under C++11 with the new standard
> library (although the code itself doesn't use any C++11-specific
> syntax), but G++ (4.6-Ubuntu and 4.2-Darwin) compiles it fine:
>
>    #include <map>
>    using std::map;
>
>    template<typename K>
>    struct Templ8 {
>        struct Member {
>            typename map<K,Member*>::iterator it;
>        };
>        typedef typename map<K,Member*>::iterator iterator_type;
>    };
>
>    int main() {
>        Templ8<int> test;
>    }
>
>
>
> This is the command-line:
>    clang++ -stdlib=libc++ -std=c++11 main_bug.cpp
> If either of the flags are removed (to compile in C++03 mode, or to
> use the non-clang standard library), the code compiles.  If the
> typedef is removed or commented out, clang++ compiles the code fine.
> If the typedef is moved inside the "Member" inner class, the code
> compiles fine (even if a second typedef pulls the symbol back into the
> main template scope).
>
> My clang version information:
>    Apple clang version 4.1 (tags/Apple/clang-421.11.65) (based on LLVM 3.1svn)
>    Target: x86_64-apple-darwin12.2.0
>    Thread model: posix
>
> The error output:
>
> main_bug.cpp:7:34: error: no type named 'iterator' in
> 'std::__1::map<int, Templ8<int>::Member *, std::__1::less<int>,
> std::__1::allocator<std::__1::pair<const int, Templ8<int>::Member
> *>>>'
>        typename map<K,Member*>::iterator it;
>        ~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~
> /usr/bin/../lib/c++/v1/type_traits:1184:57: note: in instantiation of
> member class 'Templ8<int>::Member' requested here
> decltype((_VSTD::declval<_Tp>() = _VSTD::declval<_Arg>(), true_type()))
>                                                        ^
> /usr/bin/../lib/c++/v1/type_traits:1186:1: note: while substituting
> deduced template arguments into function template
> '__is_assignable_test' [with _Tp = Templ8<int>::Member *&, _Arg = <no
> value>]
> __is_assignable_test(_Tp&&, _Arg&&);
> ^
> /usr/bin/../lib/c++/v1/type_traits:1214:14: note: in instantiation of
> template class 'std::__1::__is_assignable_imp<Templ8<int>::Member *&,
> Templ8<int>::Member *&, false>' requested here
>    : public __is_assignable_imp<_Tp, _Arg> {};
>             ^
> /usr/bin/../lib/c++/v1/type_traits:2616:38: note: in instantiation of
> template class 'std::__1::is_assignable<Templ8<int>::Member *&,
> Templ8<int>::Member *&>' requested here
>    : public __is_nothrow_assignable<is_assignable<_Tp, _Arg>::value,
> _Tp, _Arg>
>                                     ^
> /usr/bin/../lib/c++/v1/type_traits:2667:14: note: in instantiation of
> template class 'std::__1::is_nothrow_assignable<Templ8<int>::Member
> *&, Templ8<int>::Member *&>' requested here
>    : public is_nothrow_assignable<typename add_lvalue_reference<_Tp>::type,
>             ^
> /usr/bin/../lib/c++/v1/utility:250:20: note: (skipping 9 contexts in
> backtrace; use -ftemplate-backtrace-limit=0 to see all)
>                   is_nothrow_copy_assignable<second_type>::value)
>                   ^
> /usr/bin/../lib/c++/v1/__config:253:34: note: expanded from macro '_NOEXCEPT_'
> #  define _NOEXCEPT_(x) noexcept(x)
>                                 ^
> /usr/bin/../lib/c++/v1/memory:2386:15: note: in instantiation of
> template class 'std::__1::__libcpp_compressed_pair_imp<std::__1::__tree_end_node<std::__1::__tree_node_base<void
> *> *>,
>      std::__1::allocator<std::__1::__tree_node<std::__1::pair<int,
> Templ8<int>::Member *>, void *>>, 2>' requested here
>    : private __libcpp_compressed_pair_imp<_T1, _T2>
>              ^
> /usr/bin/../lib/c++/v1/__tree:813:56: note: in instantiation of
> template class 'std::__1::__compressed_pair<std::__1::__tree_end_node<std::__1::__tree_node_base<void
> *> *>,
>      std::__1::allocator<std::__1::__tree_node<std::__1::pair<int,
> Templ8<int>::Member *>, void *>>>' requested here
>    __compressed_pair<__end_node_t, __node_allocator>  __pair1_;
>                                                       ^
> /usr/bin/../lib/c++/v1/map:711:22: note: in instantiation of template
> class 'std::__1::__tree<std::__1::pair<int, Templ8<int>::Member *>,
> std::__1::__map_value_compare<int, Templ8<int>::Member *,
>      std::__1::less<int>, true>,
> std::__1::allocator<std::__1::pair<int, Templ8<int>::Member *>>>'
> requested here
>    typedef typename __base::__node_traits                 __node_traits;
>                     ^
> main_bug.cpp:9:22: note: in instantiation of template class
> 'std::__1::map<int, Templ8<int>::Member *, std::__1::less<int>,
> std::__1::allocator<std::__1::pair<const int, Templ8<int>::Member
> *>>>'
>      requested here
>    typedef typename map<K,Member*>::iterator iterator_type;
>                     ^
> main_bug.cpp:13:17: note: in instantiation of template class
> 'Templ8<int>' requested here
>    Templ8<int> test;
>                ^
> 1 error generated.
> _______________________________________________
> LLVM Developers mailing list
> [hidden email]         http://llvm.cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev

_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
Reply | Threaded
Open this post in threaded view
|

Re: Clang bug?

Richard Smith-33
Reduced testcase:

template<typename T> struct A { typedef decltype(T() + 0) type; };
template<typename T> struct B {
  struct C { typedef typename A<C*>::type type; };
  typedef typename A<C*>::type type;
};
B<int> b;

... produces ...

<stdin>:3:38: error: no type named 'type' in 'A<B<int>::C *>'
  struct C { typedef typename A<C*>::type type; };
                     ~~~~~~~~~~~~~~~~^~~~
<stdin>:1:54: note: in instantiation of member class 'B<int>::C' requested here
template<typename T> struct A { typedef decltype(T() + 0) type; };
                                                     ^
<stdin>:4:20: note: in instantiation of template class 'A<B<int>::C *>' requested here
  typedef typename A<C*>::type type;
                   ^
<stdin>:6:8: note: in instantiation of template class 'B<int>' requested here
B<int> b;
       ^

I think it would be worth filing this as a diagnostic QoR issue. We should be able to say something like

<stdin>:3:38: error: member 'type' of 'A<B<int>::C *>' required recursively within the instantiation of 'A<B<int>::C *>', but it has not been instantiated yet

On Fri, Sep 28, 2012 at 7:51 AM, Howard Hinnant <[hidden email]> wrote:
That is one evil bug!

I just tested it against tip-of-trunk clang and it appears to be fixed there (just fyi for everyone).

Howard

On Sep 27, 2012, at 7:17 PM, Adam Peterson <[hidden email]> wrote:

> Is this a relevant location to provide information about what I
> believe is a compiler bug in clang?  If not, please forgive me for
> posting it here.  (Perhaps you can redirect me to some place more
> appropriate.)  If so, here are the details:
>
> I have a short 15-line C++ program using only one standard header that
> clang fails to compile properly under C++11 with the new standard
> library (although the code itself doesn't use any C++11-specific
> syntax), but G++ (4.6-Ubuntu and 4.2-Darwin) compiles it fine:
>
>    #include <map>
>    using std::map;
>
>    template<typename K>
>    struct Templ8 {
>        struct Member {
>            typename map<K,Member*>::iterator it;
>        };
>        typedef typename map<K,Member*>::iterator iterator_type;
>    };
>
>    int main() {
>        Templ8<int> test;
>    }
>
>
>
> This is the command-line:
>    clang++ -stdlib=libc++ -std=c++11 main_bug.cpp
> If either of the flags are removed (to compile in C++03 mode, or to
> use the non-clang standard library), the code compiles.  If the
> typedef is removed or commented out, clang++ compiles the code fine.
> If the typedef is moved inside the "Member" inner class, the code
> compiles fine (even if a second typedef pulls the symbol back into the
> main template scope).
>
> My clang version information:
>    Apple clang version 4.1 (tags/Apple/clang-421.11.65) (based on LLVM 3.1svn)
>    Target: x86_64-apple-darwin12.2.0
>    Thread model: posix
>
> The error output:
>
> main_bug.cpp:7:34: error: no type named 'iterator' in
> 'std::__1::map<int, Templ8<int>::Member *, std::__1::less<int>,
> std::__1::allocator<std::__1::pair<const int, Templ8<int>::Member
> *>>>'
>        typename map<K,Member*>::iterator it;
>        ~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~
> /usr/bin/../lib/c++/v1/type_traits:1184:57: note: in instantiation of
> member class 'Templ8<int>::Member' requested here
> decltype((_VSTD::declval<_Tp>() = _VSTD::declval<_Arg>(), true_type()))
>                                                        ^
> /usr/bin/../lib/c++/v1/type_traits:1186:1: note: while substituting
> deduced template arguments into function template
> '__is_assignable_test' [with _Tp = Templ8<int>::Member *&, _Arg = <no
> value>]
> __is_assignable_test(_Tp&&, _Arg&&);
> ^
> /usr/bin/../lib/c++/v1/type_traits:1214:14: note: in instantiation of
> template class 'std::__1::__is_assignable_imp<Templ8<int>::Member *&,
> Templ8<int>::Member *&, false>' requested here
>    : public __is_assignable_imp<_Tp, _Arg> {};
>             ^
> /usr/bin/../lib/c++/v1/type_traits:2616:38: note: in instantiation of
> template class 'std::__1::is_assignable<Templ8<int>::Member *&,
> Templ8<int>::Member *&>' requested here
>    : public __is_nothrow_assignable<is_assignable<_Tp, _Arg>::value,
> _Tp, _Arg>
>                                     ^
> /usr/bin/../lib/c++/v1/type_traits:2667:14: note: in instantiation of
> template class 'std::__1::is_nothrow_assignable<Templ8<int>::Member
> *&, Templ8<int>::Member *&>' requested here
>    : public is_nothrow_assignable<typename add_lvalue_reference<_Tp>::type,
>             ^
> /usr/bin/../lib/c++/v1/utility:250:20: note: (skipping 9 contexts in
> backtrace; use -ftemplate-backtrace-limit=0 to see all)
>                   is_nothrow_copy_assignable<second_type>::value)
>                   ^
> /usr/bin/../lib/c++/v1/__config:253:34: note: expanded from macro '_NOEXCEPT_'
> #  define _NOEXCEPT_(x) noexcept(x)
>                                 ^
> /usr/bin/../lib/c++/v1/memory:2386:15: note: in instantiation of
> template class 'std::__1::__libcpp_compressed_pair_imp<std::__1::__tree_end_node<std::__1::__tree_node_base<void
> *> *>,
>      std::__1::allocator<std::__1::__tree_node<std::__1::pair<int,
> Templ8<int>::Member *>, void *>>, 2>' requested here
>    : private __libcpp_compressed_pair_imp<_T1, _T2>
>              ^
> /usr/bin/../lib/c++/v1/__tree:813:56: note: in instantiation of
> template class 'std::__1::__compressed_pair<std::__1::__tree_end_node<std::__1::__tree_node_base<void
> *> *>,
>      std::__1::allocator<std::__1::__tree_node<std::__1::pair<int,
> Templ8<int>::Member *>, void *>>>' requested here
>    __compressed_pair<__end_node_t, __node_allocator>  __pair1_;
>                                                       ^
> /usr/bin/../lib/c++/v1/map:711:22: note: in instantiation of template
> class 'std::__1::__tree<std::__1::pair<int, Templ8<int>::Member *>,
> std::__1::__map_value_compare<int, Templ8<int>::Member *,
>      std::__1::less<int>, true>,
> std::__1::allocator<std::__1::pair<int, Templ8<int>::Member *>>>'
> requested here
>    typedef typename __base::__node_traits                 __node_traits;
>                     ^
> main_bug.cpp:9:22: note: in instantiation of template class
> 'std::__1::map<int, Templ8<int>::Member *, std::__1::less<int>,
> std::__1::allocator<std::__1::pair<const int, Templ8<int>::Member
> *>>>'
>      requested here
>    typedef typename map<K,Member*>::iterator iterator_type;
>                     ^
> main_bug.cpp:13:17: note: in instantiation of template class
> 'Templ8<int>' requested here
>    Templ8<int> test;
>                ^
> 1 error generated.
> _______________________________________________
> LLVM Developers mailing list
> [hidden email]         http://llvm.cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev

_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev


_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
Reply | Threaded
Open this post in threaded view
|

Re: Clang bug?

Adam Peterson
This doesn't appear to me to be the same issue (but of course I don't
know clang as well as you all do).  This code appears invalid (and G++
rejects it with a similar "no type named ..." error message), whereas
the original code is valid C++ (both C++98 and C++11).

On Fri, Sep 28, 2012 at 3:54 PM, Richard Smith <[hidden email]> wrote:

> Reduced testcase:
>
> template<typename T> struct A { typedef decltype(T() + 0) type; };
> template<typename T> struct B {
>   struct C { typedef typename A<C*>::type type; };
>   typedef typename A<C*>::type type;
> };
> B<int> b;
>
> ... produces ...
>
> <stdin>:3:38: error: no type named 'type' in 'A<B<int>::C *>'
>   struct C { typedef typename A<C*>::type type; };
>                      ~~~~~~~~~~~~~~~~^~~~
> <stdin>:1:54: note: in instantiation of member class 'B<int>::C' requested
> here
> template<typename T> struct A { typedef decltype(T() + 0) type; };
>                                                      ^
> <stdin>:4:20: note: in instantiation of template class 'A<B<int>::C *>'
> requested here
>   typedef typename A<C*>::type type;
>                    ^
> <stdin>:6:8: note: in instantiation of template class 'B<int>' requested
> here
> B<int> b;
>        ^
>
> I think it would be worth filing this as a diagnostic QoR issue. We should
> be able to say something like
>
> <stdin>:3:38: error: member 'type' of 'A<B<int>::C *>' required recursively
> within the instantiation of 'A<B<int>::C *>', but it has not been
> instantiated yet
>
> On Fri, Sep 28, 2012 at 7:51 AM, Howard Hinnant <[hidden email]> wrote:
>>
>> That is one evil bug!
>>
>> I just tested it against tip-of-trunk clang and it appears to be fixed
>> there (just fyi for everyone).
>>
>> Howard
>>
>> On Sep 27, 2012, at 7:17 PM, Adam Peterson <[hidden email]> wrote:
>>
>> > Is this a relevant location to provide information about what I
>> > believe is a compiler bug in clang?  If not, please forgive me for
>> > posting it here.  (Perhaps you can redirect me to some place more
>> > appropriate.)  If so, here are the details:
>> >
>> > I have a short 15-line C++ program using only one standard header that
>> > clang fails to compile properly under C++11 with the new standard
>> > library (although the code itself doesn't use any C++11-specific
>> > syntax), but G++ (4.6-Ubuntu and 4.2-Darwin) compiles it fine:
>> >
>> >    #include <map>
>> >    using std::map;
>> >
>> >    template<typename K>
>> >    struct Templ8 {
>> >        struct Member {
>> >            typename map<K,Member*>::iterator it;
>> >        };
>> >        typedef typename map<K,Member*>::iterator iterator_type;
>> >    };
>> >
>> >    int main() {
>> >        Templ8<int> test;
>> >    }
>> >
>> >
>> >
>> > This is the command-line:
>> >    clang++ -stdlib=libc++ -std=c++11 main_bug.cpp
>> > If either of the flags are removed (to compile in C++03 mode, or to
>> > use the non-clang standard library), the code compiles.  If the
>> > typedef is removed or commented out, clang++ compiles the code fine.
>> > If the typedef is moved inside the "Member" inner class, the code
>> > compiles fine (even if a second typedef pulls the symbol back into the
>> > main template scope).
>> >
>> > My clang version information:
>> >    Apple clang version 4.1 (tags/Apple/clang-421.11.65) (based on LLVM
>> > 3.1svn)
>> >    Target: x86_64-apple-darwin12.2.0
>> >    Thread model: posix
>> >
>> > The error output:
>> >
>> > main_bug.cpp:7:34: error: no type named 'iterator' in
>> > 'std::__1::map<int, Templ8<int>::Member *, std::__1::less<int>,
>> > std::__1::allocator<std::__1::pair<const int, Templ8<int>::Member
>> > *>>>'
>> >        typename map<K,Member*>::iterator it;
>> >        ~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~
>> > /usr/bin/../lib/c++/v1/type_traits:1184:57: note: in instantiation of
>> > member class 'Templ8<int>::Member' requested here
>> > decltype((_VSTD::declval<_Tp>() = _VSTD::declval<_Arg>(), true_type()))
>> >                                                        ^
>> > /usr/bin/../lib/c++/v1/type_traits:1186:1: note: while substituting
>> > deduced template arguments into function template
>> > '__is_assignable_test' [with _Tp = Templ8<int>::Member *&, _Arg = <no
>> > value>]
>> > __is_assignable_test(_Tp&&, _Arg&&);
>> > ^
>> > /usr/bin/../lib/c++/v1/type_traits:1214:14: note: in instantiation of
>> > template class 'std::__1::__is_assignable_imp<Templ8<int>::Member *&,
>> > Templ8<int>::Member *&, false>' requested here
>> >    : public __is_assignable_imp<_Tp, _Arg> {};
>> >             ^
>> > /usr/bin/../lib/c++/v1/type_traits:2616:38: note: in instantiation of
>> > template class 'std::__1::is_assignable<Templ8<int>::Member *&,
>> > Templ8<int>::Member *&>' requested here
>> >    : public __is_nothrow_assignable<is_assignable<_Tp, _Arg>::value,
>> > _Tp, _Arg>
>> >                                     ^
>> > /usr/bin/../lib/c++/v1/type_traits:2667:14: note: in instantiation of
>> > template class 'std::__1::is_nothrow_assignable<Templ8<int>::Member
>> > *&, Templ8<int>::Member *&>' requested here
>> >    : public is_nothrow_assignable<typename
>> > add_lvalue_reference<_Tp>::type,
>> >             ^
>> > /usr/bin/../lib/c++/v1/utility:250:20: note: (skipping 9 contexts in
>> > backtrace; use -ftemplate-backtrace-limit=0 to see all)
>> >                   is_nothrow_copy_assignable<second_type>::value)
>> >                   ^
>> > /usr/bin/../lib/c++/v1/__config:253:34: note: expanded from macro
>> > '_NOEXCEPT_'
>> > #  define _NOEXCEPT_(x) noexcept(x)
>> >                                 ^
>> > /usr/bin/../lib/c++/v1/memory:2386:15: note: in instantiation of
>> > template class
>> > 'std::__1::__libcpp_compressed_pair_imp<std::__1::__tree_end_node<std::__1::__tree_node_base<void
>> > *> *>,
>> >      std::__1::allocator<std::__1::__tree_node<std::__1::pair<int,
>> > Templ8<int>::Member *>, void *>>, 2>' requested here
>> >    : private __libcpp_compressed_pair_imp<_T1, _T2>
>> >              ^
>> > /usr/bin/../lib/c++/v1/__tree:813:56: note: in instantiation of
>> > template class
>> > 'std::__1::__compressed_pair<std::__1::__tree_end_node<std::__1::__tree_node_base<void
>> > *> *>,
>> >      std::__1::allocator<std::__1::__tree_node<std::__1::pair<int,
>> > Templ8<int>::Member *>, void *>>>' requested here
>> >    __compressed_pair<__end_node_t, __node_allocator>  __pair1_;
>> >                                                       ^
>> > /usr/bin/../lib/c++/v1/map:711:22: note: in instantiation of template
>> > class 'std::__1::__tree<std::__1::pair<int, Templ8<int>::Member *>,
>> > std::__1::__map_value_compare<int, Templ8<int>::Member *,
>> >      std::__1::less<int>, true>,
>> > std::__1::allocator<std::__1::pair<int, Templ8<int>::Member *>>>'
>> > requested here
>> >    typedef typename __base::__node_traits                 __node_traits;
>> >                     ^
>> > main_bug.cpp:9:22: note: in instantiation of template class
>> > 'std::__1::map<int, Templ8<int>::Member *, std::__1::less<int>,
>> > std::__1::allocator<std::__1::pair<const int, Templ8<int>::Member
>> > *>>>'
>> >      requested here
>> >    typedef typename map<K,Member*>::iterator iterator_type;
>> >                     ^
>> > main_bug.cpp:13:17: note: in instantiation of template class
>> > 'Templ8<int>' requested here
>> >    Templ8<int> test;
>> >                ^
>> > 1 error generated.
>> > _______________________________________________
>> > LLVM Developers mailing list
>> > [hidden email]         http://llvm.cs.uiuc.edu
>> > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
>>
>> _______________________________________________
>> LLVM Developers mailing list
>> [hidden email]         http://llvm.cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
>
>
_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
Reply | Threaded
Open this post in threaded view
|

Re: Clang bug?

Richard Smith-33
On Fri, Sep 28, 2012 at 5:11 PM, Adam Peterson <[hidden email]> wrote:
This doesn't appear to me to be the same issue (but of course I don't
know clang as well as you all do).  This code appears invalid (and G++
rejects it with a similar "no type named ..." error message), whereas
the original code is valid C++ (both C++98 and C++11).

[The difference in whether we accept the original code isn't clang versus g++, it's libc++ versus libstdc++. Clang with libstdc++ accepted this code.]

There's two separate problems here. One is that given:

typedef typename map<K,Member*>::iterator iterator_type;

libc++'s std::map implementation was using a construct whose semantics depended on whether 'Member' is a complete type (thus triggering the instantiation of that type in the middle of instantiating map<K,Member*>, creating a dependency cycle between the two instantiations). I'm not at all clear on whether that is permissible behavior for a standard library implementation, but it still seems to be a problem in some cases. libc++'s is_assignable implementation uses SFINAE on this:

  decltype((_VSTD::declval<_Tp>() = _VSTD::declval<_Arg>(), true_type()))

Now, our case was: _Tp = Member*&, _Arg = Member*. In that case, we use the built-in assignment operator, which produces an lvalue of type Member*. Then we perform argument-dependent lookup looking for an overloaded 'operator,', because its RHS is of a class type. This lookup triggers the (undesirable) instantiation of Member, because it is an associated class. I'm not sure exactly what has stopped this problem from manifesting, but the root cause superficially appears to still be present.


The other problem (the one my prior message was addressing) is that we have a diagnostic QoR issue, in that we produced a diagnostic message which is factually incorrect.
 
On Fri, Sep 28, 2012 at 3:54 PM, Richard Smith <[hidden email]> wrote:
> Reduced testcase:
>
> template<typename T> struct A { typedef decltype(T() + 0) type; };
> template<typename T> struct B {
>   struct C { typedef typename A<C*>::type type; };
>   typedef typename A<C*>::type type;
> };
> B<int> b;
>
> ... produces ...
>
> <stdin>:3:38: error: no type named 'type' in 'A<B<int>::C *>'
>   struct C { typedef typename A<C*>::type type; };
>                      ~~~~~~~~~~~~~~~~^~~~
> <stdin>:1:54: note: in instantiation of member class 'B<int>::C' requested
> here
> template<typename T> struct A { typedef decltype(T() + 0) type; };
>                                                      ^
> <stdin>:4:20: note: in instantiation of template class 'A<B<int>::C *>'
> requested here
>   typedef typename A<C*>::type type;
>                    ^
> <stdin>:6:8: note: in instantiation of template class 'B<int>' requested
> here
> B<int> b;
>        ^
>
> I think it would be worth filing this as a diagnostic QoR issue. We should
> be able to say something like
>
> <stdin>:3:38: error: member 'type' of 'A<B<int>::C *>' required recursively
> within the instantiation of 'A<B<int>::C *>', but it has not been
> instantiated yet
>
> On Fri, Sep 28, 2012 at 7:51 AM, Howard Hinnant <[hidden email]> wrote:
>>
>> That is one evil bug!
>>
>> I just tested it against tip-of-trunk clang and it appears to be fixed
>> there (just fyi for everyone).
>>
>> Howard
>>
>> On Sep 27, 2012, at 7:17 PM, Adam Peterson <[hidden email]> wrote:
>>
>> > Is this a relevant location to provide information about what I
>> > believe is a compiler bug in clang?  If not, please forgive me for
>> > posting it here.  (Perhaps you can redirect me to some place more
>> > appropriate.)  If so, here are the details:
>> >
>> > I have a short 15-line C++ program using only one standard header that
>> > clang fails to compile properly under C++11 with the new standard
>> > library (although the code itself doesn't use any C++11-specific
>> > syntax), but G++ (4.6-Ubuntu and 4.2-Darwin) compiles it fine:
>> >
>> >    #include <map>
>> >    using std::map;
>> >
>> >    template<typename K>
>> >    struct Templ8 {
>> >        struct Member {
>> >            typename map<K,Member*>::iterator it;
>> >        };
>> >        typedef typename map<K,Member*>::iterator iterator_type;
>> >    };
>> >
>> >    int main() {
>> >        Templ8<int> test;
>> >    }
>> >
>> >
>> >
>> > This is the command-line:
>> >    clang++ -stdlib=libc++ -std=c++11 main_bug.cpp
>> > If either of the flags are removed (to compile in C++03 mode, or to
>> > use the non-clang standard library), the code compiles.  If the
>> > typedef is removed or commented out, clang++ compiles the code fine.
>> > If the typedef is moved inside the "Member" inner class, the code
>> > compiles fine (even if a second typedef pulls the symbol back into the
>> > main template scope).
>> >
>> > My clang version information:
>> >    Apple clang version 4.1 (tags/Apple/clang-421.11.65) (based on LLVM
>> > 3.1svn)
>> >    Target: x86_64-apple-darwin12.2.0
>> >    Thread model: posix
>> >
>> > The error output:
>> >
>> > main_bug.cpp:7:34: error: no type named 'iterator' in
>> > 'std::__1::map<int, Templ8<int>::Member *, std::__1::less<int>,
>> > std::__1::allocator<std::__1::pair<const int, Templ8<int>::Member
>> > *>>>'
>> >        typename map<K,Member*>::iterator it;
>> >        ~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~
>> > /usr/bin/../lib/c++/v1/type_traits:1184:57: note: in instantiation of
>> > member class 'Templ8<int>::Member' requested here
>> > decltype((_VSTD::declval<_Tp>() = _VSTD::declval<_Arg>(), true_type()))
>> >                                                        ^
>> > /usr/bin/../lib/c++/v1/type_traits:1186:1: note: while substituting
>> > deduced template arguments into function template
>> > '__is_assignable_test' [with _Tp = Templ8<int>::Member *&, _Arg = <no
>> > value>]
>> > __is_assignable_test(_Tp&&, _Arg&&);
>> > ^
>> > /usr/bin/../lib/c++/v1/type_traits:1214:14: note: in instantiation of
>> > template class 'std::__1::__is_assignable_imp<Templ8<int>::Member *&,
>> > Templ8<int>::Member *&, false>' requested here
>> >    : public __is_assignable_imp<_Tp, _Arg> {};
>> >             ^
>> > /usr/bin/../lib/c++/v1/type_traits:2616:38: note: in instantiation of
>> > template class 'std::__1::is_assignable<Templ8<int>::Member *&,
>> > Templ8<int>::Member *&>' requested here
>> >    : public __is_nothrow_assignable<is_assignable<_Tp, _Arg>::value,
>> > _Tp, _Arg>
>> >                                     ^
>> > /usr/bin/../lib/c++/v1/type_traits:2667:14: note: in instantiation of
>> > template class 'std::__1::is_nothrow_assignable<Templ8<int>::Member
>> > *&, Templ8<int>::Member *&>' requested here
>> >    : public is_nothrow_assignable<typename
>> > add_lvalue_reference<_Tp>::type,
>> >             ^
>> > /usr/bin/../lib/c++/v1/utility:250:20: note: (skipping 9 contexts in
>> > backtrace; use -ftemplate-backtrace-limit=0 to see all)
>> >                   is_nothrow_copy_assignable<second_type>::value)
>> >                   ^
>> > /usr/bin/../lib/c++/v1/__config:253:34: note: expanded from macro
>> > '_NOEXCEPT_'
>> > #  define _NOEXCEPT_(x) noexcept(x)
>> >                                 ^
>> > /usr/bin/../lib/c++/v1/memory:2386:15: note: in instantiation of
>> > template class
>> > 'std::__1::__libcpp_compressed_pair_imp<std::__1::__tree_end_node<std::__1::__tree_node_base<void
>> > *> *>,
>> >      std::__1::allocator<std::__1::__tree_node<std::__1::pair<int,
>> > Templ8<int>::Member *>, void *>>, 2>' requested here
>> >    : private __libcpp_compressed_pair_imp<_T1, _T2>
>> >              ^
>> > /usr/bin/../lib/c++/v1/__tree:813:56: note: in instantiation of
>> > template class
>> > 'std::__1::__compressed_pair<std::__1::__tree_end_node<std::__1::__tree_node_base<void
>> > *> *>,
>> >      std::__1::allocator<std::__1::__tree_node<std::__1::pair<int,
>> > Templ8<int>::Member *>, void *>>>' requested here
>> >    __compressed_pair<__end_node_t, __node_allocator>  __pair1_;
>> >                                                       ^
>> > /usr/bin/../lib/c++/v1/map:711:22: note: in instantiation of template
>> > class 'std::__1::__tree<std::__1::pair<int, Templ8<int>::Member *>,
>> > std::__1::__map_value_compare<int, Templ8<int>::Member *,
>> >      std::__1::less<int>, true>,
>> > std::__1::allocator<std::__1::pair<int, Templ8<int>::Member *>>>'
>> > requested here
>> >    typedef typename __base::__node_traits                 __node_traits;
>> >                     ^
>> > main_bug.cpp:9:22: note: in instantiation of template class
>> > 'std::__1::map<int, Templ8<int>::Member *, std::__1::less<int>,
>> > std::__1::allocator<std::__1::pair<const int, Templ8<int>::Member
>> > *>>>'
>> >      requested here
>> >    typedef typename map<K,Member*>::iterator iterator_type;
>> >                     ^
>> > main_bug.cpp:13:17: note: in instantiation of template class
>> > 'Templ8<int>' requested here
>> >    Templ8<int> test;
>> >                ^
>> > 1 error generated.
>> > _______________________________________________
>> > LLVM Developers mailing list
>> > [hidden email]         http://llvm.cs.uiuc.edu
>> > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
>>
>> _______________________________________________
>> LLVM Developers mailing list
>> [hidden email]         http://llvm.cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
>
>


_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
Reply | Threaded
Open this post in threaded view
|

Re: Clang bug?

Adam Peterson
On Fri, Sep 28, 2012 at 7:11 PM, Richard Smith <[hidden email]> wrote:

> On Fri, Sep 28, 2012 at 5:11 PM, Adam Peterson <[hidden email]>
> wrote:
>>
>> This doesn't appear to me to be the same issue (but of course I don't
>> know clang as well as you all do).  This code appears invalid (and G++
>> rejects it with a similar "no type named ..." error message), whereas
>> the original code is valid C++ (both C++98 and C++11).
>
>
> [The difference in whether we accept the original code isn't clang versus
> g++, it's libc++ versus libstdc++. Clang with libstdc++ accepted this code.]

Right; I was just thrown off by the reduction of the test-case from
valid code to invalid code, and I was calling on G++ as secondary
anecdotal evidence, but in the context of the error message QoI, my
observation was misguided.

>
> There's two separate problems here. One is that given:
>
> typedef typename map<K,Member*>::iterator iterator_type;
>
> libc++'s std::map implementation was using a construct whose semantics
> depended on whether 'Member' is a complete type (thus triggering the
> instantiation of that type in the middle of instantiating map<K,Member*>,
> creating a dependency cycle between the two instantiations). I'm not at all
> clear on whether that is permissible behavior for a standard library
> implementation, but it still seems to be a problem in some cases.

The ramifications here are a bit beyond me, but certainly the ability
to create standard containers of pointers is fundamental, and it seems
to me like we (that is, someone like me, a programmer writing C++
code) would have ODR violations that are almost impossible to avoid if
the same template were instantiated differently depending on whether
the pointed-at type were complete.

> libc++'s
> is_assignable implementation uses SFINAE on this:
>
>   decltype((_VSTD::declval<_Tp>() = _VSTD::declval<_Arg>(), true_type()))
>
> Now, our case was: _Tp = Member*&, _Arg = Member*. In that case, we use the
> built-in assignment operator, which produces an lvalue of type Member*. Then
> we perform argument-dependent lookup looking for an overloaded 'operator,',
> because its RHS is of a class type.

Ugh.  That seems like enough to make me wonder if it were ever wise to
allow operator,() to be overloaded.  Its semantics are so different
from the built-in one and I've personally never found it useful.  (I
think boost::lambda uses it to some good effect, though.)

> This lookup triggers the (undesirable)
> instantiation of Member, because it is an associated class. I'm not sure
> exactly what has stopped this problem from manifesting, but the root cause
> superficially appears to still be present.

I'm curious, though.  Why doesn't the problem manifest if the typedef
is in the Member inner class?  And, for whatever reason that works,
can the same or a similar code-path be used when the typedef is in the
surrounding template scope?

>
>
> The other problem (the one my prior message was addressing) is that we have
> a diagnostic QoR issue, in that we produced a diagnostic message which is
> factually incorrect.

I understand now.  Thank you.
_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
Reply | Threaded
Open this post in threaded view
|

Re: Clang bug?

Howard Hinnant-2
In reply to this post by Richard Smith-33
On Sep 28, 2012, at 5:54 PM, Richard Smith <[hidden email]> wrote:

> Reduced testcase:
>
> template<typename T> struct A { typedef decltype(T() + 0) type; };
> template<typename T> struct B {
>   struct C { typedef typename A<C*>::type type; };
>   typedef typename A<C*>::type type;
> };
> B<int> b;
>
> ... produces ...
>
> <stdin>:3:38: error: no type named 'type' in 'A<B<int>::C *>'
>   struct C { typedef typename A<C*>::type type; };
>                      ~~~~~~~~~~~~~~~~^~~~
> <stdin>:1:54: note: in instantiation of member class 'B<int>::C' requested here
> template<typename T> struct A { typedef decltype(T() + 0) type; };
>                                                      ^
> <stdin>:4:20: note: in instantiation of template class 'A<B<int>::C *>' requested here
>   typedef typename A<C*>::type type;
>                    ^
> <stdin>:6:8: note: in instantiation of template class 'B<int>' requested here
> B<int> b;
>        ^
>
> I think it would be worth filing this as a diagnostic QoR issue. We should be able to say something like
>
> <stdin>:3:38: error: member 'type' of 'A<B<int>::C *>' required recursively within the instantiation of 'A<B<int>::C *>', but it has not been instantiated yet

Hi Richard,

Is your position that tot clang/libc++ is in error for not producing a diagnostic?

Howard

_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
Reply | Threaded
Open this post in threaded view
|

Re: Clang bug?

Richard Smith-33
On Fri, Sep 28, 2012 at 6:45 PM, Howard Hinnant <[hidden email]> wrote:
On Sep 28, 2012, at 5:54 PM, Richard Smith <[hidden email]> wrote:

> Reduced testcase:
>
> template<typename T> struct A { typedef decltype(T() + 0) type; };
> template<typename T> struct B {
>   struct C { typedef typename A<C*>::type type; };
>   typedef typename A<C*>::type type;
> };
> B<int> b;
>
> ... produces ...
>
> <stdin>:3:38: error: no type named 'type' in 'A<B<int>::C *>'
>   struct C { typedef typename A<C*>::type type; };
>                      ~~~~~~~~~~~~~~~~^~~~
> <stdin>:1:54: note: in instantiation of member class 'B<int>::C' requested here
> template<typename T> struct A { typedef decltype(T() + 0) type; };
>                                                      ^
> <stdin>:4:20: note: in instantiation of template class 'A<B<int>::C *>' requested here
>   typedef typename A<C*>::type type;
>                    ^
> <stdin>:6:8: note: in instantiation of template class 'B<int>' requested here
> B<int> b;
>        ^
>
> I think it would be worth filing this as a diagnostic QoR issue. We should be able to say something like
>
> <stdin>:3:38: error: member 'type' of 'A<B<int>::C *>' required recursively within the instantiation of 'A<B<int>::C *>', but it has not been instantiated yet

Hi Richard,

Is your position that tot clang/libc++ is in error for not producing a diagnostic?

No, my position is the opposite. Trunk clang + libc++ still reject this:

#include <type_traits>
template<typename T> struct S { static_assert(sizeof(T) == 1, ""); };
bool b = std::is_assignable<S<int>*&, S<int>*>::value;

... because is_assignable triggers the instantiation of S<int>.

I believe Clang is behaving correctly here. I don't know whether libc++'s implementation is valid (I don't know under what circumstances the library can use constructs which could depend on the completeness of user-provided types) but I suspect it is not, and even if it were, we'd want to allow this as a QoI issue. Here's a fix (first change: avoid overloaded 'operator,', second change: avoid ADL for __is_assignable_test):


--- type_traits (revision 164877)
+++ type_traits (working copy)
@@ -1187,10 +1187,15 @@
 
 #endif  // _LIBCPP_HAS_NO_VARIADICS
 
+template <class _Fst, class _Snd>
+struct __select_2nd {
+  typedef _Snd type;
+};
+
 // is_assignable
 
 template <class _Tp, class _Arg>
-decltype((_VSTD::declval<_Tp>() = _VSTD::declval<_Arg>(), true_type()))
+typename __select_2nd<decltype(_VSTD::declval<_Tp>() = _VSTD::declval<_Arg>()), true_type>::type
 #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
 __is_assignable_test(_Tp&&, _Arg&&);
 #else
@@ -1209,7 +1214,7 @@
 struct __is_assignable_imp
     : public common_type
         <
-            decltype(__is_assignable_test(declval<_Tp>(), declval<_Arg>()))
+            decltype(_VSTD::__is_assignable_test(declval<_Tp>(), declval<_Arg>()))
         >::type {};
 
 template <class _Tp, class _Arg>


I don't know whether there are other similar cases elsewhere in libc++, but that's enough to get my is_assignable test to work.

_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
Reply | Threaded
Open this post in threaded view
|

Re: Clang bug?

Howard Hinnant-2
On Sep 28, 2012, at 10:18 PM, Richard Smith <[hidden email]> wrote:

> On Fri, Sep 28, 2012 at 6:45 PM, Howard Hinnant <[hidden email]> wrote:
> On Sep 28, 2012, at 5:54 PM, Richard Smith <[hidden email]> wrote:
>
> > Reduced testcase:
> >
> > template<typename T> struct A { typedef decltype(T() + 0) type; };
> > template<typename T> struct B {
> >   struct C { typedef typename A<C*>::type type; };
> >   typedef typename A<C*>::type type;
> > };
> > B<int> b;
> >
> > ... produces ...
> >
> > <stdin>:3:38: error: no type named 'type' in 'A<B<int>::C *>'
> >   struct C { typedef typename A<C*>::type type; };
> >                      ~~~~~~~~~~~~~~~~^~~~
> > <stdin>:1:54: note: in instantiation of member class 'B<int>::C' requested here
> > template<typename T> struct A { typedef decltype(T() + 0) type; };
> >                                                      ^
> > <stdin>:4:20: note: in instantiation of template class 'A<B<int>::C *>' requested here
> >   typedef typename A<C*>::type type;
> >                    ^
> > <stdin>:6:8: note: in instantiation of template class 'B<int>' requested here
> > B<int> b;
> >        ^
> >
> > I think it would be worth filing this as a diagnostic QoR issue. We should be able to say something like
> >
> > <stdin>:3:38: error: member 'type' of 'A<B<int>::C *>' required recursively within the instantiation of 'A<B<int>::C *>', but it has not been instantiated yet
>
> Hi Richard,
>
> Is your position that tot clang/libc++ is in error for not producing a diagnostic?
>
> No, my position is the opposite. Trunk clang + libc++ still reject this:
>
> #include <type_traits>
> template<typename T> struct S { static_assert(sizeof(T) == 1, ""); };
> bool b = std::is_assignable<S<int>*&, S<int>*>::value;
>
> ... because is_assignable triggers the instantiation of S<int>.
>
> I believe Clang is behaving correctly here. I don't know whether libc++'s implementation is valid (I don't know under what circumstances the library can use constructs which could depend on the completeness of user-provided types) but I suspect it is not, and even if it were, we'd want to allow this as a QoI issue. Here's a fix (first change: avoid overloaded 'operator,', second change: avoid ADL for __is_assignable_test):
>
>
> --- type_traits (revision 164877)
> +++ type_traits (working copy)
> @@ -1187,10 +1187,15 @@
>  
>  #endif  // _LIBCPP_HAS_NO_VARIADICS
>  
> +template <class _Fst, class _Snd>
> +struct __select_2nd {
> +  typedef _Snd type;
> +};
> +
>  // is_assignable
>  
>  template <class _Tp, class _Arg>
> -decltype((_VSTD::declval<_Tp>() = _VSTD::declval<_Arg>(), true_type()))
> +typename __select_2nd<decltype(_VSTD::declval<_Tp>() = _VSTD::declval<_Arg>()), true_type>::type
>  #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
>  __is_assignable_test(_Tp&&, _Arg&&);
>  #else
> @@ -1209,7 +1214,7 @@
>  struct __is_assignable_imp
>      : public common_type
>          <
> -            decltype(__is_assignable_test(declval<_Tp>(), declval<_Arg>()))
> +            decltype(_VSTD::__is_assignable_test(declval<_Tp>(), declval<_Arg>()))
>          >::type {};
>  
>  template <class _Tp, class _Arg>
>
>
> I don't know whether there are other similar cases elsewhere in libc++, but that's enough to get my is_assignable test to work.

I'm a little confused, and admittedly skimming (it's late for me and I can't even believe you're still awake!).  But we seem to have a miscommunication somewhere.

For me, all with tot clang, your example is giving a diagnostic:

#include <type_traits>
template<typename T> struct S { static_assert(sizeof(T) == 1, ""); };
bool b = std::is_assignable<S<int>*&, S<int>*>::value;


But Adam's code:

   #include <map>
   using std::map;

   template<typename K>
   struct Templ8 {
       struct Member {
           typename map<K,Member*>::iterator it;
       };
       typedef typename map<K,Member*>::iterator iterator_type;
   };

   int main() {
       Templ8<int> test;
   }

is not giving a diagnostic (-stdlib=libc++ -std=c++11).

You seem to be saying that Adam's code with tot clang++ -stdlib=libc++ -std=c++11 is giving a diagnostic.  So there's a minor mystery here.

Howard

_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
Reply | Threaded
Open this post in threaded view
|

Re: Clang bug?

Richard Smith-33
On Fri, Sep 28, 2012 at 7:35 PM, Howard Hinnant <[hidden email]> wrote:
On Sep 28, 2012, at 10:18 PM, Richard Smith <[hidden email]> wrote:

> On Fri, Sep 28, 2012 at 6:45 PM, Howard Hinnant <[hidden email]> wrote:
> On Sep 28, 2012, at 5:54 PM, Richard Smith <[hidden email]> wrote:
>
> > Reduced testcase:
> >
> > template<typename T> struct A { typedef decltype(T() + 0) type; };
> > template<typename T> struct B {
> >   struct C { typedef typename A<C*>::type type; };
> >   typedef typename A<C*>::type type;
> > };
> > B<int> b;
> >
> > ... produces ...
> >
> > <stdin>:3:38: error: no type named 'type' in 'A<B<int>::C *>'
> >   struct C { typedef typename A<C*>::type type; };
> >                      ~~~~~~~~~~~~~~~~^~~~
> > <stdin>:1:54: note: in instantiation of member class 'B<int>::C' requested here
> > template<typename T> struct A { typedef decltype(T() + 0) type; };
> >                                                      ^
> > <stdin>:4:20: note: in instantiation of template class 'A<B<int>::C *>' requested here
> >   typedef typename A<C*>::type type;
> >                    ^
> > <stdin>:6:8: note: in instantiation of template class 'B<int>' requested here
> > B<int> b;
> >        ^
> >
> > I think it would be worth filing this as a diagnostic QoR issue. We should be able to say something like
> >
> > <stdin>:3:38: error: member 'type' of 'A<B<int>::C *>' required recursively within the instantiation of 'A<B<int>::C *>', but it has not been instantiated yet
>
> Hi Richard,
>
> Is your position that tot clang/libc++ is in error for not producing a diagnostic?
>
> No, my position is the opposite. Trunk clang + libc++ still reject this:
>
> #include <type_traits>
> template<typename T> struct S { static_assert(sizeof(T) == 1, ""); };
> bool b = std::is_assignable<S<int>*&, S<int>*>::value;
>
> ... because is_assignable triggers the instantiation of S<int>.
>
> I believe Clang is behaving correctly here. I don't know whether libc++'s implementation is valid (I don't know under what circumstances the library can use constructs which could depend on the completeness of user-provided types) but I suspect it is not, and even if it were, we'd want to allow this as a QoI issue. Here's a fix (first change: avoid overloaded 'operator,', second change: avoid ADL for __is_assignable_test):
>
>
> --- type_traits (revision 164877)
> +++ type_traits (working copy)
> @@ -1187,10 +1187,15 @@
>
>  #endif  // _LIBCPP_HAS_NO_VARIADICS
>
> +template <class _Fst, class _Snd>
> +struct __select_2nd {
> +  typedef _Snd type;
> +};
> +
>  // is_assignable
>
>  template <class _Tp, class _Arg>
> -decltype((_VSTD::declval<_Tp>() = _VSTD::declval<_Arg>(), true_type()))
> +typename __select_2nd<decltype(_VSTD::declval<_Tp>() = _VSTD::declval<_Arg>()), true_type>::type
>  #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
>  __is_assignable_test(_Tp&&, _Arg&&);
>  #else
> @@ -1209,7 +1214,7 @@
>  struct __is_assignable_imp
>      : public common_type
>          <
> -            decltype(__is_assignable_test(declval<_Tp>(), declval<_Arg>()))
> +            decltype(_VSTD::__is_assignable_test(declval<_Tp>(), declval<_Arg>()))
>          >::type {};
>
>  template <class _Tp, class _Arg>
>
>
> I don't know whether there are other similar cases elsewhere in libc++, but that's enough to get my is_assignable test to work.

I'm a little confused, and admittedly skimming (it's late for me and I can't even believe you're still awake!).  But we seem to have a miscommunication somewhere.

For me, all with tot clang, your example is giving a diagnostic:

#include <type_traits>
template<typename T> struct S { static_assert(sizeof(T) == 1, ""); };
bool b = std::is_assignable<S<int>*&, S<int>*>::value;

And likewise for me. This code triggers the instantiation of S<int>. My claim was that this code need not give a diagnostic (although it's on very thin ice) because we don't actually need to instantiate S<int>. And it's not clear to me that the standard allows us to give a diagnostic here, because the expression declval<S<int>*&>() = declval<S<int>*>() is probably well-formed (this is somewhat debatable, because the pointer conversion rules for built-in pointer comparisons in 5.10/1 are handwaved over and 14.7.1/1 is a little vague, but g++, clang and EDG all accept it).
 
But Adam's code:

   #include <map>
   using std::map;

   template<typename K>
   struct Templ8 {
       struct Member {
           typename map<K,Member*>::iterator it;
       };
       typedef typename map<K,Member*>::iterator iterator_type;
   };

   int main() {
       Templ8<int> test;
   }

is not giving a diagnostic (-stdlib=libc++ -std=c++11).

You seem to be saying that Adam's code with tot clang++ -stdlib=libc++ -std=c++11 is giving a diagnostic.  So there's a minor mystery here.

Apologies for the confusion. I didn't mean to imply that Adam's code is currently giving a diagnostic for me. The original report was that this code did give a diagnostic, and then "got better", and my observation was that the component of libc++ which was causing the spurious diagnostic (is_assignable) still has the same behavior. FWIW, it looks like it was the delayed instantiation of exception specifications which fixed this.

_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev