Bug 15480 - ICE with sizeof(T().f()) as template parameter in function resolution
Summary: ICE with sizeof(T().f()) as template parameter in function resolution
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 3.4.0
: P2 normal
Target Milestone: 4.5.0
Assignee: Not yet assigned to anyone
URL:
Keywords: ice-on-valid-code, rejects-valid
Depends on:
Blocks:
 
Reported: 2004-05-16 21:27 UTC by gianni
Modified: 2009-04-16 16:35 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail: 3.2.3 3.3.3 3.4.0 4.0.0 2.95.3 3.0.4
Last reconfirmed: 2005-11-10 23:02:37


Attachments
Patch for the ICE (444 bytes, patch)
2004-05-18 02:15 UTC, Giovanni Bajo
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description gianni 2004-05-16 21:27:38 UTC
Below is a template that is supposed to discover wether a type contains a method
 named "Function".

Comeau compiles this fine on Comeau C/C++ 4.3.3, fails on MSC++ 7.1 with what
seems to be the wrong error and ICE's on gcc 3.4.0.



typedef char MPT_False;

struct MPT_True { int m[2]; };


template <unsigned int w_siz>
struct MPT_IntToType
{
    typedef char    type[ w_siz ];
};

template <typename w_D>
struct MPT_Finder_Member
{
    template <typename w_T>
    static MPT_True finder(
        const w_T *,
        typename MPT_IntToType<
            sizeof(w_T().Function())
//          sizeof(static_cast<w_T>(0)->Function()) //fails same way
        >::type * = 0
    );
        
    static MPT_False finder( const w_D * );

};

template <typename w_D >
struct MPT_ContainsFuncMember
{
    struct DerivedClass : w_D
    {
    };

    typedef DerivedClass  * DerivedClassp;

    enum {
        value = (
            sizeof( MPT_Finder_Member<w_D>::finder( DerivedClassp() ) )
            == sizeof( MPT_True )
        )
    };
    
};


struct A
{
};

struct B
{
    int Function();
};

#include <iostream>

int main()
{
    std::cout << MPT_ContainsFuncMember<A>::value << "\n";
    std::cout << MPT_ContainsFuncMember<B>::value << "\n";
}
Comment 1 gianni 2004-05-16 21:29:40 UTC
Adding ice-on-valid-code kw.
Comment 2 Andrew Pinski 2004-05-16 21:39:06 UTC
Confirmed.
Here is a simplied example (it might be turned into invalid though):
template <unsigned int w_siz>
struct MPT_IntToType
{
    typedef char    type;
};
template <typename w_D>
struct MPT_Finder_Member
{
    template <typename w_T>
    static int finder(
        const w_T *,
        typename MPT_IntToType<
            sizeof(w_T().Function())
        >::type * = 0
    );
    static int finder( const w_D * );
};
template <typename w_D >
struct MPT_ContainsFuncMember
{
    struct DerivedClass : w_D{};
    typedef DerivedClass  * DerivedClassp;
    enum {
        value = (
            sizeof( MPT_Finder_Member<w_D>::finder( DerivedClassp() ) )
            == sizeof( int)
        )
    };
};
struct A{};
int t = MPT_ContainsFuncMember<A>::value;
Comment 3 Giovanni Bajo 2004-05-17 00:47:01 UTC
Fails with 3.2.3, 3.3.3, 3.4.0 and current mainline. Interestingly enough, it 
used to work with 3.4.0 20040216.

What does it happen with 2.95?
Comment 4 Andrew Pinski 2004-05-17 00:57:13 UTC
2.95.3 and 3.0.4 fails (I had forgot to fill in known to fail, woops).
Comment 5 Wolfgang Bangerth 2004-05-17 02:56:44 UTC
Here is a yet simpler example: 
------------------- 
template <int> struct S {}; 
 
template <int> struct G { 
    template <typename U> 
    static int finder(U *, S< sizeof(U().foo()) > * = 0); 
 
    static int finder (int *); 
}; 
 
