See attached testcase. Several things can happen when decltype is used in a function template's return type to refer to another specialization of the same template. - The right thing (not easily produced from the current code, but see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=44162) - Non-production of a candidate, a la SFINAE - g++: Internal error: Segmentation fault (program cc1plus). This happens for me with the given testcase. As the "recursive" type must be dependent, it should be evaluated at the point of instantiation. Using the template's identifier even before it has been defined shouldn't be an issue. The behavior seems to depend on what types are passed to the template in question. Type deduction doesn't seem to matter. Types involving only primitives are likely to quietly fail. Types involving classes may succeed or crash. For example, if I adjust ft<a,2> to ft<int,2>, no crash.
Created attachment 20686 [details] recursive decltype crashes g++
Many thanks. Let's add Jason in CC.
Created attachment 20687 [details] recursive decltype crashes g++ fix minor error (no change in behavior)
The crash may have something to do with using a dependent type in a particular context. This shorter code still crashes despite resolution failing — no recursion… #include <type_traits> template< int x > typename std::enable_if< x*0 >::type ft() {} template< class F, int n > decltype( ft< F >( F() ) ) ft() {} int main() { ft< struct a *, 0 >(); } It's conceivable that I'm seeing more than one issue, though.
Created attachment 20690 [details] regression test using G++ typeof Here is a version that doesn't require C++0x. It uses the typeof extension. It compiles on Apple GCC 4.2.1 and crashes my 4.5.
Author: jason Date: Wed Jun 1 20:27:22 2011 New Revision: 174543 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=174543 Log: PR c++/44175 * pt.c (template_args_equal): Handle one arg being NULL_TREE. (deduction_tsubst_fntype): Handle excessive non-infinite recursion. Added: trunk/gcc/testsuite/g++.dg/cpp0x/decltype28.C trunk/gcc/testsuite/g++.dg/cpp0x/decltype29.C Modified: trunk/gcc/cp/ChangeLog trunk/gcc/cp/pt.c trunk/gcc/testsuite/ChangeLog
Author: jason Date: Tue Jun 7 21:54:07 2011 New Revision: 174772 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=174772 Log: PR c++/48969 PR c++/44175 gcc/c-family/ * c-common.c (max_tinst_depth): Lower default to 900. gcc/cp/ * error.c (subst_to_string): New. (cp_printer): Use it for 'S'. (print_instantiation_partial_context_line): Handle subst context. * pt.c (push_tinst_level): Handle subst context. (deduction_tsubst_fntype): Don't track specific substitutions. Use push_tinst_level. Modified: trunk/gcc/c-family/ChangeLog trunk/gcc/c-family/c-common.c trunk/gcc/cp/ChangeLog trunk/gcc/cp/error.c trunk/gcc/cp/pt.c trunk/gcc/doc/invoke.texi trunk/gcc/testsuite/ChangeLog trunk/gcc/testsuite/g++.dg/abi/mangle11.C trunk/gcc/testsuite/g++.dg/abi/mangle12.C trunk/gcc/testsuite/g++.dg/abi/mangle17.C trunk/gcc/testsuite/g++.dg/abi/mangle20-2.C trunk/gcc/testsuite/g++.dg/abi/pragma-pack1.C trunk/gcc/testsuite/g++.dg/cpp0x/decltype26.C trunk/gcc/testsuite/g++.dg/cpp0x/decltype28.C trunk/gcc/testsuite/g++.dg/cpp0x/decltype29.C trunk/gcc/testsuite/g++.dg/cpp0x/enum11.C trunk/gcc/testsuite/g++.dg/cpp0x/forw_enum8.C trunk/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-errloc2.C trunk/gcc/testsuite/g++.dg/cpp0x/pr47416.C trunk/gcc/testsuite/g++.dg/ext/case-range2.C trunk/gcc/testsuite/g++.dg/ext/case-range3.C trunk/gcc/testsuite/g++.dg/gomp/for-19.C trunk/gcc/testsuite/g++.dg/gomp/pr37533.C trunk/gcc/testsuite/g++.dg/gomp/pr38639.C trunk/gcc/testsuite/g++.dg/gomp/tpl-parallel-2.C trunk/gcc/testsuite/g++.dg/inherit/base3.C trunk/gcc/testsuite/g++.dg/inherit/using6.C trunk/gcc/testsuite/g++.dg/init/placement4.C trunk/gcc/testsuite/g++.dg/init/reference3.C trunk/gcc/testsuite/g++.dg/lookup/scoped6.C trunk/gcc/testsuite/g++.dg/lookup/using7.C trunk/gcc/testsuite/g++.dg/other/abstract1.C trunk/gcc/testsuite/g++.dg/other/error10.C trunk/gcc/testsuite/g++.dg/other/error5.C trunk/gcc/testsuite/g++.dg/other/field1.C trunk/gcc/testsuite/g++.dg/other/offsetof5.C trunk/gcc/testsuite/g++.dg/parse/bitfield2.C trunk/gcc/testsuite/g++.dg/parse/constant4.C trunk/gcc/testsuite/g++.dg/parse/crash20.C trunk/gcc/testsuite/g++.dg/parse/invalid-op1.C trunk/gcc/testsuite/g++.dg/parse/non-dependent2.C trunk/gcc/testsuite/g++.dg/parse/template18.C trunk/gcc/testsuite/g++.dg/tc1/dr152.C trunk/gcc/testsuite/g++.dg/tc1/dr166.C trunk/gcc/testsuite/g++.dg/tc1/dr176.C trunk/gcc/testsuite/g++.dg/tc1/dr213.C trunk/gcc/testsuite/g++.dg/template/access11.C trunk/gcc/testsuite/g++.dg/template/access2.C trunk/gcc/testsuite/g++.dg/template/access3.C trunk/gcc/testsuite/g++.dg/template/access7.C trunk/gcc/testsuite/g++.dg/template/arg7.C trunk/gcc/testsuite/g++.dg/template/cond2.C trunk/gcc/testsuite/g++.dg/template/crash13.C trunk/gcc/testsuite/g++.dg/template/crash40.C trunk/gcc/testsuite/g++.dg/template/crash7.C trunk/gcc/testsuite/g++.dg/template/crash84.C trunk/gcc/testsuite/g++.dg/template/ctor5.C trunk/gcc/testsuite/g++.dg/template/defarg13.C trunk/gcc/testsuite/g++.dg/template/defarg14.C trunk/gcc/testsuite/g++.dg/template/dtor7.C trunk/gcc/testsuite/g++.dg/template/eh2.C trunk/gcc/testsuite/g++.dg/template/error2.C trunk/gcc/testsuite/g++.dg/template/error43.C trunk/gcc/testsuite/g++.dg/template/friend32.C trunk/gcc/testsuite/g++.dg/template/injected1.C trunk/gcc/testsuite/g++.dg/template/instantiate1.C trunk/gcc/testsuite/g++.dg/template/instantiate3.C trunk/gcc/testsuite/g++.dg/template/instantiate5.C trunk/gcc/testsuite/g++.dg/template/instantiate7.C trunk/gcc/testsuite/g++.dg/template/local6.C trunk/gcc/testsuite/g++.dg/template/lookup2.C trunk/gcc/testsuite/g++.dg/template/member5.C trunk/gcc/testsuite/g++.dg/template/memfriend15.C trunk/gcc/testsuite/g++.dg/template/memfriend16.C trunk/gcc/testsuite/g++.dg/template/memfriend17.C trunk/gcc/testsuite/g++.dg/template/memfriend7.C trunk/gcc/testsuite/g++.dg/template/meminit1.C trunk/gcc/testsuite/g++.dg/template/nested3.C trunk/gcc/testsuite/g++.dg/template/non-type-template-argument-1.C trunk/gcc/testsuite/g++.dg/template/nontype12.C trunk/gcc/testsuite/g++.dg/template/nontype13.C trunk/gcc/testsuite/g++.dg/template/nontype6.C trunk/gcc/testsuite/g++.dg/template/pr23510.C trunk/gcc/testsuite/g++.dg/template/pr35240.C trunk/gcc/testsuite/g++.dg/template/ptrmem15.C trunk/gcc/testsuite/g++.dg/template/ptrmem6.C trunk/gcc/testsuite/g++.dg/template/qualified-id1.C trunk/gcc/testsuite/g++.dg/template/qualttp20.C trunk/gcc/testsuite/g++.dg/template/qualttp3.C trunk/gcc/testsuite/g++.dg/template/qualttp4.C trunk/gcc/testsuite/g++.dg/template/qualttp5.C trunk/gcc/testsuite/g++.dg/template/qualttp6.C trunk/gcc/testsuite/g++.dg/template/qualttp7.C trunk/gcc/testsuite/g++.dg/template/qualttp8.C trunk/gcc/testsuite/g++.dg/template/recurse.C trunk/gcc/testsuite/g++.dg/template/recurse2.C trunk/gcc/testsuite/g++.dg/template/ref5.C trunk/gcc/testsuite/g++.dg/template/scope2.C trunk/gcc/testsuite/g++.dg/template/sfinae10.C trunk/gcc/testsuite/g++.dg/template/sfinae3.C trunk/gcc/testsuite/g++.dg/template/sizeof3.C trunk/gcc/testsuite/g++.dg/template/static9.C trunk/gcc/testsuite/g++.dg/template/template-id-2.C trunk/gcc/testsuite/g++.dg/template/typedef13.C trunk/gcc/testsuite/g++.dg/template/typename4.C trunk/gcc/testsuite/g++.dg/template/using14.C trunk/gcc/testsuite/g++.dg/template/using2.C trunk/gcc/testsuite/g++.dg/template/warn1.C trunk/gcc/testsuite/g++.dg/warn/Wparentheses-13.C trunk/gcc/testsuite/g++.dg/warn/Wparentheses-15.C trunk/gcc/testsuite/g++.dg/warn/Wparentheses-16.C trunk/gcc/testsuite/g++.dg/warn/Wparentheses-17.C trunk/gcc/testsuite/g++.dg/warn/Wparentheses-18.C trunk/gcc/testsuite/g++.dg/warn/Wparentheses-19.C trunk/gcc/testsuite/g++.dg/warn/Wparentheses-20.C trunk/gcc/testsuite/g++.dg/warn/Wparentheses-23.C trunk/gcc/testsuite/g++.dg/warn/Wstrict-aliasing-3.C trunk/gcc/testsuite/g++.dg/warn/noeffect2.C trunk/gcc/testsuite/g++.dg/warn/noeffect4.C trunk/gcc/testsuite/g++.dg/warn/pr8570.C trunk/gcc/testsuite/g++.old-deja/g++.brendan/init2.C trunk/gcc/testsuite/g++.old-deja/g++.eh/spec6.C trunk/gcc/testsuite/g++.old-deja/g++.pt/crash10.C trunk/gcc/testsuite/g++.old-deja/g++.pt/crash36.C trunk/gcc/testsuite/g++.old-deja/g++.pt/derived3.C trunk/gcc/testsuite/g++.old-deja/g++.pt/error2.C trunk/gcc/testsuite/g++.old-deja/g++.pt/explicit70.C trunk/gcc/testsuite/g++.old-deja/g++.pt/infinite1.C trunk/gcc/testsuite/g++.old-deja/g++.pt/memtemp89.C trunk/gcc/testsuite/g++.old-deja/g++.pt/overload7.C trunk/gcc/testsuite/g++.old-deja/g++.pt/vaarg3.C trunk/gcc/testsuite/lib/prune.exp trunk/libstdc++-v3/ChangeLog trunk/libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc trunk/libstdc++-v3/testsuite/20_util/duration/requirements/typedefs_neg1.cc trunk/libstdc++-v3/testsuite/20_util/duration/requirements/typedefs_neg2.cc trunk/libstdc++-v3/testsuite/20_util/duration/requirements/typedefs_neg3.cc trunk/libstdc++-v3/testsuite/20_util/forward/1_neg.cc trunk/libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc trunk/libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc trunk/libstdc++-v3/testsuite/20_util/ratio/cons/cons_overflow_neg.cc trunk/libstdc++-v3/testsuite/20_util/ratio/operations/ops_overflow_neg.cc trunk/libstdc++-v3/testsuite/20_util/shared_ptr/assign/shared_ptr_neg.cc trunk/libstdc++-v3/testsuite/ext/ext_pointer/1_neg.cc trunk/libstdc++-v3/testsuite/ext/pb_ds/example/hash_resize_neg.cc trunk/libstdc++-v3/testsuite/ext/type_traits/add_unsigned_floating_neg.cc trunk/libstdc++-v3/testsuite/ext/type_traits/add_unsigned_integer_neg.cc trunk/libstdc++-v3/testsuite/ext/type_traits/remove_unsigned_floating_neg.cc trunk/libstdc++-v3/testsuite/ext/type_traits/remove_unsigned_integer_neg.cc trunk/libstdc++-v3/testsuite/lib/prune.exp trunk/libstdc++-v3/testsuite/tr1/2_general_utilities/shared_ptr/assign/shared_ptr_neg.cc
I wonder if for at least Linux host the driver shouldn't attempt to increase stack size for its children, say to 32MB if possible: { struct rlimit rl; if (getrlimit (RLIMIT_STACK, &rl) == 0) { if (rl.rlim_cur != RLIM_INFINITY && rl.rlim_cur < 32*1024*1024 && (rl.rlim_max == RLIM_INFINITY || rl.rlim_max > rl.rlim_cur)) { if (rl.rlim_max == RLIM_INFINITY || rl.rlim_max >= 32*1024*1024) rl.rlim_cur = 32*1024*1024; else rl.rlim_cur = rl.rlim_max; setrlimit (RLIMIT_STACK, &rl); } } } then I guess maximum tinst depth could go back to 1024.
Additionally, if the only deep recursion problem is during GC, perhaps: --- gcc/cp/cp-tree.h 2011-05-27 21:13:30.946483346 +0200 +++ gcc/cp/cp-tree.h 2011-06-08 14:15:06.743389464 +0200 @@ -4635,7 +4635,7 @@ struct cp_declarator { }; /* A level of template instantiation. */ -struct GTY(()) tinst_level { +struct GTY((chain_next ("%h.next"))) tinst_level { /* The immediately deeper level in the chain. */ struct tinst_level *next; could fix it and allow going back to 1024 from 900.
The deep recursion issue is in the actual recursive template substitution, not the tinst_level stuff.