http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46003

--- Comment #3 from Yufeng Zhang <yufeng.zhang at arm dot com> 2011-02-10 
17:36:12 UTC ---
The repro can be reduced to:

------------ CODE ------------
struct A
{
  A(int);
};

template<int> void foo(A& x) 
{ 0 ? x : 0; }

------------ CUT ------------

The assertion failure occurs in cp/tree.c:build_target_expr(tree decl, tree
value), which is expecting the TREE_TYPE of the VALUE to meet one of the
following conditions:

1. is VOID_TYPE
2. is the same as the type of the DECL, which is to be initialized with the
VALUE
3. passes useless_type_conversion_p()

The assertions fails when the TREE_TYPE of the VALUE is found to be
POINTER_TYPE, while the DECL has VOID_TYPE.

Note that the assertion does not fail in the x86-targeted (or any of many other
targets targeted) compiler, because of the difference in the ARM C++ ABI on
constructor return values. The ARM C++ ABI requires C1 and C2 constructors to
return this (instead of being void functions).

During the parsing of an conditional expression, the C++ front-end needs to
determine the expression type, especially when the 2nd and 3rd operands are of
different types. For 0 ? x : 0 in the repro code, it seems that ctors
(constructors) of A (including the user defined ctor and the compiler generated
copy ctor) are invoked to convert the type of the 3rd operand from INTEGER_TYPE
to the RECORD_TYPE of A. This is part of the process in order to match the type
of the 3rd operand to that of the 2nd one.

When the assertion happens, the VALUE is the following like tree node:

  CALL_EXPR (pointer_type to struct A)
    COMPONENT_REF  (pointer_type to method_type of a method in A)
      INDIRECT_REF (record_type of A)
        INTEGER_CST 0 (pointer_type to A)
        BASELINK
          OVERLOAD
            A* A::A(const A&)
            A* A::A(int)
    TARGET_EXPR (record_type of A)
      VAR_DECL
      AGGR_INIT_EXPR (void_type)
        op0: (A*)0
        op1: (int)0
        func: ADDR_EXPR (method_type)
                FUNCTION_DECL __comp_ctor A* A::A(int)

Basically what the tree is doing is:

  ((A)0).A((A*)0->A(0))

i.e. construct a temporary object of A by explicitly calling the user-defined
ctor, and pass it to the copy ctor of A to construct another temporary object
of A, but this time replying on the overload resolution to get the copy ctor
selected.

Leave aside the kids nodes of the CALL_EXPR tree node, and focus on its
TREE_TYPE, which is the return type of the routine to be called. Because the
routine is a ctor and the compiler targets ARM, it has the TREE_TYPE of
POINTER_TYPE (conforming to the ABI). When the CALL_EXPR tree node is passed to
build_target_expr as the VALUE to initialize the DECL, which sensibly has the
type of RECORD_TYPE (of A), the compiler complains: mismatching types!! You
cannot use a tree node of POINTER_TYPE to initialize a RECORD_TYPE tree node!

In x86-targeted GCC, however, such a CALL_EXPR tree node has VOID_TYPE as a
ctor returns void as specified by the generic C++ ABI, and thus the assertion
failure will not happen.

Reply via email to