Bug 44175 - [C++0x] decltype sometimes cannot recurse
Summary: [C++0x] decltype sometimes cannot recurse
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.5.0
: P3 normal
Target Milestone: 4.7.0
Assignee: Jason Merrill
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-05-17 19:37 UTC by David Krauss
Modified: 2011-06-08 21:56 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2010-05-17 19:40:46


Attachments
recursive decltype crashes g++ (181 bytes, text/plain)
2010-05-17 19:38 UTC, David Krauss
Details
recursive decltype crashes g++ (177 bytes, text/plain)
2010-05-17 20:10 UTC, David Krauss
Details
regression test using G++ typeof (186 bytes, text/plain)
2010-05-17 22:56 UTC, David Krauss
Details

Note You need to log in before you can comment on or make changes to this bug.
Description David Krauss 2010-05-17 19:37:38 UTC
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.
Comment 1 David Krauss 2010-05-17 19:38:56 UTC
Created attachment 20686 [details]
recursive decltype crashes g++
Comment 2 Paolo Carlini 2010-05-17 19:40:46 UTC
Many thanks. Let's add Jason in CC.
Comment 3 David Krauss 2010-05-17 20:10:27 UTC
Created attachment 20687 [details]
recursive decltype crashes g++

fix minor error (no change in behavior)
Comment 4 David Krauss 2010-05-17 20:44:19 UTC
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.
Comment 5 David Krauss 2010-05-17 22:56:32 UTC
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.
Comment 6 Jason Merrill 2011-06-01 20:27:26 UTC
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
Comment 7 Jason Merrill 2011-06-07 21:54:13 UTC
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
Comment 8 Jakub Jelinek 2011-06-08 06:08:54 UTC
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.
Comment 9 Jakub Jelinek 2011-06-08 12:16:49 UTC
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.
Comment 10 Jason Merrill 2011-06-08 21:56:46 UTC
The deep recursion issue is in the actual recursive template substitution, not the tinst_level stuff.