Bug 69851 - [6 Regression] ICE: in assign_temp, at function.c:961
Summary: [6 Regression] ICE: in assign_temp, at function.c:961
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 6.0
: P1 normal
Target Milestone: 6.0
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-02-17 08:26 UTC by Markus Trippelsdorf
Modified: 2016-02-21 10:43 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2016-02-17 00:00:00


Attachments
gcc6-pr69851.patch (1.06 KB, patch)
2016-02-19 10:05 UTC, Jakub Jelinek
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Markus Trippelsdorf 2016-02-17 08:26:51 UTC
markus@x4 tmp % cat subprocess.ii
namespace std {
template <typename _Tp, _Tp> struct integral_constant {
  static constexpr _Tp value = 0;
};
template <typename> struct conditional;
template <typename...> struct __or_;
template <typename _B1, typename _B2>
struct __or_<_B1, _B2> : conditional<_B2>::type {};
template <typename> struct is_enum : integral_constant<bool, __is_enum(int)> {};
template <typename> struct remove_reference;
template <typename _Tp> struct remove_reference<_Tp &> { typedef _Tp type; };
template <typename _Tp> struct decay {
  typedef typename remove_reference<_Tp>::type type;
};
template <typename> struct conditional { typedef is_enum<char> type; };
template <typename _Head> struct _Head_base { _Head _M_head_impl; };
template <unsigned long, typename...> struct _Tuple_impl;
template <unsigned long _Idx, typename _Head, typename... _Tail>
struct _Tuple_impl<_Idx, _Head, _Tail...> : _Tuple_impl<1, _Tail...>,
                                            _Head_base<_Head> {
  _Tuple_impl(_Tuple_impl &) = default;
  _Tuple_impl(_Tuple_impl &&__in) : _Tuple_impl(__in) {}
};
template <unsigned long _Idx, typename _Head>
struct _Tuple_impl<_Idx, _Head> {};
template <typename... _Elements> struct tuple : _Tuple_impl<0, _Elements...> {};
template <typename> struct _Bind;
template <typename _Functor, typename... _Bound_args>
struct _Bind<_Functor(_Bound_args...)> {
  tuple<_Bound_args...> _M_bound_args;
};
template <typename _Tp, typename _Tp2 = typename decay<_Tp>::type>
using __is_socketlike = __or_<integral_constant<bool, false>, is_enum<_Tp2>>;
template <int, typename... _BoundArgs> struct _Bind_helper {
  typedef _Bind<int(typename decay<_BoundArgs>::type...)> type;
};
template <typename _Func, typename... _BoundArgs>
typename _Bind_helper<__is_socketlike<_Func>::value, _BoundArgs...>::type
bind(_Func &&, _BoundArgs &&...);
struct _Any_data {
  template <typename _Tp> _Tp _M_access() const;
};
enum _Manager_operation {};
template <typename> struct function;
struct _Function_base {
  template <typename _Functor> struct _Base_manager {
    static bool _M_manager(_Any_data &, const _Any_data &__source,
                           _Manager_operation) {
      _Functor(*__source._M_access<_Functor *>());
    }
  };
  typedef bool (*_Manager_type)(_Any_data &, const _Any_data &,
                                _Manager_operation);
  _Manager_type _M_manager;
};
template <typename, typename> struct _Function_handler;
template <typename _Res, typename _Functor, typename... _ArgTypes>
struct _Function_handler<_Res(_ArgTypes...), _Functor>
    : _Function_base::_Base_manager<_Functor> {};
template <typename _Res, typename... _ArgTypes>
struct function<_Res(_ArgTypes...)> : _Function_base {
  template <typename, typename> using _Requires = int;
  template <typename _Functor, typename = _Requires<int, void>,
            typename = _Requires<int, void>>
  function(_Functor);
  _Res operator()(_ArgTypes...);
};
template <typename _Res, typename... _ArgTypes>
template <typename _Functor, typename, typename>
function<_Res(_ArgTypes...)>::function(_Functor) {
  _M_manager = _Function_handler<_Res(), _Functor>::_M_manager;
}
}
struct Option {
  Option(Option &);
};
using std::bind;
using std::function;
struct Subprocess {};
using InputFileDescriptors = Subprocess;
using OutputFileDescriptors = int;
void defaultClone(Option setup) {
  InputFileDescriptors stdinfds;
  OutputFileDescriptors stdoutfds, envp;
  function<int(function<int()>)> clone = 0;
  int pipes = clone(bind(envp, setup, stdinfds, stdoutfds, pipes));
}

markus@x4 tmp % g++ -c subprocess.ii
subprocess.ii: In copy constructor ‘std::_Tuple_impl<_Idx, _Head, _Tail ...>::_Tuple_impl(std::_Tuple_impl<_Idx, _Head, _Tail ...>&) [with long unsigned int _Idx = 0ul; _Head = Option; _Tail = {Subprocess, int, int}]’:
subprocess.ii:21:3: internal compiler error: in assign_temp, at function.c:961
   _Tuple_impl(_Tuple_impl &) = default;
   ^~~~~~~~~~~
0xa51353 assign_temp(tree_node*, int, int)
        ../../gcc/gcc/function.c:961
