Bug 56247 - [4.6/4.7/4.8 Regression] internal compiler error: in tsubst_copy, at cp/pt.c:12131
Summary: [4.6/4.7/4.8 Regression] internal compiler error: in tsubst_copy, at cp/pt.c:...
Status: VERIFIED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.7.2
: P2 normal
Target Milestone: 4.6.4
Assignee: Jason Merrill
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2013-02-07 22:28 UTC by DS
Modified: 2020-04-18 10:55 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2013-02-07 00:00:00


Attachments
Test case (275 bytes, application/octet-stream)
2013-02-07 22:28 UTC, DS
Details

Note You need to log in before you can comment on or make changes to this bug.
Description DS 2013-02-07 22:28:25 UTC
Created attachment 29392 [details]
Test case

ICE when the same member function pointer (to a base class's method) is used as a template parameter from two different methods of the same templated child class. What's a bit unusual here is that the bug is only triggered if the same instantiation occurs in two different methods.

The reduced test case is short enough to include directly:

--------
struct Base {
    void method() {}
};  

typedef void (Base::*MemPtr)();

// Template with a member function pointer "non-type parameter".
template<MemPtr func>
struct Wrapper {};

template<class C>
struct Child : public Base {
    // Templated derived class instantiates the Wrapper with the same parameter
    // in two different virtual methods.
    void foo() { typedef Wrapper<&Base::method> W; }
    void bar() { typedef Wrapper<&Base::method> W; }
};

// Instantiate Child with some type. 
template class Child<int>;
--------

Here's the detailed gcc output:
% /usr/local/bin/g++47 -v -save-temps -c bugtest.cc
Using built-in specs.
COLLECT_GCC=/usr/local/bin/g++47
Target: x86_64-portbld-freebsd8.2
Configured with: ./../gcc-4.7-20120818/configure --disable-nls --enable-languages=c,c++,objc,fortran --libdir=/usr/local/lib/gcc47 --libexecdir=/usr/local/libexec/gcc47 --program-suffix=47 --with-as=/usr/local/bin/as --with-gmp=/usr/local --with-gxx-include-dir=/usr/local/lib/gcc47/include/c++/ --with-ld=/usr/local/bin/ld --with-libiconv-prefix=/usr/local --with-pkgversion='FreeBSD Ports Collection' --with-system-zlib --enable-languages=c,c++,objc,fortran,java --prefix=/usr/local --mandir=/usr/local/man --infodir=/usr/local/info/gcc47 --build=x86_64-portbld-freebsd8.2
Thread model: posix
gcc version 4.7.2 20120818 (prerelease) (FreeBSD Ports Collection) 
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64'
 /usr/local/libexec/gcc47/gcc/x86_64-portbld-freebsd8.2/4.7.2/cc1plus -E -quiet -v src/scratch/bugtest.cc -mtune=generic -march=x86-64 -fpch-preprocess -o bugtest.ii
ignoring nonexistent directory "/usr/local/lib/gcc47/gcc/x86_64-portbld-freebsd8.2/4.7.2/../../../../../x86_64-portbld-freebsd8.2/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/local/lib/gcc47/include/c++/
 /usr/local/lib/gcc47/include/c++//x86_64-portbld-freebsd8.2
 /usr/local/lib/gcc47/include/c++//backward
 /usr/local/lib/gcc47/gcc/x86_64-portbld-freebsd8.2/4.7.2/include
 /usr/local/include
 /usr/local/lib/gcc47/gcc/x86_64-portbld-freebsd8.2/4.7.2/include-fixed
 /usr/include
End of search list.
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64'
 /usr/local/libexec/gcc47/gcc/x86_64-portbld-freebsd8.2/4.7.2/cc1plus -fpreprocessed bugtest.ii -quiet -dumpbase bugtest.cc -mtune=generic -march=x86-64 -auxbase bugtest -version -o bugtest.s
GNU C++ (FreeBSD Ports Collection) version 4.7.2 20120818 (prerelease) (x86_64-portbld-freebsd8.2)
        compiled by GNU C version 4.7.2 20120818 (prerelease), GMP version 5.0.1, MPFR version 3.0.0, MPC version 0.8.2
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
GNU C++ (FreeBSD Ports Collection) version 4.7.2 20120818 (prerelease) (x86_64-portbld-freebsd8.2)
        compiled by GNU C version 4.7.2 20120818 (prerelease), GMP version 5.0.1, MPFR version 3.0.0, MPC version 0.8.2
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 4c5936a9f1a6230b2e84e5f997572e48
src/scratch/bugtest.cc: In instantiation of 'void Child<C>::bar() [with C = int]':
src/scratch/bugtest.cc:21:16:   required from here
src/scratch/bugtest.cc:17:49: internal compiler error: in tsubst_copy, at cp/pt.c:12131
Please submit a full bug report,
with preprocessed source if appropriate.
See <http://gcc.gnu.org/bugs.html> for instructions.
Comment 1 Paolo Carlini 2013-02-07 23:44:56 UTC
Confirmed. 4.5.4 works for me.
Comment 2 Jakub Jelinek 2013-02-08 08:46:12 UTC
Started with http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=149223
Comment 3 Jason Merrill 2013-02-09 20:39:21 UTC
Author: jason
Date: Sat Feb  9 20:39:13 2013
New Revision: 195922

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=195922
Log:
	PR c++/56247
	* pt.c (eq_specializations): Set comparing_specializations.
	* tree.c (cp_tree_equal): Check it.
	* cp-tree.h: Declare it.

Added:
    trunk/gcc/testsuite/g++.dg/template/ptrmem23.C
Modified:
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/cp-tree.h
    trunk/gcc/cp/pt.c
    trunk/gcc/cp/tree.c
Comment 4 Jason Merrill 2013-02-09 20:47:31 UTC
Author: jason
Date: Sat Feb  9 20:47:24 2013
New Revision: 195923

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=195923
Log:
	PR c++/56247
	* pt.c (eq_specializations): Set comparing_specializations.
	* tree.c (cp_tree_equal): Check it.
	* cp-tree.h: Declare it.

Added:
    branches/gcc-4_7-branch/gcc/testsuite/g++.dg/template/ptrmem23.C
Modified:
    branches/gcc-4_7-branch/gcc/cp/ChangeLog
    branches/gcc-4_7-branch/gcc/cp/cp-tree.h
    branches/gcc-4_7-branch/gcc/cp/pt.c
    branches/gcc-4_7-branch/gcc/cp/tree.c
Comment 5 Jason Merrill 2013-02-09 20:54:05 UTC
Author: jason
Date: Sat Feb  9 20:53:59 2013
New Revision: 195924

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=195924
Log:
	PR c++/56247
	* pt.c (eq_specializations): Set comparing_specializations.
	* tree.c (cp_tree_equal): Check it.
	* cp-tree.h: Declare it.

Added:
    branches/gcc-4_6-branch/gcc/testsuite/g++.dg/template/ptrmem23.C
Modified:
    branches/gcc-4_6-branch/gcc/cp/ChangeLog
    branches/gcc-4_6-branch/gcc/cp/cp-tree.h
    branches/gcc-4_6-branch/gcc/cp/pt.c
    branches/gcc-4_6-branch/gcc/cp/tree.c
Comment 6 Jakub Jelinek 2013-02-11 08:48:14 UTC
Fixed.
Comment 7 DS 2013-03-01 19:59:04 UTC
Awesome quick work. Very impressive -- thank you!
Comment 8 GCC Commits 2020-04-18 10:55:58 UTC
The master branch has been updated by Patrick Palka <ppalka@gcc.gnu.org>:

https://gcc.gnu.org/g:f83adb68ed9cef1fbd4c16447eb4e89676df9f62

commit r10-7787-gf83adb68ed9cef1fbd4c16447eb4e89676df9f62
Author: Patrick Palka <ppalka@redhat.com>
Date:   Sat Apr 18 06:22:21 2020 -0400

    c++: spec_hasher::equal and PARM_DECLs [PR94632]
    
    In the testcase below, during specialization of c<int>::d, we build two
    identical specializations of the parameter type b<decltype(e)::k> -- one when
    substituting into c<int>::d's TYPE_ARG_TYPES and another when substituting into
    c<int>::d's DECL_ARGUMENTS.
    
    We don't reuse the first specialization the second time around as a consequence
    of the fix for PR c++/56247 which made PARM_DECLs always compare different from
    one another during spec_hasher::equal.  As a result, when looking up existing
    specializations of 'b', spec_hasher::equal considers the template argument
    decltype(e')::k to be different from decltype(e'')::k, where e' and e'' are the
    result of two calls to tsubst_copy on the PARM_DECL e.
    
    Since the two specializations are considered different due to the mentioned fix,
    their TYPE_CANONICAL points to themselves even though they are otherwise
    identical types, and this triggers an ICE in maybe_rebuild_function_decl_type
    when comparing the TYPE_ARG_TYPES of c<int>::d to its DECL_ARGUMENTS.
    
    This patch fixes this issue at the spec_hasher::equal level by ignoring the
    'comparing_specializations' flag in cp_tree_equal whenever the DECL_CONTEXTs of
    the two parameters are identical.  This seems to be a sufficient condition to be
    able to correctly compare PARM_DECLs structurally.  (This also subsumes the
    CONSTRAINT_VAR_P check since constraint variables all have empty, and therefore
    identical, DECL_CONTEXTs.)
    
    gcc/cp/ChangeLog:
    
            PR c++/94632
            * tree.c (cp_tree_equal) <case PARM_DECL>: Ignore
            comparing_specializations if the parameters' contexts are identical.
    
    gcc/testsuite/ChangeLog:
    
            PR c++/94632
            * g++.dg/template/canon-type-14.C: New test.