diff options
author | Jason Merrill <jason@redhat.com> | 2024-07-26 16:53:03 -0400 |
---|---|---|
committer | Thomas Koenig <tkoenig@gcc.gnu.org> | 2024-07-28 19:06:02 +0200 |
commit | b300fd3985cc1435ecea30d18d00bfab8022d091 (patch) | |
tree | 6c31e6191019ffac9ac30e645b51aa522945a841 /gcc | |
parent | 557373c0cd6c0d6b4a1e46dc7a53d929b60b3c9b (diff) | |
download | gcc-b300fd3985cc1435ecea30d18d00bfab8022d091.zip gcc-b300fd3985cc1435ecea30d18d00bfab8022d091.tar.gz gcc-b300fd3985cc1435ecea30d18d00bfab8022d091.tar.bz2 |
c++: ICE with concept, local class, and lambda [PR115561]
Here when we want to synthesize methods for foo()::B maybe_push_to_top_level
calls push_function_context, which sets cfun to a dummy value; later
finish_call_expr tries to set something in
cp_function_chain (i.e. cfun->language), which isn't set. Many places in
the compiler check cfun && cp_function_chain to avoid this problem; here we
also want to check !cp_unevaluated_operand, like set_flags_from_callee does.
PR c++/115561
gcc/cp/ChangeLog:
* semantics.cc (finish_call_expr): Check cp_unevaluated_operand.
gcc/testsuite/ChangeLog:
* g++.dg/cpp2a/concepts-lambda21.C: New test.
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/semantics.cc | 2 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/concepts-lambda21.C | 69 |
2 files changed, 70 insertions, 1 deletions
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index 0f122b8..a9abf32 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -2968,7 +2968,7 @@ finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual, -Wredundant-move warning. */ suppress_warning (result, OPT_Wpessimizing_move); - if (cfun) + if (cfun && cp_function_chain && !cp_unevaluated_operand) { bool abnormal = true; for (lkp_iterator iter (maybe_get_fns (fn)); iter; ++iter) diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-lambda21.C b/gcc/testsuite/g++.dg/cpp2a/concepts-lambda21.C new file mode 100644 index 0000000..8d701cd --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-lambda21.C @@ -0,0 +1,69 @@ +// PR c++/115561 +// { dg-do compile { target c++20 } } + +template<typename _Tp> +auto declval() noexcept -> _Tp&&; + +template<bool, typename _Tp = void> +struct enable_if +{ }; + +template<typename _Tp> +struct enable_if<true, _Tp> +{ using type = _Tp; }; + +template<bool _Cond, typename _Tp = void> +using enable_if_t = typename enable_if<_Cond, _Tp>::type; + +template<typename _Tp> +struct is_void +{ static constexpr bool value = false; }; + +template<typename Fun, typename... Args> +using invoke_result_t = + decltype(declval<Fun>()(declval<Args>()...)); + +template<typename R> +using iter_reference_t = decltype(*declval<R &>()); + +struct iter_move_fn +{ + template<typename I> + constexpr + auto operator() (I &&i) -> void; +} iter_move; + +template<typename I> +using iter_rvalue_reference_t = decltype(iter_move(declval<I &>())); + +template<class, class> +concept same_as = true; + +template<typename I> +concept readable_concept_ = + same_as<iter_rvalue_reference_t<I const>, iter_rvalue_reference_t<I>>; + +template<typename I> +concept indirectly_readable = + readable_concept_<enable_if_t<true, I>>; + +template<typename Fun, typename I> +using indirect_result_t = + enable_if_t<indirectly_readable<I>, + invoke_result_t<Fun, iter_reference_t<I>>>; + +template<typename I, typename Fun> +concept transformable = + (!is_void<indirect_result_t<Fun &, I>>::value); + +template<typename I, typename Fun > + requires transformable<I, Fun> +constexpr void transform(I, Fun) +{ +} + +void foo() +{ + struct B {}; + (void) transform((B*)nullptr, [](B) {return 0; }); +} |