diff mbox

[C++] Fix PR80294 -- Segfault in constexpr.c (reduced_constant_expression_p)

Message ID 20170404095452.GA2549@x4
State New
Headers show

Commit Message

Markus Trippelsdorf April 4, 2017, 9:54 a.m. UTC
As the testcase shows, elt can become a NULL tree during
FOR_EACH_CONSTRUCTOR_VALUE. So guard against this possibility before
calling reduced_constant_expression_p() recursively.

Tested on ppc64le.
OK for trunk?

	PR c++/80294
	* constexpr.c (reduced_constant_expression_p): Guard against NULL
	tree before recursing.
diff mbox

Patch

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 3ca356071810..9ee794d5bf37 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -1716,7 +1716,7 @@  reduced_constant_expression_p (tree t)
       /* And we need to handle PTRMEM_CST wrapped in a CONSTRUCTOR.  */
       tree elt; unsigned HOST_WIDE_INT idx;
       FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (t), idx, elt)
-	if (!reduced_constant_expression_p (elt))
+	if (elt && !reduced_constant_expression_p (elt))
 	  return false;
       return true;
 
diff --git a/gcc/testsuite/g++.dg/torture/pr80294.C b/gcc/testsuite/g++.dg/torture/pr80294.C
new file mode 100644
index 000000000000..859a10ba3e31
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/pr80294.C
@@ -0,0 +1,167 @@ 
+// { dg-do compile }
+
+namespace std {
+typedef long unsigned size_t;
+template <typename _Tp> struct integral_constant {
+  static constexpr _Tp value = 0;
+};
+template <unsigned long, typename> struct tuple_element;
+template <typename _Tp, _Tp> struct integer_sequence;
+} // namespace std
+namespace meta {
+using std::integer_sequence;
+template <typename...> struct list;
+template <template <typename...> class, typename...> struct defer;
+template <typename T> using _t = typename T::type;
+template <int> using size_t = std::integral_constant<int>;
+namespace detail {
+enum indices_strategy_ { recurse };
+constexpr indices_strategy_ strategy_(std::size_t, std::size_t) {
+  return recurse;
+}
+template <std::size_t, typename State, indices_strategy_> struct make_indices_ {
+  using type = State;
+};
+} // namespace detail
+template <long... Is>
+using index_sequence = integer_sequence<unsigned long, Is...>;
+template <std::size_t>
+using make_index_sequence =
+    _t<detail::make_indices_<0, index_sequence<0>, detail::strategy_(0, 0)>>;
+template <typename F, typename... Args>
+using invoke = typename F::template invoke<Args...>;
+namespace lazy {
+template <typename F, typename... Args>
+using invoke = defer<invoke, F, Args...>;
+}
+template <typename> struct id { using type = int; };
+namespace detail {
+struct defer_if_ {
+  template <template <typename...> class C, typename... Ts> struct result {
+    using type = C<Ts...>;
+  };
+  template <template <typename...> class C, typename... Ts>
+  result<C, Ts...> try_();
+};
+template <template <typename...> class C, typename... Ts>
+using defer_ = decltype(defer_if_{}.try_<C, Ts...>());
+} // namespace detail
+template <template <typename...> class C, typename... Ts>
+struct defer : detail::defer_<C, Ts...> {};
+template <template <typename...> class C> struct quote {
+  template <typename... Ts> using invoke = _t<detail::defer_<C, Ts...>>;
+};
+template <template <typename> class> using quote_trait = int;
+template <typename F, typename... Ts> struct bind_front {
+  template <typename... Us> using invoke = invoke<F, Ts..., Us...>;
+};
+namespace extension {
+template <typename, typename> struct apply;
+template <typename F, typename Ret, typename... Args>
+struct apply<F, Ret(Args...)> : lazy::invoke<F, Ret, Args...> {};
+} // namespace extension
+template <typename C, typename List>
+using apply = _t<extension::apply<C, List>>;
+template <typename, typename Q = quote<list>> using curry = Q;
+template <typename F> using uncurry = bind_front<quote<apply>, F>;
+namespace detail {
+template <typename T, int> using first_ = T;
+template <typename, typename> struct repeat_n_c_;
+template <typename T, unsigned long... Is>
+struct repeat_n_c_<T, index_sequence<Is...>> {
+  using type = list<first_<T, Is>...>;
+};
+} // namespace detail
+template <int, typename T>
+using repeat_n_c = _t<detail::repeat_n_c_<T, make_index_sequence<0>>>;
+template <typename N, typename T> using repeat_n = repeat_n_c<N::value, T>;
+namespace detail {
+template <typename> struct at_impl_;
+template <typename... VoidPtrs> struct at_impl_<list<VoidPtrs...>> {
+  template <typename T> static T eval(VoidPtrs..., T *);
+};
+template <typename, typename> struct at_;
+template <typename... Ts, typename N>
+struct at_<list<Ts...>, N> : decltype(at_impl_<repeat_n<N, void *>>::eval(
+                                 static_cast<id<Ts> *>(0)...)) {};
+} // namespace detail
+template <typename List, typename N> using at = _t<detail::at_<List, N>>;
+template <typename List, int> using at_c = at<List, size_t<0>>;
+namespace detail {
+template <typename> struct front_;
+template <typename Head, typename... List> struct front_<list<Head, List...>> {
+  using type = Head;
+};
+} // namespace detail
+template <typename List> using front = _t<detail::front_<List>>;
+namespace detail {
+template <typename> struct back_;
+template <typename Head, typename... List> struct back_<list<Head, List...>> {
+  using type = at_c<list<Head, List...>, sizeof...(List)>;
+};
+} // namespace detail
+template <typename List> using back = _t<detail::back_<List>>;
+namespace detail {
+template <typename Sequence>
+struct as_list_ : lazy::invoke<uncurry<curry<quote_trait<id>>>, Sequence> {};
+} // namespace detail
+template <typename Sequence> using as_list = _t<detail::as_list_<Sequence>>;
+} // namespace meta
+namespace detail {
+template <typename T> using tag_spec = meta::front<meta::as_list<T>>;
+template <typename T> using tag_elem = meta::back<meta::as_list<T>>;
+template <std::size_t, typename T> constexpr auto adl_get(T) {}
+} // namespace detail
+template <typename, unsigned long, typename...> struct chain {
+  using type = int;
+};
+template <typename Base, unsigned long I, typename First, typename... Rest>
+struct chain<Base, I, First, Rest...> {
+  using type =
+      typename First::template getter<Base, 0,
+                                      meta::_t<chain<Base, 0, Rest...>>>;
+};
+template <typename Base, typename... Tags>
+struct Trans_NS_tagged_detail_tagged : meta::_t<chain<Base, 0, Tags...>> {};
+namespace compressed_tuple_detail {
+template <typename, typename> struct compressed_tuple_;
+template <typename... Ts>
+using compressed_tuple =
+    compressed_tuple_<meta::list<Ts...>,
+                      meta::make_index_sequence<sizeof...(Ts)>>;
+} // namespace compressed_tuple_detail
+using compressed_tuple_detail::compressed_tuple;
+template <typename... Ts>
+using tagged_compressed_tuple =
+    Trans_NS_tagged_detail_tagged<compressed_tuple<detail::tag_elem<Ts>...>,
+                                  detail::tag_spec<Ts>...>;
+struct first {
+  template <typename, int, typename Next> struct getter : Next {};
+};
+struct second {
+  template <typename Untagged, int, typename> struct getter {
+    constexpr meta::_t<std::tuple_element<0, Untagged>> second() {
+      detail::adl_get<0>(*this);
+    }
+  };
+};
+template <typename Second>
+struct compressed_pair : tagged_compressed_tuple<first(int), second(Second)> {};
+namespace std {
+template <size_t I, typename... Ts, size_t... Is>
+struct tuple_element<I, compressed_tuple_detail::compressed_tuple_<
+                            meta::list<Ts...>, meta::index_sequence<Is...>>> {
+  using type = meta::at_c<meta::list<Ts...>, 0>;
+};
+} // namespace std
+template <typename T, typename P, typename E = int>
+struct Constrained : compressed_pair<int> {
+  int value_;
+  constexpr T enforce_constraint(T) { executor(); }
+  constexpr Constrained(T) : Constrained(0, 0, 0) {}
+  template <typename T_>
+  constexpr Constrained(T_, P, E) : value_{enforce_constraint(0)} {}
+  constexpr E executor() { second(); }
+};
+using Positive = Constrained<int, int>;
+Positive n = 0;