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