On 06/10/2015 09:01 AM, Jason Merrill wrote:
My change to rationalize the *_constant_value functions broke this testcase, because we were no longer replacing the reference to the array with its constant value. Fixed by using maybe_constant_value instead.
We need to deal with this properly in tsubst_copy, as well. Fixed by calling process_outer_var_ref.
Tested x86_64-pc-linux-gnu, applying to trunk and 5.
commit a7a168ac826a3adffd8cc7c7db5061451f638fd0 Author: Jason Merrill <ja...@redhat.com> Date: Mon Jun 15 15:57:34 2015 -0400 PR c++/66387 * pt.c (tsubst_copy) [VAR_DECL]: Use process_outer_var_ref. diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index ea8c8b6..9236311 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -13071,10 +13071,8 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl) if (TREE_STATIC (r)) rest_of_decl_compilation (r, toplevel_bindings_p (), at_eof); - else if (decl_constant_var_p (r)) - /* A use of a local constant decays to its value. - FIXME update for core DR 696. */ - r = scalar_constant_value (r); + else + r = process_outer_var_ref (r, complain); } } /* Remember this for subsequent uses. */ diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 59ec9047..a1519b9 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -3103,6 +3103,8 @@ process_outer_var_ref (tree decl, tsubst_flags_t complain) if (cp_unevaluated_operand) /* It's not a use (3.2) if we're in an unevaluated context. */ return decl; + if (decl == error_mark_node) + return decl; tree context = DECL_CONTEXT (decl); tree containing_function = current_function_decl; diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-ice2.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-ice2.C new file mode 100644 index 0000000..57e0ad2 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-ice2.C @@ -0,0 +1,123 @@ +// PR c++/66387 +// { dg-do compile { target c++14 } } + +namespace boost { +namespace hana { +namespace detail { +namespace std { +using size_t = decltype(0); +} +} +namespace ic_detail { +template <typename T, T> struct _with_index { + template <typename F> constexpr void operator()(F &&) const; +}; +template <typename T, T v> struct _times { _with_index<T, v> with_index; }; +} +template <typename T, T v> struct _integral_constant { + using value_type = T; + operator value_type() const; + ic_detail::_times<T, v> times; +}; +template <detail::std::size_t i> +constexpr _integral_constant<detail::std::size_t, i> size_t{}; +template <typename, typename = void> struct datatype; +} +} +namespace std { +typedef int size_t; +inline namespace __cxx11 {} +} +namespace boost { +namespace hana { +template <bool> struct when; +template <typename, typename, typename> struct to_impl; +template <typename T, typename> struct datatype : datatype<T, when<true>> {}; +template <typename T, bool condition> struct datatype<T, when<condition>> { + using type = typename T::hana::datatype; +}; +template <typename> struct _models; +template <typename To, typename From> + struct to_impl < To, + From, when < _models<From> { +} >> ; +namespace detail { +namespace std { +template <typename T, T> struct integer_sequence; +template <size_t... n> using index_sequence = integer_sequence<size_t, n...>; +namespace int_seq_detail { +template <size_t> struct make_index_sequence { + using type = index_sequence<0>; +}; +template <typename, typename> struct cast_to; +template <typename T, typename U, U... u> +struct cast_to<T, integer_sequence<U, u...>> { + using type = integer_sequence<T, u...>; +}; +} +template <typename T, T> +using make_integer_sequence = typename int_seq_detail::cast_to< + T, int_seq_detail::make_index_sequence<1>::type>::type; +} +} +namespace ic_detail { +template <typename T, T N, typename = detail::std::make_integer_sequence<T, N>> +struct go; +template <typename T, T N, T... i> +struct go<T, N, detail::std::integer_sequence<T, i...>> { + using swallow = T; + template <typename F> static void with_index(F f) { + swallow{(f(_integral_constant<T, i>{}), 0)...}; + } +}; +template <typename T, T v> +template <typename F> +constexpr void _with_index<T, v>::operator()(F &&f) const { + go<T, 0>::with_index(f); +} +} +} +} +namespace std { +template <typename> class allocator; +template <class> struct char_traits; +template <typename _CharT, typename = char_traits<_CharT>> class basic_ostream; +namespace __cxx11 { +template <typename _CharT, typename = char_traits<_CharT>, + typename = allocator<_CharT>> +class basic_stringstream; +} +typedef basic_ostream<char> ostream; +typedef basic_stringstream<char> stringstream; +template <typename, typename> class basic_ostream {}; +template <typename _CharT, typename> +class basic_iostream : public basic_ostream<_CharT> {}; +namespace __cxx11 { +template <typename _CharT, typename _Traits, typename> +class basic_stringstream : public basic_iostream<_CharT, _Traits> {}; +} +} +namespace hana = boost::hana; +template <typename> struct print_impl; +template <typename X> void print(std::ostream os, X x) { + using Tag = typename hana::datatype<X>::type; + print_impl<Tag>::apply(os, x); +} +struct Vector; +template <typename, typename> struct vector2 { + struct hana { + using datatype = Vector; + }; + static constexpr std::size_t size = 0; +}; +template <> struct print_impl<Vector> { + template <typename vectorN> static void apply(std::ostream, vectorN) { + constexpr auto N = hana::size_t<vectorN::size>; + N.times.with_index([&](auto) { N - hana::size_t<1>; }); + } +}; +int main() { + std::stringstream ss; + vector2<int, char> v2; + print(ss, v2); +}