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 <hhinnant at apple.com> 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 <alpha.eta.pi at gmail.com> 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 > > LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev > > _______________________________________________ > LLVM Developers mailing list > LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20120928/828399b0/attachment.html>
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 <richard at metafoo.co.uk> 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 <hhinnant at apple.com> 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 <alpha.eta.pi at gmail.com> 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 >> > LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu >> > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev >> >> _______________________________________________ >> LLVM Developers mailing list >> LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu >> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev > >
On Fri, Sep 28, 2012 at 5:11 PM, Adam Peterson <alpha.eta.pi at gmail.com>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 <richard at metafoo.co.uk> > 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 <hhinnant at apple.com> > 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 <alpha.eta.pi at gmail.com> > 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 > >> > LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > >> > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev > >> > >> _______________________________________________ > >> LLVM Developers mailing list > >> LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > >> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev > > > > >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20120928/f2b00fde/attachment.html>
On Sep 28, 2012, at 5:54 PM, Richard Smith <richard at metafoo.co.uk> 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 yetHi Richard, Is your position that tot clang/libc++ is in error for not producing a diagnostic? Howard
On Fri, Sep 28, 2012 at 6:45 PM, Howard Hinnant <hhinnant at apple.com> wrote:> On Sep 28, 2012, at 5:54 PM, Richard Smith <richard at metafoo.co.uk> 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. -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20120928/49b92df2/attachment.html>