int t = sizeof( G<1>::finder( (int*)0 ) ); 
--------------------- 
We ICE on this: 
g/x> /home/bangerth/bin/gcc-3.4-pre/bin/c++ -c x.cc 
x.cc: In instantiation of `G<1>': 
x.cc:10:   instantiated from here 
x.cc:5: internal compiler error: Segmentation fault 
Please submit a full bug report, 
with preprocessed source if appropriate. 
See <URL:http://gcc.gnu.org/bugs.html> for instructions. 
 
 
I wonder if this is somehow related to the fact that we 
(spuriously) don't accept this code (the same as above, 
just that G isn't a template: 
------------------- 
template <int> struct S {}; 
 
struct G { 
    template <typename U> 
    static int finder(U *, S< sizeof(U().foo()) > * = 0); 
 
    static int finder (int *); 
}; 
 
int t = sizeof( G::finder( (int*)0 ) ); 
-------------------- 
 
g/x> /home/bangerth/bin/gcc-3.4-pre/bin/c++ -c x.cc 
x.cc:10: error: request for member `foo' in `0', which is of non-class type 
`int' 
 
This should be just a SFINAE. 
 
W. 
Comment 6 gianni 2004-05-17 03:48:42 UTC
I get this error when removing the templates:

xx6.cpp:43: sorry, unimplemented: call_expr cannot be mangled due to a defect in
the C++ ABI


------------------------------
typedef char MPT_False;
typedef int MPT_True;

template <unsigned w_siz>
struct MPT_IntToType
{
    typedef char    type[ 1 ];
};

struct B
{
    int Function();
};

struct DerivedClass_B : B
{
};

struct FinderM
{

    template <typename w_T>
    static MPT_True finder(
        const w_T *,
        typename MPT_IntToType<
            sizeof(static_cast<w_T *>(0)->Function())
        >::type * = 0
    );

    static MPT_False finder( const B * );

};

bool  value = 
    sizeof( FinderM::finder( static_cast<DerivedClass_B *>(0) ) ) == sizeof(
MPT_True );


------------------------------
Comment 7 gianni 2004-05-17 06:26:04 UTC
I don't know if this is related to this bug but I think this code is also not
correctly parsed by gcc.  Again comeau compiles this fine and MSVC ++ gets all
confused about not being able to deduce func in a similar way to gcc.


typedef char MPT_False;
typedef int MPT_True;


template <unsigned int w_siz>
struct MPT_IntToType
{
    typedef char    type;
};

template <typename T1, typename T2>
int func( T2 ( T1::* )() );

template <typename w_D>
struct MPT_Finder_Member
{

    template <typename w_T>
    static MPT_True finder(
        const w_T *,
        typename MPT_IntToType<
            sizeof( func( & w_T::Function ) )
        >::type * = 0
    );
        
    static MPT_False finder( const w_D * );

};

template <typename w_D >
struct MPT_ContainsFuncMember
{
    struct DerivedClass : w_D
    {
    };

    typedef DerivedClass  * DerivedClassp;

    enum {
        value = (
            sizeof( MPT_Finder_Member<w_D>::finder( DerivedClassp() ) )
            == sizeof( MPT_True )
        )
    };
    
};


struct A
{
};

struct B
{
    int Function();
};

// this works find so func<T1,T2> can be deduced
int x = sizeof( func( &B::Function ) );
int y = MPT_ContainsFuncMember<A>::value;
int z = MPT_ContainsFuncMember<B>::value;

Comment 8 Giovanni Bajo 2004-05-18 02:15:17 UTC
Created attachment 6326 [details]
Patch for the ICE

The ICE is easily fixed, with this patch. Anybody has a little time to regtest
this (make check-c++ is enough)?

Anyway, this patch just makes the two testcases in comment #5 behave the same:
we still have a rejects-legal which is the relevant problem here.
Comment 9 Andrew Pinski 2005-01-06 02:01:09 UTC
(In reply to comment #5)
> Here is a yet simpler example: 
We reject this now (and not ICE).

>  I wonder if this is somehow related to the fact that we 
> (spuriously) don't accept this code (the same as above, 
And we reject this still.
Comment 10 Andrew Pinski 2009-04-16 16:35:28 UTC
Fixed at least on the trunk.