0x9e9e25 expand_expr_real_1(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
        ../../gcc/gcc/expr.c:10408
0x9f9048 expand_normal
        ../../gcc/gcc/expr.h:262
0x9f9048 store_field
        ../../gcc/gcc/expr.c:6679
0x9f4c7d expand_assignment(tree_node*, tree_node*, bool)
        ../../gcc/gcc/expr.c:5021
0x8e79de expand_gimple_stmt_1
        ../../gcc/gcc/cfgexpand.c:3606
0x8e79de expand_gimple_stmt
        ../../gcc/gcc/cfgexpand.c:3702
0x8e9e88 expand_gimple_basic_block
        ../../gcc/gcc/cfgexpand.c:5708
0x8efe96 execute
        ../../gcc/gcc/cfgexpand.c:6323
Comment 1 Jakub Jelinek 2016-02-17 08:53:36 UTC
Reduced testcase:
template <typename T>
struct A { T a; };
template <unsigned long, typename...>
struct B;
template <unsigned long N, typename T, typename... U>
struct B<N, T, U...> : B<1, U...>, A<T>
{
  B (B &) = default;
  B (B &&__in) : B(__in) {}
};
template <unsigned long N, typename T>
struct B<N, T> {};
struct C { C (C &); };
struct D {};

void
foo (B<0, C, D, int, int> a)
{
  B<0, C, D, int, int> b (a);
}
Comment 2 Jakub Jelinek 2016-02-17 09:09:41 UTC
Started with r228704, with ICEs like
pr69851.C: In copy constructor ‘B<N, T, U ...>::B(B<N, T, U ...>&) [with long unsigned int N = 0ul; T = C; U = {D, int, int}]’:
pr69851.C:8:3: internal compiler error: in store_field, at expr.c:6637
   B (B &) = default;
   ^
0xbc7f2a store_field
	../../gcc/expr.c:6637
0xbc1947 expand_assignment(tree_node*, tree_node*, bool)
	../../gcc/expr.c:5017
and in r232167 that changed to the current
pr69851.C: In copy constructor ‘B<N, T, U ...>::B(B<N, T, U ...>&) [with long unsigned int N = 0ul; T = C; U = {D, int, int}]’:
pr69851.C:8:3: internal compiler error: in assign_temp, at function.c:961
   B (B &) = default;
   ^

0xc80dc7 assign_temp(tree_node*, int, int)
	../../gcc/function.c:961
0xc263d2 expand_expr_real_1(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
	../../gcc/expr.c:10411
0xc1bc42 expand_expr_real(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
	../../gcc/expr.c:7946
0xc03c84 expand_normal
	../../gcc/expr.h:262
0xc17a0c store_field
	../../gcc/expr.c:6678
0xc11114 expand_assignment(tree_node*, tree_node*, bool)
	../../gcc/expr.c:5020
In any case, this is on the
  this_2(D)->D.2344 = _5(D)->D.2344;
assignment where both the lhs and rhs are TREE_ADDRESSABLE typed fields 5 bytes long (i.e. without padding), while the actual type is 8 bytes long (with padding).
Do we want a memcpy/memmove like assignment in this case, something else?
As the assignment is without padding, during expansion we chose to store_bit_field it, but that means the rhs is evaluated using expand_normal, i.e. with NULL target, and that wants to create a temporary, because the type of the COMPONENT_REF is the type including padding, but the FIELD_DECL without padding.
Comment 3 Jason Merrill 2016-02-17 15:19:52 UTC
(In reply to Jakub Jelinek from comment #2)
> Do we want a memcpy/memmove like assignment in this case, something else?

memcpy, yes.  Why isn't that the default for whole bytes in memory, anyway?
Comment 4 Jakub Jelinek 2016-02-17 15:24:12 UTC
(In reply to Jason Merrill from comment #3)
> (In reply to Jakub Jelinek from comment #2)
> > Do we want a memcpy/memmove like assignment in this case, something else?
> 
> memcpy, yes.  Why isn't that the default for whole bytes in memory, anyway?

No idea.  I guess at least for GCC 6 it might be safest to just hack up expand_assignment to expand TREE_ADDRESSABLE assignment that way (just ones with weirdo sizes, which would otherwise go into store_field, or all?).
Comment 5 Jakub Jelinek 2016-02-19 10:05:15 UTC
Created attachment 37738 [details]
gcc6-pr69851.patch

Untested fix.
Comment 6 Jakub Jelinek 2016-02-19 19:12:29 UTC
Author: jakub
Date: Fri Feb 19 19:11:58 2016
New Revision: 233566

URL: https://gcc.gnu.org/viewcvs?rev=233566&root=gcc&view=rev
Log:
	PR c++/69851
	* expr.c (store_field): Don't use bit-field path if exp is
	COMPONENT_REF with TREE_ADDRESSABLE type, where TYPE_SIZE is
	different from bitsize, but DECL_SIZE of FIELD_DECL is bitsize
	and the assignment can be performed by bitwise copy.  Formatting
	fix.

	* g++.dg/torture/pr69851.C: New test.

Added:
    trunk/gcc/testsuite/g++.dg/torture/pr69851.C
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/expr.c
    trunk/gcc/testsuite/ChangeLog
Comment 7 Jakub Jelinek 2016-02-19 19:18:09 UTC
Fixed.
Comment 8 Benjamin Bannier 2016-02-21 10:43:48 UTC
Thanks for the fast turn-around, that patch fixed the original issue like expected. I encountered another similar issue in the same code base which still causes an ICE, see 69889.