[gcc r14-10890] c++: reference variable as default targ [PR101463]
https://gcc.gnu.org/g:124f2f62e01c6f110279608ad09e0f1d378e4899 commit r14-10890-g124f2f62e01c6f110279608ad09e0f1d378e4899 Author: Patrick Palka Date: Tue Nov 5 15:18:26 2024 -0500 c++: reference variable as default targ [PR101463] Here during default template argument substitution we wrongly consider the (substituted) default arguments v and vt as value-dependent which ultimately leads to deduction failure for the calls. The bogus value_dependent_expression_p result aside, I noticed type_unification_real during default targ substitution keeps track of whether all previous targs are known and non-dependent, as is the case for these calls. And in such cases it should be safe to avoid checking dependence of the substituted default targ and just assume it's not. This patch implements this optimization for GCC 14, which lets us accept both testcases by sidestepping the value_dependent_expression_p issue altogether. (Note that for GCC 15 we fixed this differently, see r15-3038-g5348e3cb9bc99d.) PR c++/101463 gcc/cp/ChangeLog: * pt.cc (type_unification_real): Avoid checking dependence of a substituted default template argument if we can assume it's non-dependent. gcc/testsuite/ChangeLog: * g++.dg/cpp1z/nontype6.C: New test. * g++.dg/cpp1z/nontype6a.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/pt.cc | 4 +++- gcc/testsuite/g++.dg/cpp1z/nontype6.C | 24 gcc/testsuite/g++.dg/cpp1z/nontype6a.C | 25 + 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 818d5b65edce..4f83426fb56c 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -23651,12 +23651,14 @@ type_unification_real (tree tparms, /* We replaced all the tparms, substitute again out of template context. */ substed = NULL_TREE; + else + processing_template_decl = 1; } if (!substed) substed = tsubst_template_arg (arg, full_targs, complain, NULL_TREE); - if (!uses_template_parms (substed)) + if (!processing_template_decl || !uses_template_parms (substed)) arg = convert_template_argument (parm, substed, full_targs, complain, i, NULL_TREE); else if (saw_undeduced == 1) diff --git a/gcc/testsuite/g++.dg/cpp1z/nontype6.C b/gcc/testsuite/g++.dg/cpp1z/nontype6.C new file mode 100644 index ..06cd234cc61a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/nontype6.C @@ -0,0 +1,24 @@ +// PR c++/101463 +// { dg-do compile { target c++17 } } + +int a; + +int& v = a; + +template +void f(int) { } + +template +void g(T) { } + +template +int& vt = a; + +template> +void h(T) { } + +int main() { + f(0); + g(0); + h(0); +} diff --git a/gcc/testsuite/g++.dg/cpp1z/nontype6a.C b/gcc/testsuite/g++.dg/cpp1z/nontype6a.C new file mode 100644 index ..8bc40a0505c2 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/nontype6a.C @@ -0,0 +1,25 @@ +// PR c++/101463 +// A version of nontype6.C where v and vt are constexpr. +// { dg-do compile { target c++17 } } + +int a; + +constexpr int& v = a; + +template +void f(int) { } + +template +void g(T) { } + +template +constexpr int& vt = a; + +template> +void h(T) { } + +int main() { + f(0); + g(0); + h(0); +}
[gcc r15-4544] c++: redundant hashing in register_specialization
https://gcc.gnu.org/g:ae614b8a3d7866764bfea6f30605f90268db572b commit r15-4544-gae614b8a3d7866764bfea6f30605f90268db572b Author: Patrick Palka Date: Tue Oct 22 08:01:16 2024 -0400 c++: redundant hashing in register_specialization After r15-4050-g5dad738c1dd164 register_specialization needs to set elt.hash to the (maybe) precomputed hash so that the lookup uses it rather than redundantly computing it from scratch. gcc/cp/ChangeLog: * pt.cc (register_specialization): Set elt.hash. Reviewed-by: Jason Merrill Diff: --- gcc/cp/pt.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 0141c53b617c..b590c32345f6 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -1546,9 +1546,7 @@ register_specialization (tree spec, tree tmpl, tree args, bool is_friend, elt.tmpl = tmpl; elt.args = args; elt.spec = spec; - - if (hash == 0) -hash = spec_hasher::hash (&elt); + elt.hash = hash; spec_entry **slot = decl_specializations->find_slot (&elt, INSERT); if (*slot)
[gcc r14-10820] libstdc++: Implement LWG 3664 changes to ranges::distance
https://gcc.gnu.org/g:f381a217e9b6c8276bb580a22d12445ed7a7dc8c commit r14-10820-gf381a217e9b6c8276bb580a22d12445ed7a7dc8c Author: Patrick Palka Date: Sat Oct 5 13:48:06 2024 -0400 libstdc++: Implement LWG 3664 changes to ranges::distance libstdc++-v3/ChangeLog: * include/bits/ranges_base.h (__distance_fn::operator()): Adjust iterator/sentinel overloads as per LWG 3664. * testsuite/24_iterators/range_operations/distance.cc: Test LWG 3664 example. Reviewed-by: Jonathan Wakely (cherry picked from commit 7c0d1e9f2a2f1d41d9eb755c36c871d92638c4b7) Diff: --- libstdc++-v3/include/bits/ranges_base.h| 14 +++--- .../testsuite/24_iterators/range_operations/distance.cc| 11 +++ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/libstdc++-v3/include/bits/ranges_base.h b/libstdc++-v3/include/bits/ranges_base.h index 23c0b56ff225..67ac8db8b469 100644 --- a/libstdc++-v3/include/bits/ranges_base.h +++ b/libstdc++-v3/include/bits/ranges_base.h @@ -930,7 +930,9 @@ namespace ranges struct __distance_fn final { -template _Sent> +// _GLIBCXX_RESOLVE_LIB_DEFECTS +// 3664. LWG 3392 broke std::ranges::distance(a, a+3) +template _Sent> requires (!sized_sentinel_for<_Sent, _It>) constexpr iter_difference_t<_It> operator()[[nodiscard]](_It __first, _Sent __last) const @@ -944,13 +946,11 @@ namespace ranges return __n; } -template _Sent> +template> _Sent> [[nodiscard]] - constexpr iter_difference_t<_It> - operator()(const _It& __first, const _Sent& __last) const - { - return __last - __first; - } + constexpr iter_difference_t> + operator()(_It&& __first, _Sent __last) const + { return __last - static_cast&>(__first); } template [[nodiscard]] diff --git a/libstdc++-v3/testsuite/24_iterators/range_operations/distance.cc b/libstdc++-v3/testsuite/24_iterators/range_operations/distance.cc index 9a1d0c3efe83..336956936c22 100644 --- a/libstdc++-v3/testsuite/24_iterators/range_operations/distance.cc +++ b/libstdc++-v3/testsuite/24_iterators/range_operations/distance.cc @@ -144,6 +144,16 @@ test05() VERIFY( std::ranges::distance(c4) == 5 ); } +void +test06() +{ + // LWG 3664 - LWG 3392 broke std::ranges::distance(a, a+3) + int a[] = {1, 2, 3}; + VERIFY( std::ranges::distance(a, a+3) == 3 ); + VERIFY( std::ranges::distance(a, a) == 0 ); + VERIFY( std::ranges::distance(a+3, a) == -3 ); +} + int main() { @@ -152,4 +162,5 @@ main() test03(); test04(); test05(); + test06(); }
[gcc r14-10817] libstdc++: Implement P2997R1 changes to the indirect invocability concepts
https://gcc.gnu.org/g:0b2f2a7e126cf8017626793446110aac892b00f6 commit r14-10817-g0b2f2a7e126cf8017626793446110aac892b00f6 Author: Patrick Palka Date: Thu Aug 22 09:24:20 2024 -0400 libstdc++: Implement P2997R1 changes to the indirect invocability concepts This implements the changes of this C++26 paper as a DR against C++20. In passing this patch removes the std/ranges/version_c++23.cc test which is now mostly obsolete after the version.def FTM refactoring, and instead expands the __cpp_lib_ranges checks in another test so that it verifies the exact value of the FTM on a per language version basis. libstdc++-v3/ChangeLog: * include/bits/iterator_concepts.h (indirectly_unary_invocable): Relax as per P2997R1. (indirectly_regular_unary_invocable): Likewise. (indirect_unary_predicate): Likewise. (indirect_binary_predicate): Likewise. (indirect_equivalence_relation): Likewise. (indirect_strict_weak_order): Likewise. * include/bits/version.def (ranges): Update value for C++26. * include/bits/version.h: Regenerate. * testsuite/24_iterators/indirect_callable/p2997r1.cc: New test. * testsuite/std/ranges/version_c++23.cc: Remove. * testsuite/std/ranges/headers/ranges/synopsis.cc: Refine the __cpp_lib_ranges checks. Reviewed-by: Jonathan Wakely (cherry picked from commit 620232426bd83a79c81cd2be6f485834c618e920) Diff: --- libstdc++-v3/include/bits/iterator_concepts.h | 17 ++ libstdc++-v3/include/bits/version.def | 5 ++ libstdc++-v3/include/bits/version.h| 7 ++- .../24_iterators/indirect_callable/p2997r1.cc | 37 .../std/ranges/headers/ranges/synopsis.cc | 6 +- libstdc++-v3/testsuite/std/ranges/version_c++23.cc | 70 -- 6 files changed, 57 insertions(+), 85 deletions(-) diff --git a/libstdc++-v3/include/bits/iterator_concepts.h b/libstdc++-v3/include/bits/iterator_concepts.h index 9306b7bd194c..d849ddc32fc2 100644 --- a/libstdc++-v3/include/bits/iterator_concepts.h +++ b/libstdc++-v3/include/bits/iterator_concepts.h @@ -724,7 +724,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION concept indirectly_unary_invocable = indirectly_readable<_Iter> && copy_constructible<_Fn> && invocable<_Fn&, __indirect_value_t<_Iter>> && invocable<_Fn&, iter_reference_t<_Iter>> - && invocable<_Fn&, iter_common_reference_t<_Iter>> && common_reference_with>, invoke_result_t<_Fn&, iter_reference_t<_Iter>>>; @@ -733,15 +732,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION && copy_constructible<_Fn> && regular_invocable<_Fn&, __indirect_value_t<_Iter>> && regular_invocable<_Fn&, iter_reference_t<_Iter>> - && regular_invocable<_Fn&, iter_common_reference_t<_Iter>> && common_reference_with>, invoke_result_t<_Fn&, iter_reference_t<_Iter>>>; template concept indirect_unary_predicate = indirectly_readable<_Iter> && copy_constructible<_Fn> && predicate<_Fn&, __indirect_value_t<_Iter>> - && predicate<_Fn&, iter_reference_t<_Iter>> - && predicate<_Fn&, iter_common_reference_t<_Iter>>; + && predicate<_Fn&, iter_reference_t<_Iter>>; template concept indirect_binary_predicate @@ -750,9 +747,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION && predicate<_Fn&, __indirect_value_t<_I1>, __indirect_value_t<_I2>> && predicate<_Fn&, __indirect_value_t<_I1>, iter_reference_t<_I2>> && predicate<_Fn&, iter_reference_t<_I1>, __indirect_value_t<_I2>> - && predicate<_Fn&, iter_reference_t<_I1>, iter_reference_t<_I2>> - && predicate<_Fn&, iter_common_reference_t<_I1>, - iter_common_reference_t<_I2>>; + && predicate<_Fn&, iter_reference_t<_I1>, iter_reference_t<_I2>>; template concept indirect_equivalence_relation @@ -762,9 +757,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION && equivalence_relation<_Fn&, __indirect_value_t<_I1>, iter_reference_t<_I2>> && equivalence_relation<_Fn&, iter_reference_t<_I1>, __indirect_value_t<_I2>> && equivalence_relation<_Fn&, iter_reference_t<_I1>, - iter_reference_t<_I2>> - && equivalence_relation<_Fn&, iter_common_reference_t<_I1>, - iter_common_reference_t<_I2>>; + iter_reference_t<_I2>>; template concept indirect_strict_weak_order @@ -773,9 +766,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION && strict_weak_order<_Fn&, __indirect_value_t<_I1>, __indirect_value_t<_I2>> && strict_weak_order<_Fn&, __indirect_value_t<_I1>, iter_reference_t<_I2>> && strict_weak_order<_Fn&, iter_reference_t<_I1>, __indirect_value_t<_I2>> - && strict_weak_order<_Fn&, iter_reference_t<_I1>, iter_reference_t<_I2>> -
[gcc r14-10801] c++: checking ICE w/ constexpr if and lambda as def targ [PR117054]
https://gcc.gnu.org/g:c468a0051a5ff3f91498d955edb8f684d27afe0d commit r14-10801-gc468a0051a5ff3f91498d955edb8f684d27afe0d Author: Patrick Palka Date: Tue Oct 15 13:13:15 2024 -0400 c++: checking ICE w/ constexpr if and lambda as def targ [PR117054] Here we're tripping over the assert in extract_locals_r which enforces that an extra-args tree appearing inside another extra-args tree doesn't actually have extra args. This invariant doesn't always hold for lambdas (which recently gained the extra-args mechanism) but that should be harmless since cp_walk_subtrees doesn't walk LAMBDA_EXPR_EXTRA_ARGS and so should be immune to the PR114303 issue for now. So let's just disable this assert for lambdas. PR c++/117054 gcc/cp/ChangeLog: * pt.cc (extract_locals_r): Disable tree_extra_args assert for LAMBDA_EXPR. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/lambda-targ9.C: New test. Reviewed-by: Jason Merrill (cherry picked from commit bb2bfdb2048aed18ef7dc01b51816a800e83ce54) Diff: --- gcc/cp/pt.cc | 7 ++- gcc/testsuite/g++.dg/cpp2a/lambda-targ9.C | 16 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 85228b9f9435..818d5b65edce 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -13364,7 +13364,12 @@ extract_locals_r (tree *tp, int *walk_subtrees, void *data_) outermost tree. Nested *_EXTRA_ARGS should naturally be empty since the outermost (extra-args) tree will intercept any substitution before a nested tree can. */ -gcc_checking_assert (tree_extra_args (*tp) == NULL_TREE); +gcc_checking_assert (tree_extra_args (*tp) == NULL_TREE + /* Except a lambda nested inside an extra-args tree + can have extra args if we deferred partial + substitution into it at template parse time. But + we don't walk LAMBDA_EXPR_EXTRA_ARGS anyway. */ +|| TREE_CODE (*tp) == LAMBDA_EXPR); if (TREE_CODE (*tp) == DECL_EXPR) { diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-targ9.C b/gcc/testsuite/g++.dg/cpp2a/lambda-targ9.C new file mode 100644 index ..41f8526184a8 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/lambda-targ9.C @@ -0,0 +1,16 @@ +// PR c++/117054 +// { dg-do compile { target c++20 } } + +template +constexpr bool v = true; + +template +void f() { + [](auto) { +if constexpr (v<>) { } + }(0); +} + +int main() { + f(); +}
[gcc r15-4412] doc: remove outdated C++ Concepts section
https://gcc.gnu.org/g:c962153633048a506107a3ce13906edd19bfeb5c commit r15-4412-gc962153633048a506107a3ce13906edd19bfeb5c Author: Patrick Palka Date: Thu Oct 17 09:12:16 2024 -0400 doc: remove outdated C++ Concepts section This was added as part of the initial Concepts TS implementation and reflects an early version of the Concepts TS paper, which is very different from standard C++20 concepts (and even from more recent versions of the Concepts TS, support for which we deprecated in GCC 14 and removed for GCC 15). So there's not much to salvage from this section besides the __is_same trait documentation which we can conveniently move to the previous Type Traits section. gcc/ChangeLog: * doc/extend.texi (C++ Concepts): Remove section. Move __is_same documentation to the previous Type Traits section. Reviewed-by: Jason Merrill Diff: --- gcc/doc/extend.texi | 44 1 file changed, 44 deletions(-) diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 9bb263f9510e..42bd567119de 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -29268,7 +29268,6 @@ Predefined Macros,cpp,The GNU C Preprocessor}). * C++ Attributes:: Variable, function, and type attributes for C++ only. * Function Multiversioning:: Declaring multiple function versions. * Type Traits:: Compiler support for type traits. -* C++ Concepts::Improved support for generic programming. * Deprecated Features:: Things will disappear from G++. * Backwards Compatibility:: Compatibilities with earlier definitions of C++. @end menu @@ -30145,49 +30144,6 @@ from @code{0} to @code{@var{length}-1}. This is provided for efficient implementation of @code{std::make_integer_sequence}. @enddefbuiltin - -@node C++ Concepts -@section C++ Concepts - -C++ concepts provide much-improved support for generic programming. In -particular, they allow the specification of constraints on template arguments. -The constraints are used to extend the usual overloading and partial -specialization capabilities of the language, allowing generic data structures -and algorithms to be ``refined'' based on their properties rather than their -type names. - -The following keywords are reserved for concepts. - -@table @code -@kindex assumes -@item assumes -States an expression as an assumption, and if possible, verifies that the -assumption is valid. For example, @code{assume(n > 0)}. - -@kindex axiom -@item axiom -Introduces an axiom definition. Axioms introduce requirements on values. - -@kindex forall -@item forall -Introduces a universally quantified object in an axiom. For example, -@code{forall (int n) n + 0 == n}. - -@kindex concept -@item concept -Introduces a concept definition. Concepts are sets of syntactic and semantic -requirements on types and their values. - -@kindex requires -@item requires -Introduces constraints on template arguments or requirements for a member -function of a class template. -@end table - -The front end also exposes a number of internal mechanism that can be used -to simplify the writing of type traits. Note that some of these traits are -likely to be removed in the future. - @defbuiltin{bool __is_same (@var{type1}, @var{type2})} A binary type trait: @code{true} whenever the @var{type1} and @var{type2} refer to the same type.
[gcc r15-4368] c++: add fixed testcase [PR80637]
https://gcc.gnu.org/g:b110e092d260906432931796c1d96cba305c60e4 commit r15-4368-gb110e092d260906432931796c1d96cba305c60e4 Author: Patrick Palka Date: Tue Oct 15 13:43:29 2024 -0400 c++: add fixed testcase [PR80637] Fixed by r15-4340-gcacbb4daac3e9a. PR c++/80637 gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-fn9.C: New test. Diff: --- gcc/testsuite/g++.dg/cpp2a/concepts-fn9.C | 15 +++ 1 file changed, 15 insertions(+) diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-fn9.C b/gcc/testsuite/g++.dg/cpp2a/concepts-fn9.C new file mode 100644 index ..eb2963afcc96 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-fn9.C @@ -0,0 +1,15 @@ +// PR c++/80637 +// { dg-do compile { target c++20 } } + +template +concept same_as = __is_same(T, U); + +template +struct A { + void f(int) requires same_as; + void f(...) requires (!same_as); +}; + +auto fptr = &A::f; +using type = decltype(fptr); +using type = void (A::*)(int);
[gcc r15-4366] c++: unifying lvalue vs rvalue (non-forwarding) ref [PR116710]
https://gcc.gnu.org/g:8161c4adea7f1842f9d28633d82e912ebb7a4cf9 commit r15-4366-g8161c4adea7f1842f9d28633d82e912ebb7a4cf9 Author: Patrick Palka Date: Tue Oct 15 13:23:17 2024 -0400 c++: unifying lvalue vs rvalue (non-forwarding) ref [PR116710] When unifying two (non-forwarding) reference types, unify immediately recurses into the referenced type without first comparing rvalueness. (Note that at this point forwarding references and other reference parameters have already been stripped to their referenced type by maybe_adjust_types_for_deduction, so this code path applies only to nested reference types.) PR c++/116710 gcc/cp/ChangeLog: * pt.cc (unify) : Compare rvalueness. gcc/testsuite/ChangeLog: * g++.dg/template/unify12.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/pt.cc| 3 ++- gcc/testsuite/g++.dg/template/unify12.C | 24 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index c9219d5b3a5a..0141c53b617c 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -25161,7 +25161,8 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict, } case REFERENCE_TYPE: - if (!TYPE_REF_P (arg)) + if (!TYPE_REF_P (arg) + || TYPE_REF_IS_RVALUE (parm) != TYPE_REF_IS_RVALUE (arg)) return unify_type_mismatch (explain_p, parm, arg); return unify (tparms, targs, TREE_TYPE (parm), TREE_TYPE (arg), strict & UNIFY_ALLOW_MORE_CV_QUAL, explain_p); diff --git a/gcc/testsuite/g++.dg/template/unify12.C b/gcc/testsuite/g++.dg/template/unify12.C new file mode 100644 index ..bed52d0fa36c --- /dev/null +++ b/gcc/testsuite/g++.dg/template/unify12.C @@ -0,0 +1,24 @@ +// PR c++/116710 +// { dg-do compile { target c++11 } } + +template struct A : T {}; + +template +void f(void (*)(T &), typename A::type * = 0); + +void f(...); + +void g(int &&); + +void q() { f(g); } // OK + +template +struct B { operator B(); }; + +template +void h(B); + +int main() { + B b; + h(b); // { dg-error "no match" } +}
[gcc r15-4365] c++: checking ICE w/ constexpr if and lambda as def targ [PR117054]
https://gcc.gnu.org/g:bb2bfdb2048aed18ef7dc01b51816a800e83ce54 commit r15-4365-gbb2bfdb2048aed18ef7dc01b51816a800e83ce54 Author: Patrick Palka Date: Tue Oct 15 13:13:15 2024 -0400 c++: checking ICE w/ constexpr if and lambda as def targ [PR117054] Here we're tripping over the assert in extract_locals_r which enforces that an extra-args tree appearing inside another extra-args tree doesn't actually have extra args. This invariant doesn't always hold for lambdas (which recently gained the extra-args mechanism) but that should be harmless since cp_walk_subtrees doesn't walk LAMBDA_EXPR_EXTRA_ARGS and so should be immune to the PR114303 issue for now. So let's just disable this assert for lambdas. PR c++/117054 gcc/cp/ChangeLog: * pt.cc (extract_locals_r): Disable tree_extra_args assert for LAMBDA_EXPR. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/lambda-targ9.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/pt.cc | 7 ++- gcc/testsuite/g++.dg/cpp2a/lambda-targ9.C | 16 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index c0a37a51cba3..c9219d5b3a5a 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -13480,7 +13480,12 @@ extract_locals_r (tree *tp, int *walk_subtrees, void *data_) outermost tree. Nested *_EXTRA_ARGS should naturally be empty since the outermost (extra-args) tree will intercept any substitution before a nested tree can. */ -gcc_checking_assert (tree_extra_args (*tp) == NULL_TREE); +gcc_checking_assert (tree_extra_args (*tp) == NULL_TREE + /* Except a lambda nested inside an extra-args tree + can have extra args if we deferred partial + substitution into it at template parse time. But + we don't walk LAMBDA_EXPR_EXTRA_ARGS anyway. */ +|| TREE_CODE (*tp) == LAMBDA_EXPR); if (TREE_CODE (*tp) == DECL_EXPR) { diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-targ9.C b/gcc/testsuite/g++.dg/cpp2a/lambda-targ9.C new file mode 100644 index ..41f8526184a8 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/lambda-targ9.C @@ -0,0 +1,16 @@ +// PR c++/117054 +// { dg-do compile { target c++20 } } + +template +constexpr bool v = true; + +template +void f() { + [](auto) { +if constexpr (v<>) { } + }(0); +} + +int main() { + f(); +}
[gcc r14-10697] c++: decltype(auto) deduction of statement-expression [PR116418]
https://gcc.gnu.org/g:abdea396e12e66185d810435bbc363845cf4664a commit r14-10697-gabdea396e12e66185d810435bbc363845cf4664a Author: Patrick Palka Date: Thu Sep 12 12:45:03 2024 -0400 c++: decltype(auto) deduction of statement-expression [PR116418] r8-7538 for PR84968 made strip_typedefs_expr diagnose STATEMENT_LIST so that we reject statement-expressions in noexcept-specifiers to match our behavior in template arguments (which the parser diagnoses directly). Later r11-7452 made decltype(auto) deduction canonicalize the expression (as an implementation detail) which in turn calls strip_typedefs_expr, and so ever since we inadvertently reject decltype(auto) deduction of a statement-expression. This patch just removes the diagnostic in strip_typedefs_expr and instead treats statement-expressions similar to lambda-expressions. The function doesn't seem like the right place for such a diagnostic and so it seems easier to just accept rather than try to reject them in a suitable place. PR c++/116418 gcc/cp/ChangeLog: * tree.cc (strip_typedefs_expr) : Replace this error path with ... : ... this, returning the original tree. gcc/testsuite/ChangeLog: * g++.dg/eh/pr84968.C: No longer expect an ahead of time diagnostic for the statement-expresssion. Instantiate the template and expect an incomplete type error instead. * g++.dg/ext/stmtexpr26.C: New test. Reviewed-by: Jason Merrill (cherry picked from commit 12bdcc3d7970860b9d66ed4dea203bde8fd68d4d) Diff: --- gcc/cp/tree.cc| 5 + gcc/testsuite/g++.dg/eh/pr84968.C | 4 +++- gcc/testsuite/g++.dg/ext/stmtexpr26.C | 10 ++ 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc index d90244609c8a..a056237e8669 100644 --- a/gcc/cp/tree.cc +++ b/gcc/cp/tree.cc @@ -2008,12 +2008,9 @@ strip_typedefs_expr (tree t, bool *remove_attributes, unsigned int flags) } case LAMBDA_EXPR: +case STMT_EXPR: return t; -case STATEMENT_LIST: - error ("statement-expression in a constant expression"); - return error_mark_node; - default: break; } diff --git a/gcc/testsuite/g++.dg/eh/pr84968.C b/gcc/testsuite/g++.dg/eh/pr84968.C index 23c49f477a88..a6e21914eed1 100644 --- a/gcc/testsuite/g++.dg/eh/pr84968.C +++ b/gcc/testsuite/g++.dg/eh/pr84968.C @@ -9,7 +9,9 @@ struct S { void a() try { } catch (int () -noexcept (({ union b a; true; }))) // { dg-error "constant" } +noexcept (({ union b a; true; }))) // { dg-error "'b a' has incomplete type" } { } }; + +template void S::a(); // { dg-message "required from here" } diff --git a/gcc/testsuite/g++.dg/ext/stmtexpr26.C b/gcc/testsuite/g++.dg/ext/stmtexpr26.C new file mode 100644 index ..2250df550d48 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/stmtexpr26.C @@ -0,0 +1,10 @@ +// PR c++/116418 +// { dg-do compile { target c++14 } } +// { dg-options "" } + +void foo (); +template +void bar () +{ + decltype(auto) v = ({ foo (); 3; }); +}
[gcc r14-10696] c++: CWG 2789 and usings [PR116492]
https://gcc.gnu.org/g:659f32ea9de57661f8a37dcfb0b9a01bfe29acce commit r14-10696-g659f32ea9de57661f8a37dcfb0b9a01bfe29acce Author: Patrick Palka Date: Fri Sep 20 17:37:03 2024 -0400 c++: CWG 2789 and usings [PR116492] For GCC 14, narrowly fix this PR by implementing the missing - if they are member functions, both are direct members of the same class, and part of CWG 2789 for constructors only. PR c++/116492 DR 2789 gcc/cp/ChangeLog: * call.cc (cand_parms_match): Return false for constructors that come from different classes. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-inherit-ctor12.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/call.cc | 8 gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor12.C | 16 2 files changed, 24 insertions(+) diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 0f4eeeb53951..492d17b17446 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -12826,6 +12826,14 @@ cand_parms_match (z_candidate *c1, z_candidate *c2, pmatch match_kind) && DECL_FUNCTION_MEMBER_P (fn2))) /* Early escape. */; + else if ((DECL_INHERITED_CTOR (fn1) || DECL_INHERITED_CTOR (fn2)) + && (DECL_CONTEXT (strip_inheriting_ctors (fn1)) + != DECL_CONTEXT (strip_inheriting_ctors (fn2 +/* This should really be checked for all member functions as per + CWG2789, but for GCC 14 we check this only for constructors since + without r15-3740 doing so would result in inconsistent handling + of object parameters (such as in concepts-memfun4.C). */ +return false; /* CWG2789 is not adequate, it should specify corresponding object parameters, not same typed object parameters. */ else if (!object_parms_correspond (c1, fn1, c2, fn2)) diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor12.C b/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor12.C new file mode 100644 index ..3e5dbfc37ad0 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor12.C @@ -0,0 +1,16 @@ +// PR c++/116492 +// CWG 2789 +// { dg-do compile { target c++20 } } + +template +struct A { + A() requires true = delete; +}; + +struct B : A { + B(); + using A::A; +}; + +B b; // OK, selects the non-inherited constructor over the more constrained + // inherited constructor.
[gcc r15-3744] c++: CWG 2789 and reversed operator candidates
https://gcc.gnu.org/g:1f70503232d4183b4b58f2910c460569d05907b9 commit r15-3744-g1f70503232d4183b4b58f2910c460569d05907b9 Author: Patrick Palka Date: Fri Sep 20 15:41:42 2024 -0400 c++: CWG 2789 and reversed operator candidates As a follow-up to r15-3741-gee3efe06c9c49c, which was specifically concerned with usings, it seems the CWG 2789 refinement should also compare contexts of a reversed vs non-reversed (member) candidate during operator overload resolution. DR 2789 gcc/cp/ChangeLog: * call.cc (cand_parms_match): Check for matching class contexts even in the reversed case. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-memfun4.C: Adjust expected result involving reversed candidate. Reviewed-by: Jason Merrill Diff: --- gcc/cp/call.cc| 11 +++ gcc/testsuite/g++.dg/cpp2a/concepts-memfun4.C | 6 +++--- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index f2ce50857ece..70783baac242 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -12865,10 +12865,6 @@ cand_parms_match (z_candidate *c1, z_candidate *c2, pmatch match_kind) } } - else if (reversed) -return (reversed_match (c1, c2) - && reversed_match (c2, c1)); - tree parms1 = TYPE_ARG_TYPES (TREE_TYPE (fn1)); tree parms2 = TYPE_ARG_TYPES (TREE_TYPE (fn2)); @@ -12880,6 +12876,10 @@ cand_parms_match (z_candidate *c1, z_candidate *c2, pmatch match_kind) if (base1 != base2) return false; + if (reversed) + return (reversed_match (c1, c2) + && reversed_match (c2, c1)); + /* Use object_parms_correspond to simplify comparing iobj/xobj/static member functions. */ if (!object_parms_correspond (fn1, fn2, base1)) @@ -12897,6 +12897,9 @@ cand_parms_match (z_candidate *c1, z_candidate *c2, pmatch match_kind) parms1 = skip_parms (fn1, parms1); parms2 = skip_parms (fn2, parms2); } + else if (reversed) +return (reversed_match (c1, c2) + && reversed_match (c2, c1)); return compparms (parms1, parms2); } diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-memfun4.C b/gcc/testsuite/g++.dg/cpp2a/concepts-memfun4.C index cf7f13c007d1..d849e9129a3b 100644 --- a/gcc/testsuite/g++.dg/cpp2a/concepts-memfun4.C +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-memfun4.C @@ -91,7 +91,7 @@ namespace N1 { A<> a; B<> b; - // when comparing the A op== to the reversed B op==, we compare them in - // reverse order, so they match, and we choose the more constrained. - static_assert (a == b); + // A op== and B op== are defined in different classes so constraints + // aren't considered, and the tie is broken via reversedness. + static_assert (!(a == b)); }
[gcc r15-3740] c++: CWG 2273 and non-constructors
https://gcc.gnu.org/g:06557ba12b64c57368673c46a21b14cf4e6afb50 commit r15-3740-g06557ba12b64c57368673c46a21b14cf4e6afb50 Author: Patrick Palka Date: Fri Sep 20 12:31:40 2024 -0400 c++: CWG 2273 and non-constructors Our implementation of the CWG 2273 inheritedness tiebreaker seems to be incorrectly considering all member functions introduced via using, not just constructors. This patch restricts the tiebreaker accordingly. DR 2273 gcc/cp/ChangeLog: * call.cc (joust): Restrict inheritedness tiebreaker to constructors. gcc/testsuite/ChangeLog: * g++.dg/cpp1z/using1.C: Expect ambiguity for non-constructor call. * g++.dg/overload/using5.C: Likewise. Reviewed-by: Jason Merrill Diff: --- gcc/cp/call.cc | 11 --- gcc/testsuite/g++.dg/cpp1z/using1.C| 8 gcc/testsuite/g++.dg/overload/using5.C | 2 +- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 3f753e2d2f98..6229dc452636 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -13350,13 +13350,10 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn, } } - /* F1 is a member of a class D, F2 is a member of a base class B of D, and - for all arguments the corresponding parameters of F1 and F2 have the same - type (CWG 2273/2277). */ - if (DECL_P (cand1->fn) && DECL_CLASS_SCOPE_P (cand1->fn) - && !DECL_CONV_FN_P (cand1->fn) - && DECL_P (cand2->fn) && DECL_CLASS_SCOPE_P (cand2->fn) - && !DECL_CONV_FN_P (cand2->fn)) + /* F1 is a constructor for a class D, F2 is a constructor for a base class B + of D, and for all arguments the corresponding parameters of F1 and F2 have + the same type (CWG 2273/2277). */ + if (DECL_INHERITED_CTOR (cand1->fn) || DECL_INHERITED_CTOR (cand2->fn)) { tree base1 = DECL_CONTEXT (strip_inheriting_ctors (cand1->fn)); tree base2 = DECL_CONTEXT (strip_inheriting_ctors (cand2->fn)); diff --git a/gcc/testsuite/g++.dg/cpp1z/using1.C b/gcc/testsuite/g++.dg/cpp1z/using1.C index 1ed939d45fd4..d8a045255795 100644 --- a/gcc/testsuite/g++.dg/cpp1z/using1.C +++ b/gcc/testsuite/g++.dg/cpp1z/using1.C @@ -1,5 +1,5 @@ -// Test for hiding of used base functions when all the conversion sequences are -// equivalent, needed to avoid a regression on inherited default ctors. +// Test the CWG 2273 inheritedness tiebreaker doesn't apply to +// non-constructors. struct A { @@ -17,7 +17,7 @@ struct B:A int main() { - B().f(1);// OK, derived f hides base f for single arg + B().f(1);// { dg-error "ambiguous" } B().f(1,2); // OK, base f can still be called with two args - B().g(1);// { dg-error "" } signatures differ, ambiguous + B().g(1);// { dg-error "ambiguous" } } diff --git a/gcc/testsuite/g++.dg/overload/using5.C b/gcc/testsuite/g++.dg/overload/using5.C index ad17c78a561e..0933a9f0fac3 100644 --- a/gcc/testsuite/g++.dg/overload/using5.C +++ b/gcc/testsuite/g++.dg/overload/using5.C @@ -24,5 +24,5 @@ struct C: B { int main() { C c (42); - c.f(); + c.f(); // { dg-error "ambiguous" } }
[gcc r15-3741] c++: CWG 2789 and usings [PR116492]
https://gcc.gnu.org/g:ee3efe06c9c49c04eaa4e195a7ae8774a1b3faa2 commit r15-3741-gee3efe06c9c49c04eaa4e195a7ae8774a1b3faa2 Author: Patrick Palka Date: Fri Sep 20 12:33:13 2024 -0400 c++: CWG 2789 and usings [PR116492] After CWG 2789, the "more constrained" tiebreaker for non-template functions should exclude member functions that are defined in different classes. This patch implements this missing refinement. In turn we can get rid of four-parameter version of object_parms_correspond and call the main overload directly since now correspondence is only only checked for members from the same class. PR c++/116492 DR 2789 gcc/cp/ChangeLog: * call.cc (object_parms_correspond): Remove. (cand_parms_match): Return false for member functions that come from different classes. Adjust call to object_parms_correspond. (joust): Update comment for the non-template "more constrained" case. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-memfun4.C: Also compile in C++20 mode. Expect ambiguity when candidates come from different classes. * g++.dg/cpp2a/concepts-inherit-ctor12.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/call.cc | 54 -- .../g++.dg/cpp2a/concepts-inherit-ctor12.C | 16 +++ gcc/testsuite/g++.dg/cpp2a/concepts-memfun4.C | 24 +- 3 files changed, 49 insertions(+), 45 deletions(-) diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 6229dc452636..f2ce50857ece 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -12808,27 +12808,6 @@ class_of_implicit_object (z_candidate *cand) return BINFO_TYPE (cand->conversion_path); } -/* True if candidates C1 and C2 have corresponding object parameters per - [basic.scope.scope]. */ - -static bool -object_parms_correspond (z_candidate *c1, tree fn1, z_candidate *c2, tree fn2) -{ - tree context = class_of_implicit_object (c1); - tree ctx2 = class_of_implicit_object (c2); - if (!ctx2) -/* Leave context as is. */; - else if (!context) -context = ctx2; - else if (context != ctx2) -/* This can't happen for normal function calls, since it means finding - functions in multiple bases which would fail with an ambiguous lookup, - but it can occur with reversed operators. */ -return false; - - return object_parms_correspond (fn1, fn2, context); -} - /* Return whether the first parameter of C1 matches the second parameter of C2. */ @@ -12893,16 +12872,19 @@ cand_parms_match (z_candidate *c1, z_candidate *c2, pmatch match_kind) tree parms1 = TYPE_ARG_TYPES (TREE_TYPE (fn1)); tree parms2 = TYPE_ARG_TYPES (TREE_TYPE (fn2)); - if (!(DECL_FUNCTION_MEMBER_P (fn1) - && DECL_FUNCTION_MEMBER_P (fn2))) -/* Early escape. */; - - /* CWG2789 is not adequate, it should specify corresponding object - parameters, not same typed object parameters. */ - else if (!object_parms_correspond (c1, fn1, c2, fn2)) -return false; - else + if (DECL_FUNCTION_MEMBER_P (fn1) + && DECL_FUNCTION_MEMBER_P (fn2)) { + tree base1 = DECL_CONTEXT (strip_inheriting_ctors (fn1)); + tree base2 = DECL_CONTEXT (strip_inheriting_ctors (fn2)); + if (base1 != base2) + return false; + + /* Use object_parms_correspond to simplify comparing iobj/xobj/static +member functions. */ + if (!object_parms_correspond (fn1, fn2, base1)) + return false; + /* We just compared the object parameters, if they don't correspond we already returned false. */ auto skip_parms = [] (tree fn, tree parms) @@ -13269,10 +13251,14 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn, return winner; } - /* Concepts: F1 and F2 are non-template functions with the same - parameter-type-lists, and F1 is more constrained than F2 according to the - partial ordering of constraints described in 13.5.4. */ - + /* F1 and F2 are non-template functions and + - they have the same non-object-parameter-type-lists ([dcl.fct]), and + - if they are member functions, both are direct members of the same + class, and + - if both are non-static member functions, they have the same types for + their object parameters, and + - F1 is more constrained than F2 according to the partial ordering of + constraints described in [temp.constr.order]. */ if (flag_concepts && DECL_P (cand1->fn) && DECL_P (cand2->fn) && !cand1->template_decl && !cand2->template_decl && cand_parms_match (cand1, cand2, pmatch::current)) diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor12.C b/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor12.C new file mode 100644 index ..3e5dbfc37ad0 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concep
[gcc r15-3694] c++: alias of decltype(lambda) is opaque [PR116714, PR107390]
https://gcc.gnu.org/g:82c2acd0bc4411524a8248fcdce219927d921a71 commit r15-3694-g82c2acd0bc4411524a8248fcdce219927d921a71 Author: Patrick Palka Date: Wed Sep 18 13:50:43 2024 -0400 c++: alias of decltype(lambda) is opaque [PR116714, PR107390] Here for using type = decltype([]{}); static_assert(is_same_v); we strip the alias ahead of time during template argument coercion which effectively transforms the template-id into is_same_v which is wrong because later substitution into the template-id will produce two new lambdas with distinct types and cause is_same_v to return false. This demonstrates that such aliases should be considered opaque (a notion that we recently introduced in r15-2331-g523836716137d0). (An alternative solution might be to consider memoizing lambda-expr substitution rather than always producing a new lambda, but this is much simpler.) PR c++/116714 PR c++/107390 gcc/cp/ChangeLog: * pt.cc (dependent_opaque_alias_p): Also return true for a decltype(lambda) alias. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/lambda-uneval18.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/pt.cc | 11 ++-- gcc/testsuite/g++.dg/cpp2a/lambda-uneval18.C | 39 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 769e7999dac1..e826206be164 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -6759,8 +6759,15 @@ dependent_opaque_alias_p (const_tree t) { return (TYPE_P (t) && typedef_variant_p (t) - && any_dependent_type_attributes_p (DECL_ATTRIBUTES - (TYPE_NAME (t; + && (any_dependent_type_attributes_p (DECL_ATTRIBUTES + (TYPE_NAME (t))) + /* Treat a dependent decltype(lambda) alias as opaque so that we +don't prematurely strip it when used as a template argument. +Otherwise substitution into each occurrence of the (stripped) +alias would incorrectly yield a distinct lambda type. */ + || (TREE_CODE (t) == DECLTYPE_TYPE + && TREE_CODE (DECLTYPE_TYPE_EXPR (t)) == LAMBDA_EXPR + && !typedef_variant_p (DECL_ORIGINAL_TYPE (TYPE_NAME (t)); } /* Return the number of innermost template parameters in TMPL. */ diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-uneval18.C b/gcc/testsuite/g++.dg/cpp2a/lambda-uneval18.C new file mode 100644 index ..b7d864c62453 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/lambda-uneval18.C @@ -0,0 +1,39 @@ +// PR c++/116714 +// PR c++/107390 +// { dg-do compile { target c++20 } } + +template +inline constexpr bool is_same_v = __is_same(T, U); + +template +struct is_same { static constexpr bool value = false; }; + +template +struct is_same { static constexpr bool value = true; }; + +template +void f() { + using type = decltype([]{}); + static_assert(is_same_v); + static_assert(is_same::value); +}; + +template +void g() { + using ty1 = decltype([]{}); + using ty2 = ty1; + static_assert(is_same_v); + static_assert(is_same::value); +}; + +template +void h() { + using ty1 = decltype([]{}); + using ty2 = decltype([]{}); + static_assert(!is_same_v); + static_assert(!is_same::value); +}; + +template void f(); +template void g(); +template void h();
[gcc r15-3611] c++: decltype(auto) deduction of statement-expression [PR116418]
https://gcc.gnu.org/g:12bdcc3d7970860b9d66ed4dea203bde8fd68d4d commit r15-3611-g12bdcc3d7970860b9d66ed4dea203bde8fd68d4d Author: Patrick Palka Date: Thu Sep 12 12:45:03 2024 -0400 c++: decltype(auto) deduction of statement-expression [PR116418] r8-7538 for PR84968 made strip_typedefs_expr diagnose STATEMENT_LIST so that we reject statement-expressions in noexcept-specifiers to match our behavior in template arguments (which the parser diagnoses directly). Later r11-7452 made decltype(auto) deduction canonicalize the expression (as an implementation detail) which in turn calls strip_typedefs_expr, and so ever since we inadvertently reject decltype(auto) deduction of a statement-expression. This patch just removes the diagnostic in strip_typedefs_expr and instead treats statement-expressions similar to lambda-expressions. The function doesn't seem like the right place for such a diagnostic and so it seems easier to just accept rather than try to reject them in a suitable place. PR c++/116418 gcc/cp/ChangeLog: * tree.cc (strip_typedefs_expr) : Replace this error path with ... : ... this, returning the original tree. gcc/testsuite/ChangeLog: * g++.dg/eh/pr84968.C: No longer expect an ahead of time diagnostic for the statement-expresssion. Instantiate the template and expect an incomplete type error instead. * g++.dg/ext/stmtexpr26.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/tree.cc| 5 + gcc/testsuite/g++.dg/eh/pr84968.C | 4 +++- gcc/testsuite/g++.dg/ext/stmtexpr26.C | 10 ++ 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc index c3a38de4f486..99088da9cee0 100644 --- a/gcc/cp/tree.cc +++ b/gcc/cp/tree.cc @@ -2009,12 +2009,9 @@ strip_typedefs_expr (tree t, bool *remove_attributes, unsigned int flags) } case LAMBDA_EXPR: +case STMT_EXPR: return t; -case STATEMENT_LIST: - error ("statement-expression in a constant expression"); - return error_mark_node; - default: break; } diff --git a/gcc/testsuite/g++.dg/eh/pr84968.C b/gcc/testsuite/g++.dg/eh/pr84968.C index 23c49f477a88..a6e21914eed1 100644 --- a/gcc/testsuite/g++.dg/eh/pr84968.C +++ b/gcc/testsuite/g++.dg/eh/pr84968.C @@ -9,7 +9,9 @@ struct S { void a() try { } catch (int () -noexcept (({ union b a; true; }))) // { dg-error "constant" } +noexcept (({ union b a; true; }))) // { dg-error "'b a' has incomplete type" } { } }; + +template void S::a(); // { dg-message "required from here" } diff --git a/gcc/testsuite/g++.dg/ext/stmtexpr26.C b/gcc/testsuite/g++.dg/ext/stmtexpr26.C new file mode 100644 index ..2250df550d48 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/stmtexpr26.C @@ -0,0 +1,10 @@ +// PR c++/116418 +// { dg-do compile { target c++14 } } +// { dg-options "" } + +void foo (); +template +void bar () +{ + decltype(auto) v = ({ foo (); 3; }); +}
[gcc r14-10656] c++: c->B::m access resolved through current inst [PR116320]
https://gcc.gnu.org/g:149d87fbe661da29d8a0aa671b42bd532206a8b8 commit r14-10656-g149d87fbe661da29d8a0aa671b42bd532206a8b8 Author: Patrick Palka Date: Thu Aug 15 10:23:54 2024 -0400 c++: c->B::m access resolved through current inst [PR116320] Here when checking the access of (the injected-class-name) B in c->B::m at parse time, we notice its context B (now the type) is a base of the object type C, so we proceed to use C as the effective qualifying type. But this C is the dependent specialization not the primary template type, so it has empty TYPE_BINFO, which leads to a segfault later from perform_or_defer_access_check. The reason the DERIVED_FROM_P (B, C) test guarding this code path works despite C having empty TYPE_BINFO is because of its currently_open_class logic (added in r9-713-gd9338471b91bbe) which replaces a dependent specialization with the primary template type if we're inside it. So the safest fix seems to be to call currently_open_class in the caller as well. PR c++/116320 gcc/cp/ChangeLog: * semantics.cc (check_accessibility_of_qualified_id): Try currently_open_class when using the object type as the effective qualifying type. gcc/testsuite/ChangeLog: * g++.dg/template/access42.C: New test. Reviewed-by: Jason Merrill (cherry picked from commit 484f139ccd3b631a777802e810a632678b42ffab) Diff: --- gcc/cp/semantics.cc | 11 --- gcc/testsuite/g++.dg/template/access42.C | 17 + 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index b5569066708e..ceeac82fa081 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -2497,9 +2497,14 @@ check_accessibility_of_qualified_id (tree decl, OBJECT_TYPE. */ && CLASS_TYPE_P (object_type) && DERIVED_FROM_P (scope, object_type)) -/* If we are processing a `->' or `.' expression, use the type of the - left-hand side. */ -qualifying_type = object_type; +{ + /* If we are processing a `->' or `.' expression, use the type of the +left-hand side. */ + if (tree open = currently_open_class (object_type)) + qualifying_type = open; + else + qualifying_type = object_type; +} else if (nested_name_specifier) { /* If the reference is to a non-static member of the diff --git a/gcc/testsuite/g++.dg/template/access42.C b/gcc/testsuite/g++.dg/template/access42.C new file mode 100644 index ..f1dcbce80c24 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/access42.C @@ -0,0 +1,17 @@ +// PR c++/116320 +// { dg-do compile { target c++11 } } + +template struct C; +template using C_ptr = C*; + +struct B { int m; using B_typedef = B; }; + +template +struct C : B { + void f(C_ptr c) { +c->B::m; +c->B_typedef::m; + } +}; + +template struct C;
[gcc r14-10655] c++: inherited CTAD fixes [PR116276]
https://gcc.gnu.org/g:b5ed381d05e0ed9edf2f320b71f8775ea96a4866 commit r14-10655-gb5ed381d05e0ed9edf2f320b71f8775ea96a4866 Author: Patrick Palka Date: Fri Aug 9 21:15:25 2024 -0400 c++: inherited CTAD fixes [PR116276] This implements the overlooked inherited vs non-inherited guide tiebreaker from P2582R1. This requires tracking inherited-ness of a guide, for which it seems natural to reuse the lang_decl_fn::context field which for a constructor tracks its inherited-ness. This patch also works around CLASSTYPE_CONSTRUCTORS not reliably returning all inherited constructors (due to some using-decl handling quirks in in push_class_level_binding) by iterating over TYPE_FIELDS instead. This patch also makes us recognize another written form of inherited constructor, 'using Base::Base::Base' whose USING_DECL_SCOPE is a TYPENAME_TYPE. PR c++/116276 gcc/cp/ChangeLog: * call.cc (joust): Implement P2582R1 inherited vs non-inherited guide tiebreaker. * cp-tree.h (lang_decl_fn::context): Document usage in deduction_guide_p FUNCTION_DECLs. (inherited_guide_p): Declare. * pt.cc (inherited_guide_p): Define. (set_inherited_guide_context): Define. (alias_ctad_tweaks): Use set_inherited_guide_context. (inherited_ctad_tweaks): Recognize some inherited constructors whose scope is a TYPENAME_TYPE. (ctor_deduction_guides_for): For C++23 inherited CTAD, iterate over TYPE_FIELDS instead of CLASSTYPE_CONSTRUCTORS to recognize all inherited constructors. gcc/testsuite/ChangeLog: * g++.dg/cpp23/class-deduction-inherited4.C: Remove an xfail. * g++.dg/cpp23/class-deduction-inherited5.C: New test. * g++.dg/cpp23/class-deduction-inherited6.C: New test. Reviewed-by: Jason Merrill (cherry picked from commit 8cc67b520968ca9a13fd96896522aa66e39a99e2) Diff: --- gcc/cp/call.cc | 27 - gcc/cp/cp-tree.h | 8 ++-- gcc/cp/pt.cc | 43 .../g++.dg/cpp23/class-deduction-inherited4.C | 4 +- .../g++.dg/cpp23/class-deduction-inherited5.C | 25 .../g++.dg/cpp23/class-deduction-inherited6.C | 46 ++ 6 files changed, 139 insertions(+), 14 deletions(-) diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 793b98347124..0f4eeeb53951 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -13226,10 +13226,35 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn, else if (cand2->rewritten ()) return 1; - /* F1 is generated from a deduction-guide (13.3.1.8) and F2 is not */ if (deduction_guide_p (cand1->fn)) { gcc_assert (deduction_guide_p (cand2->fn)); + + /* F1 and F2 are generated from class template argument deduction for a +class D, and F2 is generated from inheriting constructors from a base +class of D while F1 is not, and for each explicit function argument, +the corresponding parameters of F1 and F2 are either both ellipses or +have the same type. */ + bool inherited1 = inherited_guide_p (cand1->fn); + bool inherited2 = inherited_guide_p (cand2->fn); + if (int diff = inherited2 - inherited1) + { + for (i = 0; i < len; ++i) + { + conversion *t1 = cand1->convs[i + off1]; + conversion *t2 = cand2->convs[i + off2]; + /* ??? It seems the ellipses part of this tiebreaker isn't +needed since a mismatch should have broken the tie earlier +during ICS comparison. */ + gcc_checking_assert (t1->ellipsis_p == t2->ellipsis_p); + if (!same_type_p (t1->type, t2->type)) + break; + } + if (i == len) + return diff; + } + + /* F1 is generated from a deduction-guide (13.3.1.8) and F2 is not */ /* We distinguish between candidates from an explicit deduction guide and candidates built from a constructor based on DECL_ARTIFICIAL. */ int art1 = DECL_ARTIFICIAL (cand1->fn); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 3f607313db61..ab2b0904ed60 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -2981,9 +2981,10 @@ struct GTY(()) lang_decl_fn { this pointer and result pointer adjusting thunks are chained here. This pointer thunks to return pointer thunks will be chained on the return pointer thunk. - For a DECL_CONSTUCTOR_P FUNCTION_DECL, this is the base from - whence we inherit. Otherwise, it is the class in which a - (namespace-scope) friend is defined (if any). */ + For a DECL_CONSTRUCTOR_P or deduction_guide_p FUNCTION_DECL, + this i
[gcc r14-10652] c++: template depth of lambda in default targ [PR116567]
https://gcc.gnu.org/g:0c80216b7bb0938bff7db230cbefa5bc3e8b3034 commit r14-10652-g0c80216b7bb0938bff7db230cbefa5bc3e8b3034 Author: Patrick Palka Date: Sat Sep 7 14:10:09 2024 -0400 c++: template depth of lambda in default targ [PR116567] For GCC 14, let's narrowly fix this bug by just pruning the result of add_extra_args after the fact to get rid of any unwanted outer levels. PR c++/116567 gcc/cp/ChangeLog: * pt.cc (tsubst_lambda_expr): For a deferred-substitution lambda, trim the augmented template arguments to match the template depth of the lambda. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/lambda-targ7.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/pt.cc | 12 + gcc/testsuite/g++.dg/cpp2a/lambda-targ7.C | 42 +++ 2 files changed, 54 insertions(+) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 8e6a7d1a64a4..7135105fc375 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -19679,6 +19679,18 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) LAMBDA_EXPR_EXTRA_ARGS (t) = build_extra_args (t, args, complain); return t; } + if (LAMBDA_EXPR_EXTRA_ARGS (t)) +{ + /* If we deferred substitution into this lambda, then its original +context (e.g. default template argument context) might be unrelated +to the current context it's embedded in. After add_extra_args though, +the innermost levels of 'args' will correspond to the lambda context, +so get rid of all unrelated levels. */ + tree ctx_parms = DECL_TEMPLATE_PARMS (DECL_TI_TEMPLATE (oldfn)); + if (generic_lambda_fn_p (oldfn)) + ctx_parms = TREE_CHAIN (ctx_parms); + args = get_innermost_template_args (args, TMPL_PARMS_DEPTH (ctx_parms)); +} tree r = build_lambda_expr (); diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-targ7.C b/gcc/testsuite/g++.dg/cpp2a/lambda-targ7.C new file mode 100644 index ..97b42d6ed0c4 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/lambda-targ7.C @@ -0,0 +1,42 @@ +// PR c++/116567 +// { dg-do compile { target c++20 } } + +struct X { int n; }; + +template +auto v1 = F; + +template +auto v1g = F; + +template +struct A { + template + static inline auto v2 = F; + + template + static inline auto v2g = F; + + template + struct B { +template +static inline auto v3 = F; + +template +static inline auto v3g = F; + +template +static void f() { + static_assert(v1().n == 1); + static_assert(v1g(42).n == 1 + 42); + static_assert(v2().n == 2); + static_assert(v2g(42).n == 2 + 42); + static_assert(v3().n == 3); + static_assert(v3g(42).n == 3 + 42); +} + }; +}; + +int main() { + A::B::f(); +}
[gcc r15-3530] c++: deferring partial substitution into lambda [PR116567]
https://gcc.gnu.org/g:dfb63765e994bee74d533c810fdf75d3269530ad commit r15-3530-gdfb63765e994bee74d533c810fdf75d3269530ad Author: Patrick Palka Date: Sat Sep 7 14:06:37 2024 -0400 c++: deferring partial substitution into lambda [PR116567] Here we correctly defer partial substitution into the lambda used as a default template argument, but then incorrectly perform the full substitution, because add_extra_args adds outer template arguments from the full substitution that are not related to the original template context of the lambda. For example, the template depth of the first lambda is 1 but add_extra_args return a set of args with 3 levels, with the inner level corresponding to the parameters of v1 (good) and the outer levels corresponding to those of A and B (bad). For the cases that we're interested in, add_extra_args can assume that the deferred args are a full set of template arguments, and so it suffices to just substitute into the deferred args and not do any additional merging. This patch refines add_extra_args accordingly, and additionally makes it look for the tf_partial flag instead of for dependent args to decide if the deferred substitution is a partial one. This reveals we were neglecting to set tf_partial when substituting into a default template argument in a template context. PR c++/116567 gcc/cp/ChangeLog: * pt.cc (coerce_template_parms): Set tf_partial when substituting into a default template argument in a template context. (build_extra_args): Set TREE_STATIC on the deferred args if this is a partial substitution. (add_extra_args): Check TREE_STATIC instead of dependence of args. Adjust merging behavior in that case. (tsubst_lammda_expr): Check for tf_partial instead of dependence of args when determining whether to defer substitution. (tsubst_expr) : Remove tf_partial early exit. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/lambda-targ7.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/pt.cc | 35 +- gcc/testsuite/g++.dg/cpp2a/lambda-targ7.C | 42 +++ 2 files changed, 60 insertions(+), 17 deletions(-) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 72b17fdd8a76..310e5dfff033 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -9326,7 +9326,9 @@ coerce_template_parms (tree parms, { /* There must be a default arg in this case. */ arg = tsubst_template_arg (TREE_PURPOSE (parm), new_args, -complain, in_decl); +complain | (processing_template_decl +? tf_partial : tf_none), +in_decl); /* The position of the first default template argument, is also the number of non-defaulted arguments in NEW_INNER_ARGS. Record that. */ @@ -13569,6 +13571,9 @@ build_extra_args (tree pattern, tree args, tsubst_flags_t complain) /* Make a copy of the extra arguments so that they won't get changed out from under us. */ tree extra = preserve_args (copy_template_args (args), /*cow_p=*/false); + if (complain & tf_partial) +/* Remember whether this is a partial substitution. */ +TREE_STATIC (extra) = true; if (local_specializations) if (tree locals = extract_local_specs (pattern, complain)) extra = tree_cons (NULL_TREE, extra, locals); @@ -13581,7 +13586,10 @@ build_extra_args (tree pattern, tree args, tsubst_flags_t complain) tree add_extra_args (tree extra, tree args, tsubst_flags_t complain, tree in_decl) { - if (extra && TREE_CODE (extra) == TREE_LIST) + if (!extra) +return args; + + if (TREE_CODE (extra) == TREE_LIST) { for (tree elt = TREE_CHAIN (extra); elt; elt = TREE_CHAIN (elt)) { @@ -13599,13 +13607,13 @@ add_extra_args (tree extra, tree args, tsubst_flags_t complain, tree in_decl) gcc_assert (!TREE_PURPOSE (extra)); extra = TREE_VALUE (extra); } - if (uses_template_parms (extra)) -{ - /* This can happen after dependent substitution into a -requires-expr or a lambda that uses constexpr if. */ - extra = tsubst_template_args (extra, args, complain, in_decl); - args = add_outermost_template_args (args, extra); -} + gcc_checking_assert (TREE_STATIC (extra) == uses_template_parms (extra)); + if (TREE_STATIC (extra)) +/* This is a partial substitution into e.g. a requires-expr or lambda-expr + inside a default template argument; we expect 'extra' to be a full set + of template arguments for the template context, so it suffices to just + substitute into them. */ +args = tsubst_template_args (extra, args
[gcc r15-3491] c++: local class memfn synth from noexcept context [PR113063]
https://gcc.gnu.org/g:37977343ff4f9dcb047d966d8cbaa222964763f9 commit r15-3491-g37977343ff4f9dcb047d966d8cbaa222964763f9 Author: Patrick Palka Date: Thu Sep 5 14:31:00 2024 -0400 c++: local class memfn synth from noexcept context [PR113063] Extending the PR113063 testcase to additionally constant evaluate the <=> expression causes us to trip over the assert in cxx_eval_call_expression /* We used to shortcut trivial constructor/op= here, but nowadays we can only get a trivial function here with -fno-elide-constructors. */ gcc_checking_assert (!trivial_fn_p (fun) || !flag_elide_constructors /* We don't elide constructors when processing a noexcept-expression. */ || cp_noexcept_operand); since the local class's <=> was first used and therefore synthesized in a noexcept context and so its definition contains unelided trivial constructors. This patch fixes this by clearing cp_noexcept_operand alongside cp_unevaluated_context in the function-local case of maybe_push_to_top_level. PR c++/113063 gcc/cp/ChangeLog: * name-lookup.cc (local_state_t): Clear and restore cp_noexcept_operand as well. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/spaceship-synth16.C: Also constant evaluate the <=> expression. * g++.dg/cpp2a/spaceship-synth16a.C: Likewise. Reviewed-by: Jason Merrill Diff: --- gcc/cp/name-lookup.cc | 4 gcc/testsuite/g++.dg/cpp2a/spaceship-synth16.C | 1 + gcc/testsuite/g++.dg/cpp2a/spaceship-synth16a.C | 1 + 3 files changed, 6 insertions(+) diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index cd3947cbe4f..bfe17b7cb2f 100644 --- a/gcc/cp/name-lookup.cc +++ b/gcc/cp/name-lookup.cc @@ -8781,6 +8781,7 @@ struct local_state_t { int cp_unevaluated_operand; int c_inhibit_evaluation_warnings; + int cp_noexcept_operand_; static local_state_t save_and_clear () @@ -8790,6 +8791,8 @@ struct local_state_t ::cp_unevaluated_operand = 0; s.c_inhibit_evaluation_warnings = ::c_inhibit_evaluation_warnings; ::c_inhibit_evaluation_warnings = 0; +s.cp_noexcept_operand_ = ::cp_noexcept_operand; +::cp_noexcept_operand = 0; return s; } @@ -8798,6 +8801,7 @@ struct local_state_t { ::cp_unevaluated_operand = this->cp_unevaluated_operand; ::c_inhibit_evaluation_warnings = this->c_inhibit_evaluation_warnings; +::cp_noexcept_operand = this->cp_noexcept_operand_; } }; diff --git a/gcc/testsuite/g++.dg/cpp2a/spaceship-synth16.C b/gcc/testsuite/g++.dg/cpp2a/spaceship-synth16.C index 37a183de0f5..7dbe7e1db75 100644 --- a/gcc/testsuite/g++.dg/cpp2a/spaceship-synth16.C +++ b/gcc/testsuite/g++.dg/cpp2a/spaceship-synth16.C @@ -10,4 +10,5 @@ int main() { X x; static_assert(noexcept(x <=> x)); x <=> x; + constexpr auto r = x <=> x; } diff --git a/gcc/testsuite/g++.dg/cpp2a/spaceship-synth16a.C b/gcc/testsuite/g++.dg/cpp2a/spaceship-synth16a.C index 68388a680b2..bc0e7a54b7e 100644 --- a/gcc/testsuite/g++.dg/cpp2a/spaceship-synth16a.C +++ b/gcc/testsuite/g++.dg/cpp2a/spaceship-synth16a.C @@ -13,4 +13,5 @@ int main() { X x; static_assert(noexcept(x <=> x)); x <=> x; + constexpr auto r = X{} <=> X{}; }
[gcc r15-3089] libstdc++: Implement P2609R3 changes to the indirect invocability concepts
https://gcc.gnu.org/g:b552730faf36f1eae1dc6e73ccc93a016dec5401 commit r15-3089-gb552730faf36f1eae1dc6e73ccc93a016dec5401 Author: Patrick Palka Date: Thu Aug 22 09:24:11 2024 -0400 libstdc++: Implement P2609R3 changes to the indirect invocability concepts This implements the changes of this C++23 paper as a DR against C++20. Note that after the later P2538R1 "ADL-proof std::projected" (which we already implement), we can't use a simple partial specialization to match specializations of the 'projected' alias template. So instead we identify such specializations using a pair of distinguishing member aliases. libstdc++-v3/ChangeLog: * include/bits/iterator_concepts.h (__detail::__indirect_value): Define. (__indirect_value_t): Define as per P2609R3. (iter_common_reference_t): Adjust as per P2609R3. (indirectly_unary_invocable): Likewise. (indirectly_regular_unary_invocable): Likewise. (indirect_unary_predicate): Likewise. (indirect_binary_predicate): Likewise. (indirect_equivalence_relation): Likewise. (indirect_strict_weak_order): Likewise. (__detail::__projected::__type): Define member aliases __projected_Iter and __projected_Proj providing the template arguments of the current specialization. * include/bits/version.def (ranges): Update value. * include/bits/version.h: Regenerate. * testsuite/24_iterators/indirect_callable/p2609r3.cc: New test. * testsuite/std/ranges/version_c++23.cc: Update expected value of __cpp_lib_ranges macro. Reviewed-by: Jonathan Wakely Diff: --- libstdc++-v3/include/bits/iterator_concepts.h | 61 -- libstdc++-v3/include/bits/version.def | 2 +- libstdc++-v3/include/bits/version.h| 4 +- .../24_iterators/indirect_callable/p2609r3.cc | 27 ++ libstdc++-v3/testsuite/std/ranges/version_c++23.cc | 2 +- 5 files changed, 77 insertions(+), 19 deletions(-) diff --git a/libstdc++-v3/include/bits/iterator_concepts.h b/libstdc++-v3/include/bits/iterator_concepts.h index ce0b8a10f88f..9306b7bd194c 100644 --- a/libstdc++-v3/include/bits/iterator_concepts.h +++ b/libstdc++-v3/include/bits/iterator_concepts.h @@ -552,9 +552,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION concept indirectly_readable = __detail::__indirectly_readable_impl>; + namespace __detail + { +template + struct __indirect_value + { using type = iter_value_t<_Tp>&; }; + +// __indirect_value> is defined later. + } // namespace __detail + + template +using __indirect_value_t = typename __detail::__indirect_value<_Tp>::type; + template using iter_common_reference_t - = common_reference_t, iter_value_t<_Tp>&>; + = common_reference_t, __indirect_value_t<_Tp>>; /// Requirements for writing a value into an iterator's referenced object. template @@ -710,24 +722,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template concept indirectly_unary_invocable = indirectly_readable<_Iter> - && copy_constructible<_Fn> && invocable<_Fn&, iter_value_t<_Iter>&> + && copy_constructible<_Fn> && invocable<_Fn&, __indirect_value_t<_Iter>> && invocable<_Fn&, iter_reference_t<_Iter>> && invocable<_Fn&, iter_common_reference_t<_Iter>> - && common_reference_with&>, + && common_reference_with>, invoke_result_t<_Fn&, iter_reference_t<_Iter>>>; template concept indirectly_regular_unary_invocable = indirectly_readable<_Iter> && copy_constructible<_Fn> - && regular_invocable<_Fn&, iter_value_t<_Iter>&> + && regular_invocable<_Fn&, __indirect_value_t<_Iter>> && regular_invocable<_Fn&, iter_reference_t<_Iter>> && regular_invocable<_Fn&, iter_common_reference_t<_Iter>> - && common_reference_with&>, + && common_reference_with>, invoke_result_t<_Fn&, iter_reference_t<_Iter>>>; template concept indirect_unary_predicate = indirectly_readable<_Iter> - && copy_constructible<_Fn> && predicate<_Fn&, iter_value_t<_Iter>&> + && copy_constructible<_Fn> && predicate<_Fn&, __indirect_value_t<_Iter>> && predicate<_Fn&, iter_reference_t<_Iter>> && predicate<_Fn&, iter_common_reference_t<_Iter>>; @@ -735,9 +747,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION concept indirect_binary_predicate = indirectly_readable<_I1> && indirectly_readable<_I2> && copy_constructible<_Fn> - && predicate<_Fn&, iter_value_t<_I1>&, iter_value_t<_I2>&> - && predicate<_Fn&, iter_value_t<_I1>&, iter_reference_t<_I2>> - && predicate<_Fn&, iter_reference_t<_I1>, iter_value_t<_I2>&> + && predicate<_Fn&, __indirect_value_t<_I1>, __indirect_value_t<_I2>> + && predicate<_Fn&, __indirect_value
[gcc r15-3038] c++: default targ eligibility refinement [PR101463]
https://gcc.gnu.org/g:5348e3cb9bc99d2ee4d7438b8eca5c92fff5b931 commit r15-3038-g5348e3cb9bc99d2ee4d7438b8eca5c92fff5b931 Author: Patrick Palka Date: Tue Aug 20 08:34:36 2024 -0400 c++: default targ eligibility refinement [PR101463] On Tue, 9 Jan 2024, Jason Merrill wrote: > On 1/5/24 15:01, Patrick Palka wrote[1]: > > Here during default template argument substitution we wrongly consider > > the (substituted) default arguments v and vt as value-dependent[1] > > which ultimately leads to deduction failure for the calls. > > > > The bogus value_dependent_expression_p result aside, I noticed > > type_unification_real during default targ substitution keeps track of > > whether all previous targs are known and non-dependent, as is the case > > for these calls. And in such cases it should be safe to avoid checking > > dependence of the substituted default targ and just assume it's not. > > This patch implements this optimization, which lets us accept both > > testcases by sidestepping the value_dependent_expression_p issue > > altogether. > > Hmm, maybe instead of substituting and asking if it's dependent, we should > specifically look for undeduced parameters. This patch implements this refinement, which incidentally fixes PR101463 just as well. [1]: https://gcc.gnu.org/pipermail/gcc-patches/2024-January/641957.html PR c++/101463 gcc/cp/ChangeLog: * pt.cc (type_unification_real): Directly look for undeduced parameters in the default argument instead of doing a trial substitution. gcc/testsuite/ChangeLog: * g++.dg/cpp1z/nontype6.C: New test. * g++.dg/cpp1z/nontype6a.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/pt.cc | 41 ++ gcc/testsuite/g++.dg/cpp1z/nontype6.C | 24 gcc/testsuite/g++.dg/cpp1z/nontype6a.C | 25 + 3 files changed, 71 insertions(+), 19 deletions(-) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index ea660a5a5c6..bc3ad5edcc5 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -23619,28 +23619,31 @@ type_unification_real (tree tparms, is important if the default argument contains something that might be instantiation-dependent like access (87480). */ processing_template_decl_sentinel s (!any_dependent_targs); - tree substed = NULL_TREE; - if (saw_undeduced == 1 && !any_dependent_targs) + + tree used_tparms = NULL_TREE; + if (saw_undeduced == 1) { - /* First instatiate in template context, in case we still -depend on undeduced template parameters. */ - ++processing_template_decl; - substed = tsubst_template_arg (arg, full_targs, complain, -NULL_TREE); - --processing_template_decl; - if (substed != error_mark_node - && !uses_template_parms (substed)) - /* We replaced all the tparms, substitute again out of - template context. */ - substed = NULL_TREE; + tree tparms_list = build_tree_list (size_int (1), tparms); + used_tparms = find_template_parameters (arg, tparms_list); + for (; used_tparms; used_tparms = TREE_CHAIN (used_tparms)) + { + int level, index; + template_parm_level_and_index (TREE_VALUE (used_tparms), +&level, &index); + if (TREE_VEC_ELT (targs, index) == NULL_TREE) + break; + } } - if (!substed) - substed = tsubst_template_arg (arg, full_targs, complain, - NULL_TREE); - if (!uses_template_parms (substed)) - arg = convert_template_argument (parm, substed, full_targs, -complain, i, NULL_TREE); + if (!used_tparms) + { + /* All template parameters within this default argument are +deduced, so we can use it. */ + arg = tsubst_template_arg (arg, full_targs, complain, +NULL_TREE); + arg = convert_template_argument (parm, arg, full_targs, + complain, i, NULL_TREE); + } else if (saw_undeduced == 1) arg = NULL_TREE; else if (!any_dependent_targs) diff --git a/gcc/testsuite/g++.dg/cpp1z/nontype6.C b/gcc/testsuite/g++.dg/cpp1z/non
[gcc r15-2938] c++: fix up cpp23/consteval-if3.C test [PR115583]
https://gcc.gnu.org/g:580fe7979f3c873eae885568d2c17c9e110670b4 commit r15-2938-g580fe7979f3c873eae885568d2c17c9e110670b4 Author: Patrick Palka Date: Thu Aug 15 14:38:47 2024 -0400 c++: fix up cpp23/consteval-if3.C test [PR115583] Compiling with optimizations is needed to trigger the bug fixed by r15-2369. PR c++/115583 gcc/testsuite/ChangeLog: * g++.dg/cpp23/consteval-if13.C: Compile with -O. Diff: --- gcc/testsuite/g++.dg/cpp23/consteval-if13.C | 1 + 1 file changed, 1 insertion(+) diff --git a/gcc/testsuite/g++.dg/cpp23/consteval-if13.C b/gcc/testsuite/g++.dg/cpp23/consteval-if13.C index b98bbc33d13..b10ec18b3c6 100644 --- a/gcc/testsuite/g++.dg/cpp23/consteval-if13.C +++ b/gcc/testsuite/g++.dg/cpp23/consteval-if13.C @@ -1,5 +1,6 @@ // PR c++/115583 // { dg-do compile { target c++23 } } +// { dg-additional-options -O } consteval int f(int i) { return i;
[gcc r14-10586] c++/coroutines: fix passing *this to promise type, again [PR116327]
https://gcc.gnu.org/g:63c51e09d160a44fdce1199e8efe9d293f773a2c commit r14-10586-g63c51e09d160a44fdce1199e8efe9d293f773a2c Author: Patrick Palka Date: Thu Aug 15 10:20:18 2024 -0400 c++/coroutines: fix passing *this to promise type, again [PR116327] In r15-2210 we got rid of the unnecessary cast to lvalue reference when passing *this to the promise type ctor, and as a drive-by change we also simplified the code to use cp_build_fold_indirect_ref. But it turns out cp_build_fold_indirect_ref does too much here, namely it has a shortcut for returning current_class_ref if the operand is current_class_ptr. The problem with that shortcut is current_class_ref might have gotten clobbered earlier if it appeared in the function body, since rewrite_param_uses walks and rewrites in-place all local variable uses to their corresponding frame copy. So later cp_build_fold_indirect_ref for *this will instead return the clobbered current_class_ref i.e. *frame_ptr->this, which doesn't make sense here since we're in the ramp function and not the actor function where frame_ptr is in scope. This patch fixes this by using the build_fold_indirect_ref instead of cp_build_fold_indirect_ref. PR c++/116327 PR c++/104981 PR c++/115550 gcc/cp/ChangeLog: * coroutines.cc (morph_fn_to_coro): Use build_fold_indirect_ref instead of cp_build_fold_indirect_ref. gcc/testsuite/ChangeLog: * g++.dg/coroutines/pr104981-preview-this.C: Improve coverage by adding a non-static data member use within the coroutine member function. * g++.dg/coroutines/pr116327-preview-this.C: New test. Reviewed-by: Jason Merrill (cherry picked from commit 303bed670af962c01b77a4f0c51de97f70e8167e) Diff: --- gcc/cp/coroutines.cc | 8 ++-- .../g++.dg/coroutines/pr104981-preview-this.C | 4 +++- .../g++.dg/coroutines/pr116327-preview-this.C | 22 ++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 71e64960c5a..f5cfc80ca39 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -4618,7 +4618,9 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) if (parm_i->this_ptr || parm_i->lambda_cobj) { /* We pass a reference to *this to the allocator lookup. */ - tree this_ref = cp_build_fold_indirect_ref (arg); + /* It's unsafe to use the cp_ version here since current_class_ref +might've gotten clobbered earlier during rewrite_param_uses. */ + tree this_ref = build_fold_indirect_ref (arg); vec_safe_push (args, this_ref); } else @@ -4838,7 +4840,9 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) if (parm.this_ptr || parm.lambda_cobj) { /* We pass a reference to *this to the param preview. */ - tree this_ref = cp_build_fold_indirect_ref (arg); + /* It's unsafe to use the cp_ version here since current_class_ref +might've gotten clobbered earlier during rewrite_param_uses. */ + tree this_ref = build_fold_indirect_ref (arg); vec_safe_push (promise_args, this_ref); } else if (parm.rv_ref) diff --git a/gcc/testsuite/g++.dg/coroutines/pr104981-preview-this.C b/gcc/testsuite/g++.dg/coroutines/pr104981-preview-this.C index 81eb963db4a..9f1e3970ce3 100644 --- a/gcc/testsuite/g++.dg/coroutines/pr104981-preview-this.C +++ b/gcc/testsuite/g++.dg/coroutines/pr104981-preview-this.C @@ -23,8 +23,10 @@ struct PromiseType { }; struct Derived : Base { + int m = 41; Result f() { - co_return 42; + ++m; + co_return m; } }; diff --git a/gcc/testsuite/g++.dg/coroutines/pr116327-preview-this.C b/gcc/testsuite/g++.dg/coroutines/pr116327-preview-this.C new file mode 100644 index 000..27b69a41392 --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/pr116327-preview-this.C @@ -0,0 +1,22 @@ +// PR c++/116327 - ICE in coroutine with parameter preview on lambda with captures + +#include + +struct coroutine{ + struct promise_type{ +promise_type(const auto &...){} +std::suspend_never initial_suspend(){ return {}; } +std::suspend_always final_suspend()noexcept{ return {}; } +void unhandled_exception(){} +coroutine get_return_object(){ return {}; } +void return_value(int)noexcept{} + }; +}; + +int main(){ + auto f = [a=0](auto) -> coroutine { +co_return 2; + }; + f(0); + return 0; +}
[gcc r15-2933] c++: c->B::m access resolved through current inst [PR116320]
https://gcc.gnu.org/g:484f139ccd3b631a777802e810a632678b42ffab commit r15-2933-g484f139ccd3b631a777802e810a632678b42ffab Author: Patrick Palka Date: Thu Aug 15 10:23:54 2024 -0400 c++: c->B::m access resolved through current inst [PR116320] Here when checking the access of (the injected-class-name) B in c->B::m at parse time, we notice its context B (now the type) is a base of the object type C, so we proceed to use C as the effective qualifying type. But this C is the dependent specialization not the primary template type, so it has empty TYPE_BINFO, which leads to a segfault later from perform_or_defer_access_check. The reason the DERIVED_FROM_P (B, C) test guarding this code path works despite C having empty TYPE_BINFO is because of its currently_open_class logic (added in r9-713-gd9338471b91bbe) which replaces a dependent specialization with the primary template type if we're inside it. So the safest fix seems to be to call currently_open_class in the caller as well. PR c++/116320 gcc/cp/ChangeLog: * semantics.cc (check_accessibility_of_qualified_id): Try currently_open_class when using the object type as the effective qualifying type. gcc/testsuite/ChangeLog: * g++.dg/template/access42.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/semantics.cc | 11 --- gcc/testsuite/g++.dg/template/access42.C | 17 + 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index e58612660c9..5ab2076b673 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -2516,9 +2516,14 @@ check_accessibility_of_qualified_id (tree decl, OBJECT_TYPE. */ && CLASS_TYPE_P (object_type) && DERIVED_FROM_P (scope, object_type)) -/* If we are processing a `->' or `.' expression, use the type of the - left-hand side. */ -qualifying_type = object_type; +{ + /* If we are processing a `->' or `.' expression, use the type of the +left-hand side. */ + if (tree open = currently_open_class (object_type)) + qualifying_type = open; + else + qualifying_type = object_type; +} else if (nested_name_specifier) { /* If the reference is to a non-static member of the diff --git a/gcc/testsuite/g++.dg/template/access42.C b/gcc/testsuite/g++.dg/template/access42.C new file mode 100644 index 000..f1dcbce80c2 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/access42.C @@ -0,0 +1,17 @@ +// PR c++/116320 +// { dg-do compile { target c++11 } } + +template struct C; +template using C_ptr = C*; + +struct B { int m; using B_typedef = B; }; + +template +struct C : B { + void f(C_ptr c) { +c->B::m; +c->B_typedef::m; + } +}; + +template struct C;
[gcc r15-2932] c++/coroutines: fix passing *this to promise type, again [PR116327]
https://gcc.gnu.org/g:303bed670af962c01b77a4f0c51de97f70e8167e commit r15-2932-g303bed670af962c01b77a4f0c51de97f70e8167e Author: Patrick Palka Date: Thu Aug 15 10:20:18 2024 -0400 c++/coroutines: fix passing *this to promise type, again [PR116327] In r15-2210 we got rid of the unnecessary cast to lvalue reference when passing *this to the promise type ctor, and as a drive-by change we also simplified the code to use cp_build_fold_indirect_ref. But it turns out cp_build_fold_indirect_ref does too much here, namely it has a shortcut for returning current_class_ref if the operand is current_class_ptr. The problem with that shortcut is current_class_ref might have gotten clobbered earlier if it appeared in the function body, since rewrite_param_uses walks and rewrites in-place all local variable uses to their corresponding frame copy. So later cp_build_fold_indirect_ref for *this will instead return the clobbered current_class_ref i.e. *frame_ptr->this, which doesn't make sense here since we're in the ramp function and not the actor function where frame_ptr is in scope. This patch fixes this by using the build_fold_indirect_ref instead of cp_build_fold_indirect_ref. PR c++/116327 PR c++/104981 PR c++/115550 gcc/cp/ChangeLog: * coroutines.cc (morph_fn_to_coro): Use build_fold_indirect_ref instead of cp_build_fold_indirect_ref. gcc/testsuite/ChangeLog: * g++.dg/coroutines/pr104981-preview-this.C: Improve coverage by adding a non-static data member use within the coroutine member function. * g++.dg/coroutines/pr116327-preview-this.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/coroutines.cc | 8 ++-- .../g++.dg/coroutines/pr104981-preview-this.C | 4 +++- .../g++.dg/coroutines/pr116327-preview-this.C | 22 ++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 145ec4b1d16..f7791cbfb9a 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -4850,7 +4850,9 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) if (parm_i->this_ptr || parm_i->lambda_cobj) { /* We pass a reference to *this to the allocator lookup. */ - tree this_ref = cp_build_fold_indirect_ref (arg); + /* It's unsafe to use the cp_ version here since current_class_ref +might've gotten clobbered earlier during rewrite_param_uses. */ + tree this_ref = build_fold_indirect_ref (arg); vec_safe_push (args, this_ref); } else @@ -5070,7 +5072,9 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) if (parm.this_ptr || parm.lambda_cobj) { /* We pass a reference to *this to the param preview. */ - tree this_ref = cp_build_fold_indirect_ref (arg); + /* It's unsafe to use the cp_ version here since current_class_ref +might've gotten clobbered earlier during rewrite_param_uses. */ + tree this_ref = build_fold_indirect_ref (arg); vec_safe_push (promise_args, this_ref); } else if (parm.rv_ref) diff --git a/gcc/testsuite/g++.dg/coroutines/pr104981-preview-this.C b/gcc/testsuite/g++.dg/coroutines/pr104981-preview-this.C index 81eb963db4a..9f1e3970ce3 100644 --- a/gcc/testsuite/g++.dg/coroutines/pr104981-preview-this.C +++ b/gcc/testsuite/g++.dg/coroutines/pr104981-preview-this.C @@ -23,8 +23,10 @@ struct PromiseType { }; struct Derived : Base { + int m = 41; Result f() { - co_return 42; + ++m; + co_return m; } }; diff --git a/gcc/testsuite/g++.dg/coroutines/pr116327-preview-this.C b/gcc/testsuite/g++.dg/coroutines/pr116327-preview-this.C new file mode 100644 index 000..27b69a41392 --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/pr116327-preview-this.C @@ -0,0 +1,22 @@ +// PR c++/116327 - ICE in coroutine with parameter preview on lambda with captures + +#include + +struct coroutine{ + struct promise_type{ +promise_type(const auto &...){} +std::suspend_never initial_suspend(){ return {}; } +std::suspend_always final_suspend()noexcept{ return {}; } +void unhandled_exception(){} +coroutine get_return_object(){ return {}; } +void return_value(int)noexcept{} + }; +}; + +int main(){ + auto f = [a=0](auto) -> coroutine { +co_return 2; + }; + f(0); + return 0; +}
[gcc r15-2864] c++: inherited CTAD fixes [PR116276]
https://gcc.gnu.org/g:8cc67b520968ca9a13fd96896522aa66e39a99e2 commit r15-2864-g8cc67b520968ca9a13fd96896522aa66e39a99e2 Author: Patrick Palka Date: Fri Aug 9 21:15:25 2024 -0400 c++: inherited CTAD fixes [PR116276] This implements the overlooked inherited vs non-inherited guide tiebreaker from P2582R1. This requires tracking inherited-ness of a guide, for which it seems natural to reuse the lang_decl_fn::context field which for a constructor tracks its inherited-ness. This patch also works around CLASSTYPE_CONSTRUCTORS not reliably returning all inherited constructors (due to some using-decl handling quirks in in push_class_level_binding) by iterating over TYPE_FIELDS instead. This patch also makes us recognize another written form of inherited constructor, 'using Base::Base::Base' whose USING_DECL_SCOPE is a TYPENAME_TYPE. PR c++/116276 gcc/cp/ChangeLog: * call.cc (joust): Implement P2582R1 inherited vs non-inherited guide tiebreaker. * cp-tree.h (lang_decl_fn::context): Document usage in deduction_guide_p FUNCTION_DECLs. (inherited_guide_p): Declare. * pt.cc (inherited_guide_p): Define. (set_inherited_guide_context): Define. (alias_ctad_tweaks): Use set_inherited_guide_context. (inherited_ctad_tweaks): Recognize some inherited constructors whose scope is a TYPENAME_TYPE. (ctor_deduction_guides_for): For C++23 inherited CTAD, iterate over TYPE_FIELDS instead of CLASSTYPE_CONSTRUCTORS to recognize all inherited constructors. gcc/testsuite/ChangeLog: * g++.dg/cpp23/class-deduction-inherited4.C: Remove an xfail. * g++.dg/cpp23/class-deduction-inherited5.C: New test. * g++.dg/cpp23/class-deduction-inherited6.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/call.cc | 27 - gcc/cp/cp-tree.h | 8 ++-- gcc/cp/pt.cc | 43 .../g++.dg/cpp23/class-deduction-inherited4.C | 4 +- .../g++.dg/cpp23/class-deduction-inherited5.C | 25 .../g++.dg/cpp23/class-deduction-inherited6.C | 46 ++ 6 files changed, 139 insertions(+), 14 deletions(-) diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 67d38e2a78a7..94015db4e650 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -13262,10 +13262,35 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn, else if (cand2->rewritten ()) return 1; - /* F1 is generated from a deduction-guide (13.3.1.8) and F2 is not */ if (deduction_guide_p (cand1->fn)) { gcc_assert (deduction_guide_p (cand2->fn)); + + /* F1 and F2 are generated from class template argument deduction for a +class D, and F2 is generated from inheriting constructors from a base +class of D while F1 is not, and for each explicit function argument, +the corresponding parameters of F1 and F2 are either both ellipses or +have the same type. */ + bool inherited1 = inherited_guide_p (cand1->fn); + bool inherited2 = inherited_guide_p (cand2->fn); + if (int diff = inherited2 - inherited1) + { + for (i = 0; i < len; ++i) + { + conversion *t1 = cand1->convs[i + off1]; + conversion *t2 = cand2->convs[i + off2]; + /* ??? It seems the ellipses part of this tiebreaker isn't +needed since a mismatch should have broken the tie earlier +during ICS comparison. */ + gcc_checking_assert (t1->ellipsis_p == t2->ellipsis_p); + if (!same_type_p (t1->type, t2->type)) + break; + } + if (i == len) + return diff; + } + + /* F1 is generated from a deduction-guide (13.3.1.8) and F2 is not */ /* We distinguish between candidates from an explicit deduction guide and candidates built from a constructor based on DECL_ARTIFICIAL. */ int art1 = DECL_ARTIFICIAL (cand1->fn); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 5807f4e0edb3..a53fbcb43ec4 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -2972,9 +2972,10 @@ struct GTY(()) lang_decl_fn { this pointer and result pointer adjusting thunks are chained here. This pointer thunks to return pointer thunks will be chained on the return pointer thunk. - For a DECL_CONSTUCTOR_P FUNCTION_DECL, this is the base from - whence we inherit. Otherwise, it is the class in which a - (namespace-scope) friend is defined (if any). */ + For a DECL_CONSTRUCTOR_P or deduction_guide_p FUNCTION_DECL, + this is the base from whence we inherit. + Otherwise, it is the class in whi
[gcc r15-2863] c++: DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P tweaks
https://gcc.gnu.org/g:70da0ca1239faefa6dec0494a85e998eae34beff commit r15-2863-g70da0ca1239faefa6dec0494a85e998eae34beff Author: Patrick Palka Date: Fri Aug 9 21:13:05 2024 -0400 c++: DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P tweaks DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P templates can only appear as part of a template friend declaration, and in turn get partially instantiated only from tsubst_friend_function or tsubst_friend_class. So rather than having tsubst_template_decl clear the flag, let's leave it up to the tsubst friend routines to clear it so that template friend handling stays localized (note that tsubst_friend_function was already clearing it). Also the template depth comparison test within tsubst_friend_function is equivalent to DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P since such templates belong to the class context (and so always have more levels than the context), and conversely and it isn't possible to directly refer to an existing template that has more levels than the class context. gcc/cp/ChangeLog: * pt.cc (tsubst_friend_class): Simplify depth comparison test in the redeclaration code path to DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P. Clear the flag after partial instantiation here ... (tsubst_template_decl): ... instead of here. Reviewed-by: Jason Merrill Diff: --- gcc/cp/pt.cc | 6 ++ 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 1dde7d167fd6..c1d4cdc7e259 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -11772,8 +11772,7 @@ tsubst_friend_class (tree friend_tmpl, tree args) compatible with the attachment of the friend template. */ module_may_redeclare (tmpl, friend_tmpl); - if (TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (friend_tmpl)) - > TMPL_ARGS_DEPTH (args)) + if (DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (friend_tmpl)) { tree parms = tsubst_template_parms (DECL_TEMPLATE_PARMS (friend_tmpl), args, tf_warning_or_error); @@ -11815,6 +11814,7 @@ tsubst_friend_class (tree friend_tmpl, tree args) CLASSTYPE_USE_TEMPLATE (TREE_TYPE (tmpl)) = 0; CLASSTYPE_TI_ARGS (TREE_TYPE (tmpl)) = INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (TREE_TYPE (tmpl))); + DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (tmpl) = false; /* Substitute into and set the constraints on the new declaration. */ if (tree ci = get_constraints (friend_tmpl)) @@ -15044,8 +15044,6 @@ tsubst_template_decl (tree t, tree args, tsubst_flags_t complain, if (PRIMARY_TEMPLATE_P (t)) DECL_PRIMARY_TEMPLATE (r) = r; - DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (r) = false; - if (!lambda_fntype && !class_p) { /* Record this non-type partial instantiation. */
[gcc r15-2862] c++: clean up cp_identifier_kind checks
https://gcc.gnu.org/g:cf7feae517d4819cd33ef6bb123217ea39845fd1 commit r15-2862-gcf7feae517d4819cd33ef6bb123217ea39845fd1 Author: Patrick Palka Date: Fri Aug 9 21:13:03 2024 -0400 c++: clean up cp_identifier_kind checks The predicates for checking an IDENTIFIER node's cp_identifier_kind currently directly test the three flag bits that encode the kind. This patch instead makes the checks first reconstruct the cp_identifier_kind in its entirety and then compare that. gcc/cp/ChangeLog: * cp-tree.h (get_identifier_kind): Define. (IDENTIFIER_KEYWORD_P): Redefine in terms of get_identifier_kind. (IDENTIFIER_CDTOR_P): Likewise. (IDENTIFIER_CTOR_P): Likewise. (IDENTIFIER_DTOR_P): Likewise. (IDENTIFIER_ANY_OP_P): Likewise. (IDENTIFIER_OVL_OP_P): Likewise. (IDENTIFIER_ASSIGN_OP_P): Likewise. (IDENTIFIER_CONV_OP_P): Likewise. (IDENTIFIER_TRAIT_P): Likewise. * parser.cc (cp_lexer_peek_trait): Mark IDENTIFIER_TRAIT_P check UNLIKELY. Reviewed-by: Jason Merrill Diff: --- gcc/cp/cp-tree.h | 41 + gcc/cp/parser.cc | 3 ++- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index b1693051231b..5807f4e0edb3 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1255,56 +1255,57 @@ enum cp_identifier_kind { #define IDENTIFIER_VIRTUAL_P(NODE) \ TREE_LANG_FLAG_5 (IDENTIFIER_NODE_CHECK (NODE)) +/* Return the cp_identifier_kind of the given IDENTIFIER node ID. */ + +ATTRIBUTE_PURE inline cp_identifier_kind +get_identifier_kind (tree id) +{ + unsigned bit0 = IDENTIFIER_KIND_BIT_0 (id); + unsigned bit1 = IDENTIFIER_KIND_BIT_1 (id); + unsigned bit2 = IDENTIFIER_KIND_BIT_2 (id); + return cp_identifier_kind ((bit2 << 2) | (bit1 << 1) | bit0); +} + /* True if this identifier is a reserved word. C_RID_CODE (node) is then the RID_* value of the keyword. Value 1. */ #define IDENTIFIER_KEYWORD_P(NODE) \ - ((!IDENTIFIER_KIND_BIT_2 (NODE)) \ - & (!IDENTIFIER_KIND_BIT_1 (NODE)) \ - & IDENTIFIER_KIND_BIT_0 (NODE)) + (get_identifier_kind (NODE) == cik_keyword) /* True if this identifier is the name of a constructor or destructor. Value 2 or 3. */ #define IDENTIFIER_CDTOR_P(NODE) \ - ((!IDENTIFIER_KIND_BIT_2 (NODE)) \ - & IDENTIFIER_KIND_BIT_1 (NODE)) + (IDENTIFIER_CTOR_P (NODE) || IDENTIFIER_DTOR_P (NODE)) /* True if this identifier is the name of a constructor. Value 2. */ #define IDENTIFIER_CTOR_P(NODE)\ - (IDENTIFIER_CDTOR_P(NODE)\ -& (!IDENTIFIER_KIND_BIT_0 (NODE))) + (get_identifier_kind (NODE) == cik_ctor) /* True if this identifier is the name of a destructor. Value 3. */ #define IDENTIFIER_DTOR_P(NODE)\ - (IDENTIFIER_CDTOR_P(NODE)\ -& IDENTIFIER_KIND_BIT_0 (NODE)) + (get_identifier_kind (NODE) == cik_dtor) /* True if this identifier is for any operator name (including conversions). Value 4, 5, or 6. */ #define IDENTIFIER_ANY_OP_P(NODE) \ - (IDENTIFIER_KIND_BIT_2 (NODE) && !IDENTIFIER_TRAIT_P (NODE)) + (IDENTIFIER_OVL_OP_P (NODE) || IDENTIFIER_CONV_OP_P (NODE)) /* True if this identifier is for an overloaded operator. Values 4, 5. */ #define IDENTIFIER_OVL_OP_P(NODE) \ - (IDENTIFIER_ANY_OP_P (NODE) \ - & (!IDENTIFIER_KIND_BIT_1 (NODE))) + (get_identifier_kind (NODE) == cik_simple_op \ + || get_identifier_kind (NODE) == cik_assign_op) /* True if this identifier is for any assignment. Values 5. */ #define IDENTIFIER_ASSIGN_OP_P(NODE) \ - (IDENTIFIER_OVL_OP_P (NODE) \ - & IDENTIFIER_KIND_BIT_0 (NODE)) + (get_identifier_kind (NODE) == cik_assign_op) /* True if this identifier is the name of a type-conversion operator. Value 6. */ #define IDENTIFIER_CONV_OP_P(NODE) \ - (IDENTIFIER_ANY_OP_P (NODE) \ - & IDENTIFIER_KIND_BIT_1 (NODE) \ - & (!IDENTIFIER_KIND_BIT_0 (NODE))) + (get_identifier_kind (NODE) == cik_conv_op) /* True if this identifier is the name of a built-in trait. */ #define IDENTIFIER_TRAIT_P(NODE) \ - (IDENTIFIER_KIND_BIT_0 (NODE)\ - & IDENTIFIER_KIND_BIT_1 (NODE) \ - & IDENTIFIER_KIND_BIT_2 (NODE)) + (get_identifier_kind (NODE) == cik_trait) /* True if this identifier is a new or delete operator. */ #define IDENTIFIER_NEWDEL_OP_P(NODE) \ diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 82f3903838e2..852efe45076f 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -1198,7 +1198,8 @@ static const cp_trait * cp_lexer_peek_trait (cp_lexer *lexer) { const cp_token *token1 = cp_lexer_peek_toke
[gcc r15-2849] c-family: regenerate c.opt.urls
https://gcc.gnu.org/g:f91f7201ac0ab6805b517341c0ba7a0c48b7971c commit r15-2849-gf91f7201ac0ab6805b517341c0ba7a0c48b7971c Author: Patrick Palka Date: Fri Aug 9 09:35:17 2024 -0400 c-family: regenerate c.opt.urls The addition of -Wtemplate-body in r15-2774-g596d1ed9d40b10 means we need to regenerate c.opt.urls. gcc/c-family/ChangeLog: * c.opt.urls: Regenerate. Diff: --- gcc/c-family/c.opt.urls | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gcc/c-family/c.opt.urls b/gcc/c-family/c.opt.urls index df5f58a1eeed..e40b8e5c3a0d 100644 --- a/gcc/c-family/c.opt.urls +++ b/gcc/c-family/c.opt.urls @@ -837,6 +837,9 @@ UrlSuffix(gcc/C_002b_002b-Dialect-Options.html#index-Wno-templates) Wtautological-compare UrlSuffix(gcc/Warning-Options.html#index-Wno-tautological-compare) +Wtemplate-body +UrlSuffix(gcc/C_002b_002b-Dialect-Options.html#index-Wno-template-body) + Wtemplate-id-cdtor UrlSuffix(gcc/C_002b_002b-Dialect-Options.html#index-Wno-template-id-cdtor)
[gcc r15-2848] c++: add fixed testcase [PR116289]
https://gcc.gnu.org/g:4aa89badc8c16637e0d9a39a08da7d18e209631b commit r15-2848-g4aa89badc8c16637e0d9a39a08da7d18e209631b Author: Patrick Palka Date: Fri Aug 9 09:16:45 2024 -0400 c++: add fixed testcase [PR116289] Fully fixed since r14-6724-gfced59166f95e9. PR c++/116289 PR c++/113063 gcc/testsuite/ChangeLog: * g++.dg/cpp2a/spaceship-synth16a.C: New test. Diff: --- gcc/testsuite/g++.dg/cpp2a/spaceship-synth16a.C | 16 1 file changed, 16 insertions(+) diff --git a/gcc/testsuite/g++.dg/cpp2a/spaceship-synth16a.C b/gcc/testsuite/g++.dg/cpp2a/spaceship-synth16a.C new file mode 100644 index ..68388a680b20 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/spaceship-synth16a.C @@ -0,0 +1,16 @@ +// PR c++/116289 +// PR c++/113063 +// { dg-do link { target c++20 } } +// A version of spaceship-synth16.C where the local class isn't empty. + +#include + +int main() { + struct X { +int m = 0; +auto operator<=>(const X&) const = default; + }; + X x; + static_assert(noexcept(x <=> x)); + x <=> x; +}
[gcc r13-8967] c++: local class memfn synth from uneval context [PR113063]
https://gcc.gnu.org/g:12ba140ee93adc56a3426f0c6c05f4d6c6a3d08e commit r13-8967-g12ba140ee93adc56a3426f0c6c05f4d6c6a3d08e Author: Patrick Palka Date: Fri Aug 9 09:03:14 2024 -0400 c++: local class memfn synth from uneval context [PR113063] This is essentially a narrow backport of r14-6724-gfced59166f95e9 that instead uses cp_evaluated instead of maybe_push_to_top_level to clear cp_unevaluated_operand within synthesize_method, which turns out is sufficient to also fix the 13.3 regression PR116289 (whose immediate trigger is a change backport r13-7739-gd919309679334a). PR c++/113063 PR c++/116289 gcc/cp/ChangeLog: * method.cc (synthesize_method): Use cp_evaluated. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/spaceship-synth16.C: New test. * g++.dg/cpp2a/spaceship-synth16a.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/method.cc| 1 + gcc/testsuite/g++.dg/cpp2a/spaceship-synth16.C | 13 + gcc/testsuite/g++.dg/cpp2a/spaceship-synth16a.C | 16 3 files changed, 30 insertions(+) diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc index 9fd5567e97fd..09ea6d732dfc 100644 --- a/gcc/cp/method.cc +++ b/gcc/cp/method.cc @@ -1797,6 +1797,7 @@ synthesize_method (tree fndecl) it now. */ push_deferring_access_checks (dk_no_deferred); + cp_evaluated ev; if (! context) push_to_top_level (); else if (nested) diff --git a/gcc/testsuite/g++.dg/cpp2a/spaceship-synth16.C b/gcc/testsuite/g++.dg/cpp2a/spaceship-synth16.C new file mode 100644 index ..37a183de0f5b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/spaceship-synth16.C @@ -0,0 +1,13 @@ +// PR c++/113063 +// { dg-do link { target c++20 } } + +#include + +int main() { + struct X { +auto operator<=>(const X&) const = default; + }; + X x; + static_assert(noexcept(x <=> x)); + x <=> x; +} diff --git a/gcc/testsuite/g++.dg/cpp2a/spaceship-synth16a.C b/gcc/testsuite/g++.dg/cpp2a/spaceship-synth16a.C new file mode 100644 index ..68388a680b20 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/spaceship-synth16a.C @@ -0,0 +1,16 @@ +// PR c++/116289 +// PR c++/113063 +// { dg-do link { target c++20 } } +// A version of spaceship-synth16.C where the local class isn't empty. + +#include + +int main() { + struct X { +int m = 0; +auto operator<=>(const X&) const = default; + }; + X x; + static_assert(noexcept(x <=> x)); + x <=> x; +}
[gcc r15-2802] c++: erroneous partial spec vs primary tmpl [PR116064]
https://gcc.gnu.org/g:d1fc9816df81e953308428641685d6ec6d84c9ac commit r15-2802-gd1fc9816df81e953308428641685d6ec6d84c9ac Author: Patrick Palka Date: Wed Aug 7 14:28:26 2024 -0400 c++: erroneous partial spec vs primary tmpl [PR116064] When a partial specialization is deemed erroneous at parse time, we currently flag the primary template as erroneous instead. Later at instantiation time we check if the primary template is erroneous rather than the selected partial specialization, so at least we're consistent. But it's better not to conflate a partial specialization with the primary template since they're instantiated independenty. This avoids rejecting the instantiation of A in the below testcase. PR c++/116064 gcc/cp/ChangeLog: * error.cc (get_current_template): If the current scope is a partial specialization, return it instead of the primary template. * pt.cc (instantiate_class_template): Pass the partial specialization if any to maybe_diagnose_erroneous_template instead of the primary template. gcc/testsuite/ChangeLog: * g++.dg/template/permissive-error2.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/error.cc | 6 +- gcc/cp/pt.cc | 2 +- gcc/testsuite/g++.dg/template/permissive-error2.C | 15 +++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc index 6c22ff55b463..879e5a115cfe 100644 --- a/gcc/cp/error.cc +++ b/gcc/cp/error.cc @@ -173,7 +173,11 @@ get_current_template () { if (scope_chain && in_template_context && !current_instantiation ()) if (tree ti = get_template_info (current_scope ())) - return TI_TEMPLATE (ti); + { + if (PRIMARY_TEMPLATE_P (TI_TEMPLATE (ti)) && TI_PARTIAL_INFO (ti)) + ti = TI_PARTIAL_INFO (ti); + return TI_TEMPLATE (ti); + } return NULL_TREE; } diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 542962b6387f..3e55d5c0fea5 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -12381,7 +12381,7 @@ instantiate_class_template (tree type) if (! push_tinst_level (type)) return type; - maybe_diagnose_erroneous_template (templ); + maybe_diagnose_erroneous_template (t ? TI_TEMPLATE (t) : templ); int saved_unevaluated_operand = cp_unevaluated_operand; int saved_inhibit_evaluation_warnings = c_inhibit_evaluation_warnings; diff --git a/gcc/testsuite/g++.dg/template/permissive-error2.C b/gcc/testsuite/g++.dg/template/permissive-error2.C new file mode 100644 index ..692e7c7ac82c --- /dev/null +++ b/gcc/testsuite/g++.dg/template/permissive-error2.C @@ -0,0 +1,15 @@ +// PR c++/116064 +// { dg-additional-options -fpermissive } +// Verify we correctly mark a partial specialization as erroneous +// instead its primary template. + +template +struct A { }; + +template +struct A { // { dg-error "instantiating erroneous template" } + void f(typename A::type); // { dg-warning "does not name a type" } +}; + +A a; // { dg-bogus "" } +A b; // { dg-message "required from here" }
[gcc r15-2774] c++: permit errors inside uninstantiated templates [PR116064]
https://gcc.gnu.org/g:596d1ed9d40b1081fcc6c6161a0135952829b88f commit r15-2774-g596d1ed9d40b1081fcc6c6161a0135952829b88f Author: Patrick Palka Date: Tue Aug 6 20:54:03 2024 -0400 c++: permit errors inside uninstantiated templates [PR116064] In recent versions of GCC we've been diagnosing more and more kinds of errors inside a template ahead of time. This is a largely good thing because it catches bugs, typos, dead code etc sooner. But if the template never gets instantiated then such errors are harmless and can be inconvenient to work around if say the code in question is third party and in maintenance mode. So it'd be handy to be able to prevent these template errors from rendering the entire TU uncompilable. (Note that such code is "ill-formed no diagnostic required" according the standard.) To that end this patch turns any errors issued within a template into permerrors associated with a new -Wtemplate-body flag so that they can be downgraded via e.g. -fpermissive or -Wno-error=template-body. If the template containing a downgraded error later needs to be instantiated, we'll issue an error then. But if the template never gets instantiated then the downgraded error won't affect validity of the rest of the TU. This is implemented via a diagnostic hook that gets called for each diagnostic, and which adjusts an error diagnostic appropriately if we detect it's occurring from a template context, and additionally flags the template as erroneous. For example the new testcase permissive-error1a.C gives: gcc/testsuite/g++.dg/template/permissive-error1a.C: In function 'void f()': gcc/testsuite/g++.dg/template/permissive-error1a.C:7:5: warning: increment of read-only variable 'n' [-Wtemplate-body] 7 | ++n; | ^ ... gcc/testsuite/g++.dg/template/permissive-error1a.C: In instantiation of 'void f() [with T = int]': gcc/testsuite/g++.dg/template/permissive-error1a.C:26:9: required from here 26 | f(); | ~~^~ gcc/testsuite/g++.dg/template/permissive-error1a.C:5:6: error: instantiating erroneous template 5 | void f() { | ^ gcc/testsuite/g++.dg/template/permissive-error1a.C:7:5: note: first error appeared here 7 | ++n; // { | ^ ... PR c++/116064 gcc/c-family/ChangeLog: * c.opt (Wtemplate-body): New warning. gcc/cp/ChangeLog: * cp-tree.h (erroneous_templates_t): Declare. (erroneous_templates): Declare. (cp_seen_error): Declare. (seen_error): #define to cp_seen_error. * error.cc (get_current_template): Define. (relaxed_template_errors): Define. (cp_adjust_diagnostic_info): Define. (cp_seen_error): Define. (cxx_initialize_diagnostics): Set diagnostic_context::m_adjust_diagnostic_info. * module.cc (finish_module_processing): Don't write the module if it contains an erroneous template. * pt.cc (maybe_diagnose_erroneous_template): Define. (instantiate_class_template): Call it. (instantiate_decl): Likewise. gcc/ChangeLog: * diagnostic.cc (diagnostic_context::initialize): Set m_adjust_diagnostic_info. (diagnostic_context::report_diagnostic): Call m_adjust_diagnostic_info. * diagnostic.h (diagnostic_context::m_adjust_diagnostic_info): New data member. * doc/invoke.texi (-Wno-template-body): Document. (-fpermissive): Mention -Wtemplate-body. gcc/testsuite/ChangeLog: * g++.dg/ext/typedef-init.C: Downgrade error inside template to warning due to -fpermissive. * g++.dg/pr84492.C: Likewise. * g++.old-deja/g++.pt/crash51.C: Remove unneeded dg-options. * g++.dg/template/permissive-error1.C: New test. * g++.dg/template/permissive-error1a.C: New test. * g++.dg/template/permissive-error1b.C: New test. * g++.dg/template/permissive-error1c.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/c-family/c.opt | 4 ++ gcc/cp/cp-tree.h | 7 +++ gcc/cp/error.cc| 67 ++ gcc/cp/module.cc | 5 +- gcc/cp/pt.cc | 22 +++ gcc/diagnostic.cc | 4 ++ gcc/diagnostic.h | 4 ++ gcc/doc/invoke.texi| 12 +++- gcc/testsuite/g++.dg/ext/typedef-init.C| 2 +- gcc/testsuite/g++.dg/pr84492.C | 4 +- gcc/testsuite/g++.dg/templa
[gcc r15-2756] c++: fold calls to std::forward_like [PR96780]
https://gcc.gnu.org/g:180625ae72b3f733813a360fae4f0d6ce79eccdc commit r15-2756-g180625ae72b3f733813a360fae4f0d6ce79eccdc Author: Patrick Palka Date: Tue Aug 6 11:51:45 2024 -0400 c++: fold calls to std::forward_like [PR96780] This extends our folding of cast-like standard library functions to also include C++23's std::forward_like. PR c++/96780 gcc/cp/ChangeLog: * cp-gimplify.cc (cp_fold) : Fold calls to std::forward_like as well. gcc/testsuite/ChangeLog: * g++.dg/opt/pr96780.C: Also test std::forward_like folding. Reviewed-by: Marek Polacek Reviewed-by: Jason Merrill Diff: --- gcc/cp/cp-gimplify.cc | 1 + gcc/testsuite/g++.dg/opt/pr96780.C | 5 + 2 files changed, 6 insertions(+) diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc index b88c3b7f370b..0c589eeaaec4 100644 --- a/gcc/cp/cp-gimplify.cc +++ b/gcc/cp/cp-gimplify.cc @@ -3313,6 +3313,7 @@ cp_fold (tree x, fold_flags_t flags) && DECL_NAME (callee) != NULL_TREE && (id_equal (DECL_NAME (callee), "move") || id_equal (DECL_NAME (callee), "forward") + || id_equal (DECL_NAME (callee), "forward_like") || id_equal (DECL_NAME (callee), "addressof") /* This addressof equivalent is used heavily in libstdc++. */ || id_equal (DECL_NAME (callee), "__addressof") diff --git a/gcc/testsuite/g++.dg/opt/pr96780.C b/gcc/testsuite/g++.dg/opt/pr96780.C index 61e11855eeb3..a29cda8b836e 100644 --- a/gcc/testsuite/g++.dg/opt/pr96780.C +++ b/gcc/testsuite/g++.dg/opt/pr96780.C @@ -29,6 +29,10 @@ void f() { auto&& x11 = std::as_const(a); auto&& x12 = std::as_const(ca); #endif +#if __cpp_lib_forward_like + auto&& x13 = std::forward_like(a); + auto&& x14 = std::forward_like(ca); +#endif } // { dg-final { scan-tree-dump-not "= std::move" "gimple" } } @@ -36,3 +40,4 @@ void f() { // { dg-final { scan-tree-dump-not "= std::addressof" "gimple" } } // { dg-final { scan-tree-dump-not "= std::__addressof" "gimple" } } // { dg-final { scan-tree-dump-not "= std::as_const" "gimple" } } +// { dg-final { scan-tree-dump-not "= std::forward_like" "gimple" } }
[gcc r14-10548] c++: generic lambda in default template argument [PR88313]
https://gcc.gnu.org/g:81db6857686c2d7932949afb948419a575bc0b3f commit r14-10548-g81db6857686c2d7932949afb948419a575bc0b3f Author: Patrick Palka Date: Mon Jul 29 16:37:19 2024 -0400 c++: generic lambda in default template argument [PR88313] Here we're rejecting the generic lambda inside the default template argument ultimately because auto_is_implicit_function_template_parm_p doesn't get set during parsing of the lambda's parameter list, due to the !processing_template_parmlist restriction. But when parsing a lambda parameter list we should always set that flag regardless of where the lambda appears. This patch makes sure of this via a local lambda_p flag. PR c++/88313 gcc/cp/ChangeLog: * parser.cc (cp_parser_lambda_declarator_opt): Pass lambda_p=true to cp_parser_parameter_declaration_clause. (cp_parser_direct_declarator): Pass lambda_p=false to to cp_parser_parameter_declaration_clause. (cp_parser_parameter_declaration_clause): Add bool lambda_p parameter. Consider lambda_p instead of current_class_type when setting parser->auto_is_implicit_function_template_parm_p. Don't consider processing_template_parmlist. (cp_parser_requirement_parameter_list): Pass lambda_p=false to cp_parser_parameter_declaration_clause. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/lambda-targ6.C: New test. Reviewed-by: Jason Merrill (cherry picked from commit 72a7ab891ae0061841c4eb641ef6ab7719bf0369) Diff: --- gcc/cp/parser.cc | 34 ++- gcc/testsuite/g++.dg/cpp2a/lambda-targ6.C | 15 ++ 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 7e81c1010c45..00cf128522a7 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -2598,7 +2598,7 @@ static tree cp_parser_type_id_1 static void cp_parser_type_specifier_seq (cp_parser *, cp_parser_flags, bool, bool, cp_decl_specifier_seq *); static tree cp_parser_parameter_declaration_clause - (cp_parser *, cp_parser_flags); + (cp_parser *, cp_parser_flags, bool); static tree cp_parser_parameter_declaration_list (cp_parser *, cp_parser_flags, auto_vec *); static cp_parameter_declarator *cp_parser_parameter_declaration @@ -11867,7 +11867,7 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) /* Parse parameters. */ param_list = cp_parser_parameter_declaration_clause - (parser, CP_PARSER_FLAGS_TYPENAME_OPTIONAL); + (parser, CP_PARSER_FLAGS_TYPENAME_OPTIONAL, /*lambda_p=*/true); /* Default arguments shall not be specified in the parameter-declaration-clause of a lambda-declarator. */ @@ -23903,7 +23903,8 @@ cp_parser_direct_declarator (cp_parser* parser, /* Parse the parameter-declaration-clause. */ params - = cp_parser_parameter_declaration_clause (parser, flags); + = cp_parser_parameter_declaration_clause (parser, flags, + /*lambda_p=*/false); const location_t parens_end = cp_lexer_peek_token (parser->lexer)->location; @@ -25252,13 +25253,17 @@ function_being_declared_is_template_p (cp_parser* parser) The parser flags FLAGS is used to control type-specifier parsing. + LAMBDA_P is true if this is the parameter-declaration-clause of + a lambda-declarator. + Returns a representation for the parameter declarations. A return value of NULL indicates a parameter-declaration-clause consisting only of an ellipsis. */ static tree cp_parser_parameter_declaration_clause (cp_parser* parser, - cp_parser_flags flags) + cp_parser_flags flags, + bool lambda_p) { tree parameters; cp_token *token; @@ -25267,15 +25272,15 @@ cp_parser_parameter_declaration_clause (cp_parser* parser, auto cleanup = make_temp_override (parser->auto_is_implicit_function_template_parm_p); - if (!processing_specialization - && !processing_template_parmlist - && !processing_explicit_instantiation - /* default_arg_ok_p tracks whether this is a parameter-clause for an - actual function or a random abstract declarator. */ - && parser->default_arg_ok_p) -if (!current_function_decl - || (current_class_type && LAMBDA_TYPE_P (current_class_type))) - parser->auto_is_implicit_function_template_parm_p = true; + if (lambda_p + || (!processing_specialization + && !processing_template_parmlist + && !processing_explicit_instantiation + /* default_arg_ok_p tracks whether this is a parameter-clause for an +actual function or a
[gcc r14-10547] c++: alias of alias tmpl with dependent attrs [PR115897]
https://gcc.gnu.org/g:37e54ffd2a0a18eec23c90bdf438c01a0393328a commit r14-10547-g37e54ffd2a0a18eec23c90bdf438c01a0393328a Author: Patrick Palka Date: Thu Jul 25 19:00:23 2024 -0400 c++: alias of alias tmpl with dependent attrs [PR115897] As a follow-up to r15-2047-g7954bb4fcb6fa8, we also need to consider dependent attributes when recursing into a non-template alias that names a dependent alias template specialization (and so STF_STRIP_DEPENDENT is set), otherwise in the first testcase below we undesirably strip B all the way to T instead of to A. We also need to move the typedef recursion case of strip_typedefs up to get checked before the compound type recursion cases. Otherwise for C below (which ultimately aliases T*) we end up stripping it to T* instead of to A because the POINTER_TYPE recursion dominates the typedef recursion. It also means we issue an unexpected extra error in the third testcase below. Ideally we would also want to consider dependent attributes on non-template aliases, so that we accept the second testcase below, but making that work correctly would require broader changes to e.g. structural_comptypes. PR c++/115897 gcc/cp/ChangeLog: * tree.cc (strip_typedefs): Move up the typedef recursion case. Never strip a dependent alias template-id that has dependent attributes. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/alias-decl-78.C: New test. * g++.dg/cpp0x/alias-decl-79.C: New test. * g++.dg/cpp0x/alias-decl-pr92206-1a.C: New test. Reviewed-by: Jason Merrill (cherry picked from commit 9bcad238837e2100978cd839c343c488f72e1d4a) Diff: --- gcc/cp/tree.cc | 51 -- gcc/testsuite/g++.dg/cpp0x/alias-decl-78.C | 34 +++ gcc/testsuite/g++.dg/cpp0x/alias-decl-79.C | 37 gcc/testsuite/g++.dg/cpp0x/alias-decl-pr92206-1a.C | 10 + 4 files changed, 110 insertions(+), 22 deletions(-) diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc index 41fdf67f7574..d90244609c8a 100644 --- a/gcc/cp/tree.cc +++ b/gcc/cp/tree.cc @@ -1607,11 +1607,32 @@ strip_typedefs (tree t, bool *remove_attributes /* = NULL */, if (t == TYPE_CANONICAL (t)) return t; - if (!(flags & STF_STRIP_DEPENDENT) - && dependent_alias_template_spec_p (t, nt_opaque)) -/* DR 1558: However, if the template-id is dependent, subsequent - template argument substitution still applies to the template-id. */ -return t; + if (typedef_variant_p (t)) +{ + if ((flags & STF_USER_VISIBLE) + && !user_facing_original_type_p (t)) + return t; + + if (alias_template_specialization_p (t, nt_opaque)) + { + if (dependent_alias_template_spec_p (t, nt_opaque) + && (!(flags & STF_STRIP_DEPENDENT) + || any_dependent_type_attributes_p (DECL_ATTRIBUTES + (TYPE_NAME (t) + /* DR 1558: However, if the template-id is dependent, subsequent + template argument substitution still applies to the template-id. */ + return t; + } + else + /* If T is a non-template alias or typedef, we can assume that + instantiating its definition will hit any substitution failure, + so we don't need to retain it here as well. */ + flags |= STF_STRIP_DEPENDENT; + + result = strip_typedefs (DECL_ORIGINAL_TYPE (TYPE_NAME (t)), + remove_attributes, flags); + goto stripped; +} switch (TREE_CODE (t)) { @@ -1805,23 +1826,9 @@ strip_typedefs (tree t, bool *remove_attributes /* = NULL */, } if (!result) -{ - if (typedef_variant_p (t)) - { - if ((flags & STF_USER_VISIBLE) - && !user_facing_original_type_p (t)) - return t; - /* If T is a non-template alias or typedef, we can assume that -instantiating its definition will hit any substitution failure, -so we don't need to retain it here as well. */ - if (!alias_template_specialization_p (t, nt_opaque)) - flags |= STF_STRIP_DEPENDENT; - result = strip_typedefs (DECL_ORIGINAL_TYPE (TYPE_NAME (t)), - remove_attributes, flags); - } - else - result = TYPE_MAIN_VARIANT (t); -} +result = TYPE_MAIN_VARIANT (t); + +stripped: /*gcc_assert (!typedef_variant_p (result) || dependent_alias_template_spec_p (result, nt_opaque) || ((flags & STF_USER_VISIBLE) diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-78.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-78.C new file mode 100644 index ..a52c0622e46d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-78.C @@ -0,0 +1,
[gcc r14-10545] c++: normalizing ttp constraints [PR115656]
https://gcc.gnu.org/g:241f710c851aa6a8627c3ddba1e126d8e503e1b0 commit r14-10545-g241f710c851aa6a8627c3ddba1e126d8e503e1b0 Author: Patrick Palka Date: Tue Jul 23 13:16:14 2024 -0400 c++: normalizing ttp constraints [PR115656] Here we normalize the constraint same_as for the first time during ttp coercion of B / UU, specifically constraint subsumption checking. During this normalization the set of in-scope template parameters i.e. current_template_parms is empty, which we rely on during normalization of the ttp constraints since we pass in_decl=NULL_TREE to norm_info. And this tricks the satisfaction cache into thinking that the satisfaction value of same_as is independent of its template parameters, and we incorrectly conflate the satisfaction value with T = bool vs T = long and accept the specialization A. Since is_compatible_template_arg rewrites the ttp's constraints to be in terms of the argument template's parameters, and since it's the only caller of weakly_subsumes, the latter funcion can instead pass in_decl=tmpl to avoid relying on current_template_parms. This patch implements this, and in turns renames weakly_subsumes to ttp_subsumes to reflect that this predicate is now hardcoded for this one caller. PR c++/115656 gcc/cp/ChangeLog: * constraint.cc (weakly_subsumes): Pass in_decl=tmpl to get_normalized_constraints_from_info. Rename to ... (ttp_subsumes): ... this. * cp-tree.h (weakly_subsumes): Rename to ... (ttp_subsumes): ... this. * pt.cc (is_compatible_template_arg): Adjust after renaming. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-ttp7.C: New test. Reviewed-by: Jason Merrill (cherry picked from commit 2861eb34e30973cb991a7964af7cfeae014a98b0) Diff: --- gcc/cp/constraint.cc | 9 + gcc/cp/cp-tree.h | 2 +- gcc/cp/pt.cc | 2 +- gcc/testsuite/g++.dg/cpp2a/concepts-ttp7.C | 12 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 8a3b5d80ba7c..b6c6a5e23306 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -3610,13 +3610,14 @@ strictly_subsumes (tree ci, tree tmpl) return subsumes (n1, n2) && !subsumes (n2, n1); } -/* Returns true when the constraints in CI subsume the - associated constraints of TMPL. */ +/* Returns true when the template template parameter constraints in CI + subsume the associated constraints of the template template argument + TMPL. */ bool -weakly_subsumes (tree ci, tree tmpl) +ttp_subsumes (tree ci, tree tmpl) { - tree n1 = get_normalized_constraints_from_info (ci, NULL_TREE); + tree n1 = get_normalized_constraints_from_info (ci, tmpl); tree n2 = get_normalized_constraints_from_decl (tmpl); return subsumes (n1, n2); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index ed637015a931..3f607313db61 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -8606,7 +8606,7 @@ extern tree find_template_parameters (tree, tree); extern bool equivalent_constraints (tree, tree); extern bool equivalently_constrained(tree, tree); extern bool strictly_subsumes (tree, tree); -extern bool weakly_subsumes(tree, tree); +extern bool ttp_subsumes (tree, tree); extern int more_constrained (tree, tree); extern bool at_least_as_constrained (tree, tree); extern bool constraints_equivalent_p(tree, tree); diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 13907858273e..ea4a6c9bf530 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -8504,7 +8504,7 @@ is_compatible_template_arg (tree parm, tree arg, tree args) return false; } - return weakly_subsumes (parm_cons, arg); + return ttp_subsumes (parm_cons, arg); } // Convert a placeholder argument into a binding to the original diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-ttp7.C b/gcc/testsuite/g++.dg/cpp2a/concepts-ttp7.C new file mode 100644 index ..2ce884b995c7 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-ttp7.C @@ -0,0 +1,12 @@ +// PR c++/115656 +// { dg-do compile { target c++20 } } + +template concept same_as = __is_same(T, U); + +template T, template> class UU> +struct A { }; + +template> class B; + +A a1; +A a2; // { dg-error "constraint failure" }
[gcc r14-10544] c++: missing SFINAE during alias CTAD [PR115296]
https://gcc.gnu.org/g:e548a881a4540378151f6195e47e8413fe75a0d6 commit r14-10544-ge548a881a4540378151f6195e47e8413fe75a0d6 Author: Patrick Palka Date: Tue Jul 23 11:37:31 2024 -0400 c++: missing SFINAE during alias CTAD [PR115296] During the alias CTAD transformation, if substitution failed for some guide we should just silently discard the guide. We currently do discard the guide, but not silently, as in the below testcase which we diagnose forming a too-large array type when transforming the user-defined deduction guides. This patch fixes this by using complain=tf_none instead of tf_warning_or_error throughout alias_ctad_tweaks. PR c++/115296 gcc/cp/ChangeLog: * pt.cc (alias_ctad_tweaks): Use complain=tf_none instead of tf_warning_or_error. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/class-deduction-alias23.C: New test. Reviewed-by: Jason Merrill (cherry picked from commit f70281222df432a7bec1271904c5ebefd7f2c934) Diff: --- gcc/cp/pt.cc | 2 +- gcc/testsuite/g++.dg/cpp2a/class-deduction-alias23.C | 19 +++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 713946a1ff17..13907858273e 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -30369,7 +30369,7 @@ alias_ctad_tweaks (tree tmpl, tree uguides) (INNERMOST_TEMPLATE_PARMS (fullatparms))); } - tsubst_flags_t complain = tf_warning_or_error; + tsubst_flags_t complain = tf_none; tree aguides = NULL_TREE; tree atparms = INNERMOST_TEMPLATE_PARMS (fullatparms); unsigned natparms = TREE_VEC_LENGTH (atparms); diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias23.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias23.C new file mode 100644 index ..117212c67de7 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias23.C @@ -0,0 +1,19 @@ +// PR c++/115296 +// { dg-do compile { target c++20 } } + +using size_t = decltype(sizeof(0)); + +template +struct span { span(T); }; + +template +span(T(&)[N]) -> span; // { dg-bogus "array exceeds maximum" } + +template +requires (sizeof(T[N]) != 42) // { dg-bogus "array exceeds maximum" } +span(T*) -> span; + +template +using array_view = span; + +array_view x = 0;
[gcc r14-10543] c++: prev declared hidden tmpl friend inst [PR112288]
https://gcc.gnu.org/g:1287b4abc67a915ef6b63fb0753a0bea41de47f1 commit r14-10543-g1287b4abc67a915ef6b63fb0753a0bea41de47f1 Author: Patrick Palka Date: Wed Jul 17 21:02:52 2024 -0400 c++: prev declared hidden tmpl friend inst [PR112288] When partially instantiating a previously declared hidden template friend definition (at class template scope) such as slot_allocated in the first testcase below, tsubst_friend_function needs to go through all existing specializations thereof and make them point to the new definition. But when the previous declaration was also at class template scope, old_decl is not the most general template, instead it's the partial instantiation, and since instantiations are relative to the most general template, old_decl's DECL_TEMPLATE_INSTANTIATIONS is empty. So we to consistently use the most general template here. And when adjusting DECL_TI_ARGS to match, only the innermost template arguments should be preserved; the outer ones should correspond to the new definition. Otherwise we fail a checking-only sanity check in instantiate_decl in the first testcase, and in the second/third we end up emitting multiple definitions of the template friend instantiation, resulting in a link failure. PR c++/112288 gcc/cp/ChangeLog: * pt.cc (tsubst_friend_function): When adjusting existing specializations after defining a previously declared template friend, consider the most general template and correct DECL_TI_ARGS adjustment. gcc/testsuite/ChangeLog: * g++.dg/template/friend80.C: New test. * g++.dg/template/friend81.C: New test. * g++.dg/template/friend81a.C: New test. Reviewed-by: Jason Merrill (cherry picked from commit 30dd420a06ad7d2adf4a672d176caee632f8168a) Diff: --- gcc/cp/pt.cc | 13 +++-- gcc/testsuite/g++.dg/template/friend80.C | 25 + gcc/testsuite/g++.dg/template/friend81.C | 28 gcc/testsuite/g++.dg/template/friend81a.C | 30 ++ 4 files changed, 90 insertions(+), 6 deletions(-) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 80d0ca6d0dde..713946a1ff17 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -11582,6 +11582,7 @@ tsubst_friend_function (tree decl, tree args) ; else { + tree old_template = most_general_template (old_decl); tree new_template = TI_TEMPLATE (new_friend_template_info); tree new_args = TI_ARGS (new_friend_template_info); @@ -11619,7 +11620,7 @@ tsubst_friend_function (tree decl, tree args) /* Reassign any specializations already in the hash table to the new more general template, and add the additional template args. */ - for (t = DECL_TEMPLATE_INSTANTIATIONS (old_decl); + for (t = DECL_TEMPLATE_INSTANTIATIONS (old_template); t != NULL_TREE; t = TREE_CHAIN (t)) { @@ -11632,15 +11633,15 @@ tsubst_friend_function (tree decl, tree args) decl_specializations->remove_elt (&elt); - DECL_TI_ARGS (spec) - = add_outermost_template_args (new_args, - DECL_TI_ARGS (spec)); + tree& spec_args = DECL_TI_ARGS (spec); + spec_args = add_outermost_template_args + (new_args, INNERMOST_TEMPLATE_ARGS (spec_args)); register_specialization - (spec, new_template, DECL_TI_ARGS (spec), true, 0); + (spec, new_template, spec_args, true, 0); } - DECL_TEMPLATE_INSTANTIATIONS (old_decl) = NULL_TREE; + DECL_TEMPLATE_INSTANTIATIONS (old_template) = NULL_TREE; } } diff --git a/gcc/testsuite/g++.dg/template/friend80.C b/gcc/testsuite/g++.dg/template/friend80.C new file mode 100644 index ..5c417e12dd0c --- /dev/null +++ b/gcc/testsuite/g++.dg/template/friend80.C @@ -0,0 +1,25 @@ +// PR c++/112288 +// { dg-do compile { target c++11 } } + +template +struct slot { + template + friend constexpr bool slot_allocated(slot, U); +}; + +template +struct allocate_slot { + template + friend constexpr bool slot_allocated(slot, U) { return true; } +}; + +template{}, 42)> +constexpr int next(int) { return 1; } + +template +constexpr int next(...) { return (allocate_slot{}, 0); } + +// slot_allocated, int>() not defined yet +static_assert(next(0) == 0, ""); +// now it's defined, need to make existing spec point to defn or else ICE +static_assert(next(0) == 1, ""); diff --git a/gcc/testsuite/g++.dg
[gcc r15-2387] c++: generic lambda in default template argument [PR88313]
https://gcc.gnu.org/g:72a7ab891ae0061841c4eb641ef6ab7719bf0369 commit r15-2387-g72a7ab891ae0061841c4eb641ef6ab7719bf0369 Author: Patrick Palka Date: Mon Jul 29 16:37:19 2024 -0400 c++: generic lambda in default template argument [PR88313] Here we're rejecting the generic lambda inside the default template argument ultimately because auto_is_implicit_function_template_parm_p doesn't get set during parsing of the lambda's parameter list, due to the !processing_template_parmlist restriction. But when parsing a lambda parameter list we should always set that flag regardless of where the lambda appears. This patch makes sure of this via a local lambda_p flag. PR c++/88313 gcc/cp/ChangeLog: * parser.cc (cp_parser_lambda_declarator_opt): Pass lambda_p=true to cp_parser_parameter_declaration_clause. (cp_parser_direct_declarator): Pass lambda_p=false to to cp_parser_parameter_declaration_clause. (cp_parser_parameter_declaration_clause): Add bool lambda_p parameter. Consider lambda_p instead of current_class_type when setting parser->auto_is_implicit_function_template_parm_p. Don't consider processing_template_parmlist. (cp_parser_requirement_parameter_list): Pass lambda_p=false to cp_parser_parameter_declaration_clause. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/lambda-targ6.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/parser.cc | 34 ++- gcc/testsuite/g++.dg/cpp2a/lambda-targ6.C | 15 ++ 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index f79736c17ac6..e46cdfd20e19 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -2600,7 +2600,7 @@ static tree cp_parser_type_id_1 static void cp_parser_type_specifier_seq (cp_parser *, cp_parser_flags, bool, bool, cp_decl_specifier_seq *); static tree cp_parser_parameter_declaration_clause - (cp_parser *, cp_parser_flags); + (cp_parser *, cp_parser_flags, bool); static tree cp_parser_parameter_declaration_list (cp_parser *, cp_parser_flags, auto_vec *); static cp_parameter_declarator *cp_parser_parameter_declaration @@ -11889,7 +11889,7 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) /* Parse parameters. */ param_list = cp_parser_parameter_declaration_clause - (parser, CP_PARSER_FLAGS_TYPENAME_OPTIONAL); + (parser, CP_PARSER_FLAGS_TYPENAME_OPTIONAL, /*lambda_p=*/true); /* Default arguments shall not be specified in the parameter-declaration-clause of a lambda-declarator. */ @@ -24097,7 +24097,8 @@ cp_parser_direct_declarator (cp_parser* parser, /* Parse the parameter-declaration-clause. */ params - = cp_parser_parameter_declaration_clause (parser, flags); + = cp_parser_parameter_declaration_clause (parser, flags, + /*lambda_p=*/false); const location_t parens_end = cp_lexer_peek_token (parser->lexer)->location; @@ -25444,13 +25445,17 @@ function_being_declared_is_template_p (cp_parser* parser) The parser flags FLAGS is used to control type-specifier parsing. + LAMBDA_P is true if this is the parameter-declaration-clause of + a lambda-declarator. + Returns a representation for the parameter declarations. A return value of NULL indicates a parameter-declaration-clause consisting only of an ellipsis. */ static tree cp_parser_parameter_declaration_clause (cp_parser* parser, - cp_parser_flags flags) + cp_parser_flags flags, + bool lambda_p) { tree parameters; cp_token *token; @@ -25459,15 +25464,15 @@ cp_parser_parameter_declaration_clause (cp_parser* parser, auto cleanup = make_temp_override (parser->auto_is_implicit_function_template_parm_p); - if (!processing_specialization - && !processing_template_parmlist - && !processing_explicit_instantiation - /* default_arg_ok_p tracks whether this is a parameter-clause for an - actual function or a random abstract declarator. */ - && parser->default_arg_ok_p) -if (!current_function_decl - || (current_class_type && LAMBDA_TYPE_P (current_class_type))) - parser->auto_is_implicit_function_template_parm_p = true; + if (lambda_p + || (!processing_specialization + && !processing_template_parmlist + && !processing_explicit_instantiation + /* default_arg_ok_p tracks whether this is a parameter-clause for an +actual function or a random abstract declarator. */ + && parser->default_arg_ok_p +
[gcc r15-2331] c++: non-template alias with dependent attributes [PR115897]
https://gcc.gnu.org/g:523836716137d0f7f4088c85752a980f5f971b36 commit r15-2331-g523836716137d0f7f4088c85752a980f5f971b36 Author: Patrick Palka Date: Thu Jul 25 19:05:19 2024 -0400 c++: non-template alias with dependent attributes [PR115897] This patch generalizes our support for dependent attributes on alias templates to also support them on non-template aliases. The main addition is a new predicate dependent_opaque_alias_p controlling whether we can treat an alias (template or non-template) as type-equivalent to its expansion. PR c++/115897 gcc/cp/ChangeLog: * cp-tree.h (dependent_opaque_alias_p): Declare. * pt.cc (push_template_decl): Manually mark a dependent opaque alias or dependent alias template specialization as dependent, and use structural equality for them. (dependent_opaque_alias_p): Define. (alias_template_specialization_p): Don't look through an opaque alias. (complex_alias_template_p): Use dependent_opaque_alias_p instead of any_dependent_template_arguments_p directly. (dependent_alias_template_spec_p): Don't look through an opaque alias. (get_underlying_template): Use dependent_opaque_alias_p instead of any_dependent_template_arguments_p. (instantiate_alias_template): Mention same logic in push_template_decl. (dependent_type_p_r): Remove dependent_alias_template_spec_p check. (any_template_arguments_need_structural_equality_p): Return true for a dependent opaque alias. (alias_ctad_tweaks): Use template_args_equal instead of same_type_p followed by dependent_alias_template_spec_p. * tree.cc (strip_typedefs): Don't strip an opaque alias. * typeck.cc (structural_comptypes): Compare declaration attributes for an opaque alias. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/alias-decl-79.C: Remove xfails. * g++.dg/cpp0x/alias-decl-79a.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/cp-tree.h| 1 + gcc/cp/pt.cc| 55 - gcc/cp/tree.cc | 7 ++-- gcc/cp/typeck.cc| 17 ++--- gcc/testsuite/g++.dg/cpp0x/alias-decl-79.C | 16 - gcc/testsuite/g++.dg/cpp0x/alias-decl-79a.C | 41 + 6 files changed, 106 insertions(+), 31 deletions(-) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 7d50aac4b6b8..238d786b0674 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7621,6 +7621,7 @@ extern bool alias_type_or_template_p(tree); enum { nt_opaque = false, nt_transparent = true }; extern tree alias_template_specialization_p (const_tree, bool); extern tree dependent_alias_template_spec_p (const_tree, bool); +extern bool dependent_opaque_alias_p(const_tree); extern tree get_template_parm_object (tree expr, tree mangle); extern tree tparm_object_argument (tree); extern bool explicit_class_specialization_p (tree); diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index e102e3ea490f..39f7e8a4e688 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -6271,6 +6271,18 @@ push_template_decl (tree decl, bool is_friend) } } + if (is_typedef_decl (decl) + && (dependent_opaque_alias_p (TREE_TYPE (decl)) + || dependent_alias_template_spec_p (TREE_TYPE (decl), nt_opaque))) +{ + /* Manually mark such aliases as dependent so that dependent_type_p_r +doesn't have to handle them. */ + TYPE_DEPENDENT_P_VALID (TREE_TYPE (decl)) = true; + TYPE_DEPENDENT_P (TREE_TYPE (decl)) = true; + /* The identity of such aliases is hairy; see structural_comptypes. */ + SET_TYPE_STRUCTURAL_EQUALITY (TREE_TYPE (decl)); +} + if (flag_implicit_templates && !is_friend && TREE_PUBLIC (decl) @@ -6530,7 +6542,7 @@ alias_template_specialization_p (const_tree t, if (tree tinfo = TYPE_ALIAS_TEMPLATE_INFO (t)) if (PRIMARY_TEMPLATE_P (TI_TEMPLATE (tinfo))) return CONST_CAST_TREE (t); - if (transparent_typedefs) + if (transparent_typedefs && !dependent_opaque_alias_p (t)) return alias_template_specialization_p (DECL_ORIGINAL_TYPE (TYPE_NAME (t)), transparent_typedefs); @@ -6635,8 +6647,7 @@ complex_alias_template_p (const_tree tmpl, tree *seen_out) return true; /* An alias with dependent type attributes is complex. */ - if (any_dependent_type_attributes_p (DECL_ATTRIBUTES - (DECL_TEMPLATE_RESULT (tmpl + if (dependent_opaque_alias_p (TREE_TYPE (tmpl))) return true
[gcc r15-2330] c++: alias of alias tmpl with dependent attrs [PR115897]
https://gcc.gnu.org/g:9bcad238837e2100978cd839c343c488f72e1d4a commit r15-2330-g9bcad238837e2100978cd839c343c488f72e1d4a Author: Patrick Palka Date: Thu Jul 25 19:00:23 2024 -0400 c++: alias of alias tmpl with dependent attrs [PR115897] As a follow-up to r15-2047-g7954bb4fcb6fa8, we also need to consider dependent attributes when recursing into a non-template alias that names a dependent alias template specialization (and so STF_STRIP_DEPENDENT is set), otherwise in the first testcase below we undesirably strip B all the way to T instead of to A. We also need to move the typedef recursion case of strip_typedefs up to get checked before the compound type recursion cases. Otherwise for C below (which ultimately aliases T*) we end up stripping it to T* instead of to A because the POINTER_TYPE recursion dominates the typedef recursion. It also means we issue an unexpected extra error in the third testcase below. Ideally we would also want to consider dependent attributes on non-template aliases, so that we accept the second testcase below, but making that work correctly would require broader changes to e.g. structural_comptypes. PR c++/115897 gcc/cp/ChangeLog: * tree.cc (strip_typedefs): Move up the typedef recursion case. Never strip a dependent alias template-id that has dependent attributes. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/alias-decl-78.C: New test. * g++.dg/cpp0x/alias-decl-79.C: New test. * g++.dg/cpp0x/alias-decl-pr92206-1a.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/tree.cc | 51 -- gcc/testsuite/g++.dg/cpp0x/alias-decl-78.C | 34 +++ gcc/testsuite/g++.dg/cpp0x/alias-decl-79.C | 37 gcc/testsuite/g++.dg/cpp0x/alias-decl-pr92206-1a.C | 10 + 4 files changed, 110 insertions(+), 22 deletions(-) diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc index 250239e4e3ae..f2001ace6db0 100644 --- a/gcc/cp/tree.cc +++ b/gcc/cp/tree.cc @@ -1607,11 +1607,32 @@ strip_typedefs (tree t, bool *remove_attributes /* = NULL */, if (t == TYPE_CANONICAL (t)) return t; - if (!(flags & STF_STRIP_DEPENDENT) - && dependent_alias_template_spec_p (t, nt_opaque)) -/* DR 1558: However, if the template-id is dependent, subsequent - template argument substitution still applies to the template-id. */ -return t; + if (typedef_variant_p (t)) +{ + if ((flags & STF_USER_VISIBLE) + && !user_facing_original_type_p (t)) + return t; + + if (alias_template_specialization_p (t, nt_opaque)) + { + if (dependent_alias_template_spec_p (t, nt_opaque) + && (!(flags & STF_STRIP_DEPENDENT) + || any_dependent_type_attributes_p (DECL_ATTRIBUTES + (TYPE_NAME (t) + /* DR 1558: However, if the template-id is dependent, subsequent + template argument substitution still applies to the template-id. */ + return t; + } + else + /* If T is a non-template alias or typedef, we can assume that + instantiating its definition will hit any substitution failure, + so we don't need to retain it here as well. */ + flags |= STF_STRIP_DEPENDENT; + + result = strip_typedefs (DECL_ORIGINAL_TYPE (TYPE_NAME (t)), + remove_attributes, flags); + goto stripped; +} switch (TREE_CODE (t)) { @@ -1805,23 +1826,9 @@ strip_typedefs (tree t, bool *remove_attributes /* = NULL */, } if (!result) -{ - if (typedef_variant_p (t)) - { - if ((flags & STF_USER_VISIBLE) - && !user_facing_original_type_p (t)) - return t; - /* If T is a non-template alias or typedef, we can assume that -instantiating its definition will hit any substitution failure, -so we don't need to retain it here as well. */ - if (!alias_template_specialization_p (t, nt_opaque)) - flags |= STF_STRIP_DEPENDENT; - result = strip_typedefs (DECL_ORIGINAL_TYPE (TYPE_NAME (t)), - remove_attributes, flags); - } - else - result = TYPE_MAIN_VARIANT (t); -} +result = TYPE_MAIN_VARIANT (t); + +stripped: /*gcc_assert (!typedef_variant_p (result) || dependent_alias_template_spec_p (result, nt_opaque) || ((flags & STF_USER_VISIBLE) diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-78.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-78.C new file mode 100644 index ..a52c0622e46d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-78.C @@ -0,0 +1,34 @@ +// PR c++/115897 +// { dg-do compile { target c++11 } } + +template
[gcc r15-2230] c++: normalizing ttp constraints [PR115656]
https://gcc.gnu.org/g:2861eb34e30973cb991a7964af7cfeae014a98b0 commit r15-2230-g2861eb34e30973cb991a7964af7cfeae014a98b0 Author: Patrick Palka Date: Tue Jul 23 13:16:14 2024 -0400 c++: normalizing ttp constraints [PR115656] Here we normalize the constraint same_as for the first time during ttp coercion of B / UU, specifically constraint subsumption checking. During this normalization the set of in-scope template parameters i.e. current_template_parms is empty, which we rely on during normalization of the ttp constraints since we pass in_decl=NULL_TREE to norm_info. And this tricks the satisfaction cache into thinking that the satisfaction value of same_as is independent of its template parameters, and we incorrectly conflate the satisfaction value with T = bool vs T = long and accept the specialization A. Since is_compatible_template_arg rewrites the ttp's constraints to be in terms of the argument template's parameters, and since it's the only caller of weakly_subsumes, the latter funcion can instead pass in_decl=tmpl to avoid relying on current_template_parms. This patch implements this, and in turns renames weakly_subsumes to ttp_subsumes to reflect that this predicate is now hardcoded for this one caller. PR c++/115656 gcc/cp/ChangeLog: * constraint.cc (weakly_subsumes): Pass in_decl=tmpl to get_normalized_constraints_from_info. Rename to ... (ttp_subsumes): ... this. * cp-tree.h (weakly_subsumes): Rename to ... (ttp_subsumes): ... this. * pt.cc (is_compatible_template_arg): Adjust after renaming. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-ttp7.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/constraint.cc | 9 + gcc/cp/cp-tree.h | 2 +- gcc/cp/pt.cc | 2 +- gcc/testsuite/g++.dg/cpp2a/concepts-ttp7.C | 12 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index afd5435cc3ed..7fce78f508e9 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -3328,13 +3328,14 @@ strictly_subsumes (tree ci, tree tmpl) return subsumes (n1, n2) && !subsumes (n2, n1); } -/* Returns true when the constraints in CI subsume the - associated constraints of TMPL. */ +/* Returns true when the template template parameter constraints in CI + subsume the associated constraints of the template template argument + TMPL. */ bool -weakly_subsumes (tree ci, tree tmpl) +ttp_subsumes (tree ci, tree tmpl) { - tree n1 = get_normalized_constraints_from_info (ci, NULL_TREE); + tree n1 = get_normalized_constraints_from_info (ci, tmpl); tree n2 = get_normalized_constraints_from_decl (tmpl); return subsumes (n1, n2); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 76ac9c31763c..856699de82f2 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -8609,7 +8609,7 @@ extern tree find_template_parameters (tree, tree); extern bool equivalent_constraints (tree, tree); extern bool equivalently_constrained(tree, tree); extern bool strictly_subsumes (tree, tree); -extern bool weakly_subsumes(tree, tree); +extern bool ttp_subsumes (tree, tree); extern int more_constrained (tree, tree); extern bool at_least_as_constrained (tree, tree); extern bool constraints_equivalent_p(tree, tree); diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 8cc5e21c520d..393913294b50 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -8482,7 +8482,7 @@ is_compatible_template_arg (tree parm, tree arg, tree args) return false; } - return weakly_subsumes (parm_cons, arg); + return ttp_subsumes (parm_cons, arg); } // Convert a placeholder argument into a binding to the original diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-ttp7.C b/gcc/testsuite/g++.dg/cpp2a/concepts-ttp7.C new file mode 100644 index ..2ce884b995c7 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-ttp7.C @@ -0,0 +1,12 @@ +// PR c++/115656 +// { dg-do compile { target c++20 } } + +template concept same_as = __is_same(T, U); + +template T, template> class UU> +struct A { }; + +template> class B; + +A a1; +A a2; // { dg-error "constraint failure" }
[gcc r15-2229] c++: missing SFINAE during alias CTAD [PR115296]
https://gcc.gnu.org/g:f70281222df432a7bec1271904c5ebefd7f2c934 commit r15-2229-gf70281222df432a7bec1271904c5ebefd7f2c934 Author: Patrick Palka Date: Tue Jul 23 11:37:31 2024 -0400 c++: missing SFINAE during alias CTAD [PR115296] During the alias CTAD transformation, if substitution failed for some guide we should just silently discard the guide. We currently do discard the guide, but not silently, as in the below testcase which we diagnose forming a too-large array type when transforming the user-defined deduction guides. This patch fixes this by using complain=tf_none instead of tf_warning_or_error throughout alias_ctad_tweaks. PR c++/115296 gcc/cp/ChangeLog: * pt.cc (alias_ctad_tweaks): Use complain=tf_none instead of tf_warning_or_error. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/class-deduction-alias23.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/pt.cc | 2 +- gcc/testsuite/g++.dg/cpp2a/class-deduction-alias23.C | 19 +++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 108e929b8ee6..8cc5e21c520d 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -30287,7 +30287,7 @@ alias_ctad_tweaks (tree tmpl, tree uguides) (INNERMOST_TEMPLATE_PARMS (fullatparms))); } - tsubst_flags_t complain = tf_warning_or_error; + tsubst_flags_t complain = tf_none; tree aguides = NULL_TREE; tree atparms = INNERMOST_TEMPLATE_PARMS (fullatparms); unsigned natparms = TREE_VEC_LENGTH (atparms); diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias23.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias23.C new file mode 100644 index ..117212c67de7 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias23.C @@ -0,0 +1,19 @@ +// PR c++/115296 +// { dg-do compile { target c++20 } } + +using size_t = decltype(sizeof(0)); + +template +struct span { span(T); }; + +template +span(T(&)[N]) -> span; // { dg-bogus "array exceeds maximum" } + +template +requires (sizeof(T[N]) != 42) // { dg-bogus "array exceeds maximum" } +span(T*) -> span; + +template +using array_view = span; + +array_view x = 0;
[gcc r14-10498] c++/coroutines: correct passing *this to promise type [PR104981]
https://gcc.gnu.org/g:066c7893eae0bfc7d9b33b931f115f455246c914 commit r14-10498-g066c7893eae0bfc7d9b33b931f115f455246c914 Author: Patrick Palka Date: Mon Jul 22 21:30:49 2024 -0400 c++/coroutines: correct passing *this to promise type [PR104981] When passing *this to the promise type ctor (or to its operator new) (as per [dcl.fct.def.coroutine]/4), we add an explicit cast to lvalue reference. But this is unnecessary since *this is already always an lvalue. And doing so means we need to call convert_from_reference afterward to lower the reference expression to an implicit dereference, which we're currently neglecting to do and which causes overload resolution to get confused when computing argument conversions. So this patch removes this unneeded reference cast when passing *this to the promise ctor, and removes both the cast and implicit deref when passing *this to operator new, for consistency. While we're here, use cp_build_fold_indirect_ref instead of directly building INDIRECT_REF. PR c++/104981 PR c++/115550 gcc/cp/ChangeLog: * coroutines.cc (morph_fn_to_coro): Remove unneeded calls to convert_to_reference and convert_from_reference when passing *this. Use cp_build_fold_indirect_ref instead of directly building INDIRECT_REF. gcc/testsuite/ChangeLog: * g++.dg/coroutines/pr104981-preview-this.C: New test. * g++.dg/coroutines/pr115550-preview-this.C: New test. Reviewed-by: Iain Sandoe Reviewed-by: Jason Merrill (cherry picked from commit 7c5a9bf1d206fe20cb050200d4a30f11c76b1b19) Diff: --- gcc/cp/coroutines.cc | 18 ++--- .../g++.dg/coroutines/pr104981-preview-this.C | 34 .../g++.dg/coroutines/pr115550-preview-this.C | 47 ++ 3 files changed, 84 insertions(+), 15 deletions(-) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index b05cb9eb3302..71e64960c5a8 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -4618,13 +4618,8 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) if (parm_i->this_ptr || parm_i->lambda_cobj) { /* We pass a reference to *this to the allocator lookup. */ - tree tt = TREE_TYPE (TREE_TYPE (arg)); - tree this_ref = build1 (INDIRECT_REF, tt, arg); - tt = cp_build_reference_type (tt, false); - this_ref = convert_to_reference (tt, this_ref, CONV_STATIC, - LOOKUP_NORMAL , NULL_TREE, - tf_warning_or_error); - vec_safe_push (args, convert_from_reference (this_ref)); + tree this_ref = cp_build_fold_indirect_ref (arg); + vec_safe_push (args, this_ref); } else vec_safe_push (args, convert_from_reference (arg)); @@ -4843,14 +4838,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) if (parm.this_ptr || parm.lambda_cobj) { /* We pass a reference to *this to the param preview. */ - tree tt = TREE_TYPE (arg); - gcc_checking_assert (POINTER_TYPE_P (tt)); - tree ct = TREE_TYPE (tt); - tree this_ref = build1 (INDIRECT_REF, ct, arg); - tree rt = cp_build_reference_type (ct, false); - this_ref = convert_to_reference (rt, this_ref, CONV_STATIC, - LOOKUP_NORMAL, NULL_TREE, - tf_warning_or_error); + tree this_ref = cp_build_fold_indirect_ref (arg); vec_safe_push (promise_args, this_ref); } else if (parm.rv_ref) diff --git a/gcc/testsuite/g++.dg/coroutines/pr104981-preview-this.C b/gcc/testsuite/g++.dg/coroutines/pr104981-preview-this.C new file mode 100644 index ..81eb963db4a5 --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/pr104981-preview-this.C @@ -0,0 +1,34 @@ +// PR c++/104981 - ICE from convert_to_base when passing *this to promise ctor + +#include + +class Base {}; + +struct PromiseType; + +struct Result { + using promise_type = PromiseType; +}; + +struct PromiseType { + PromiseType(const Base& parser, auto&&...) {} + + Result get_return_object() { return {}; } + + static std::suspend_never initial_suspend() { return {}; } + static std::suspend_always final_suspend() noexcept { return {}; } + [[noreturn]] static void unhandled_exception() { throw; } + + void return_value(int) {} +}; + +struct Derived : Base { + Result f() { + co_return 42; + } +}; + +int main() { + Derived d; + d.f(); +} diff --git a/gcc/testsuite/g++.dg/coroutines/pr115550-preview-this.C b/gcc/testsuite/g++.dg/coroutines/pr115550-preview-this.C new file mode 100644 index
[gcc r14-10497] c++: xobj fn call without obj [PR115783]
https://gcc.gnu.org/g:50ff112d17ec53ccff2858f6ded9dc04b1d5d2bc commit r14-10497-g50ff112d17ec53ccff2858f6ded9dc04b1d5d2bc Author: Patrick Palka Date: Fri Jul 19 13:48:12 2024 -0400 c++: xobj fn call without obj [PR115783] The code path for rejecting an object-less call to a non-static member function should also consider xobj member functions (so that we correctly reject the below calls with a "cannot call member function without object" diagnostic). PR c++/115783 gcc/cp/ChangeLog: * call.cc (build_new_method_call): Generalize METHOD_TYPE check to DECL_OBJECT_MEMBER_FUNCTION_P. gcc/testsuite/ChangeLog: * g++.dg/cpp23/explicit-obj-diagnostics11.C: New test. Reviewed-by: Jason Merrill (cherry picked from commit 2ee70c9f83a1033f2897a35bff9e9ffdd03cc651) Diff: --- gcc/cp/call.cc | 2 +- .../g++.dg/cpp23/explicit-obj-diagnostics11.C | 48 ++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 844a7e2b35d7..793b98347124 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -11820,7 +11820,7 @@ build_new_method_call (tree instance, tree fns, vec **args, fn); } - if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE + if (DECL_OBJECT_MEMBER_FUNCTION_P (fn) && !DECL_CONSTRUCTOR_P (fn) && is_dummy_object (instance)) { diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics11.C b/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics11.C new file mode 100644 index ..cc2571f62a2d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics11.C @@ -0,0 +1,48 @@ +// PR c++/115783 +// { dg-do compile { target c++23 } } + +struct A { + int f(this auto); + + static void s() { +f(); // { dg-error "without object" } + } +}; + +int n = A::f(); // { dg-error "without object" } + +struct B { + void ns() { +A::f(); // { dg-error "without object" } + } + + static void s() { +A::f(); // { dg-error "without object" } + } +}; + +template +struct C { + void ns() { +A::f(); // { dg-error "without object" } +T::f(); // { dg-error "without object" } + } + + static void s() { +A::f(); // { dg-error "without object" } +T::f(); // { dg-error "without object" } + }; +}; + +template struct C; + +template +struct D : T { + void ns() { +A::f(); // { dg-error "without object" } +T::f(); // { dg-error "not a member of 'B'" } + } +}; + +template struct D; // { dg-message "required from here" } +template struct D; // { dg-bogus "required from here" }
[gcc r15-2210] c++/coroutines: correct passing *this to promise type [PR104981]
https://gcc.gnu.org/g:7c5a9bf1d206fe20cb050200d4a30f11c76b1b19 commit r15-2210-g7c5a9bf1d206fe20cb050200d4a30f11c76b1b19 Author: Patrick Palka Date: Mon Jul 22 21:30:49 2024 -0400 c++/coroutines: correct passing *this to promise type [PR104981] When passing *this to the promise type ctor (or to its operator new) (as per [dcl.fct.def.coroutine]/4), we add an explicit cast to lvalue reference. But this is unnecessary since *this is already always an lvalue. And doing so means we need to call convert_from_reference afterward to lower the reference expression to an implicit dereference, which we're currently neglecting to do and which causes overload resolution to get confused when computing argument conversions. So this patch removes this unneeded reference cast when passing *this to the promise ctor, and removes both the cast and implicit deref when passing *this to operator new, for consistency. While we're here, use cp_build_fold_indirect_ref instead of directly building INDIRECT_REF. PR c++/104981 PR c++/115550 gcc/cp/ChangeLog: * coroutines.cc (morph_fn_to_coro): Remove unneeded calls to convert_to_reference and convert_from_reference when passing *this. Use cp_build_fold_indirect_ref instead of directly building INDIRECT_REF. gcc/testsuite/ChangeLog: * g++.dg/coroutines/pr104981-preview-this.C: New test. * g++.dg/coroutines/pr115550-preview-this.C: New test. Reviewed-by: Iain Sandoe Reviewed-by: Jason Merrill Diff: --- gcc/cp/coroutines.cc | 18 ++--- .../g++.dg/coroutines/pr104981-preview-this.C | 34 .../g++.dg/coroutines/pr115550-preview-this.C | 47 ++ 3 files changed, 84 insertions(+), 15 deletions(-) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index f350fc33e9b4..e8f028df3adb 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -4620,13 +4620,8 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) if (parm_i->this_ptr || parm_i->lambda_cobj) { /* We pass a reference to *this to the allocator lookup. */ - tree tt = TREE_TYPE (TREE_TYPE (arg)); - tree this_ref = build1 (INDIRECT_REF, tt, arg); - tt = cp_build_reference_type (tt, false); - this_ref = convert_to_reference (tt, this_ref, CONV_STATIC, - LOOKUP_NORMAL , NULL_TREE, - tf_warning_or_error); - vec_safe_push (args, convert_from_reference (this_ref)); + tree this_ref = cp_build_fold_indirect_ref (arg); + vec_safe_push (args, this_ref); } else vec_safe_push (args, convert_from_reference (arg)); @@ -4845,14 +4840,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) if (parm.this_ptr || parm.lambda_cobj) { /* We pass a reference to *this to the param preview. */ - tree tt = TREE_TYPE (arg); - gcc_checking_assert (POINTER_TYPE_P (tt)); - tree ct = TREE_TYPE (tt); - tree this_ref = build1 (INDIRECT_REF, ct, arg); - tree rt = cp_build_reference_type (ct, false); - this_ref = convert_to_reference (rt, this_ref, CONV_STATIC, - LOOKUP_NORMAL, NULL_TREE, - tf_warning_or_error); + tree this_ref = cp_build_fold_indirect_ref (arg); vec_safe_push (promise_args, this_ref); } else if (parm.rv_ref) diff --git a/gcc/testsuite/g++.dg/coroutines/pr104981-preview-this.C b/gcc/testsuite/g++.dg/coroutines/pr104981-preview-this.C new file mode 100644 index ..81eb963db4a5 --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/pr104981-preview-this.C @@ -0,0 +1,34 @@ +// PR c++/104981 - ICE from convert_to_base when passing *this to promise ctor + +#include + +class Base {}; + +struct PromiseType; + +struct Result { + using promise_type = PromiseType; +}; + +struct PromiseType { + PromiseType(const Base& parser, auto&&...) {} + + Result get_return_object() { return {}; } + + static std::suspend_never initial_suspend() { return {}; } + static std::suspend_always final_suspend() noexcept { return {}; } + [[noreturn]] static void unhandled_exception() { throw; } + + void return_value(int) {} +}; + +struct Derived : Base { + Result f() { + co_return 42; + } +}; + +int main() { + Derived d; + d.f(); +} diff --git a/gcc/testsuite/g++.dg/coroutines/pr115550-preview-this.C b/gcc/testsuite/g++.dg/coroutines/pr115550-preview-this.C new file mode 100644 index ..f62c07096b61 --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines
[gcc r15-2159] c++: xobj fn call without obj [PR115783]
https://gcc.gnu.org/g:2ee70c9f83a1033f2897a35bff9e9ffdd03cc651 commit r15-2159-g2ee70c9f83a1033f2897a35bff9e9ffdd03cc651 Author: Patrick Palka Date: Fri Jul 19 13:48:12 2024 -0400 c++: xobj fn call without obj [PR115783] The code path for rejecting an object-less call to a non-static member function should also consider xobj member functions (so that we correctly reject the below calls with a "cannot call member function without object" diagnostic). PR c++/115783 gcc/cp/ChangeLog: * call.cc (build_new_method_call): Generalize METHOD_TYPE check to DECL_OBJECT_MEMBER_FUNCTION_P. gcc/testsuite/ChangeLog: * g++.dg/cpp23/explicit-obj-diagnostics11.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/call.cc | 2 +- .../g++.dg/cpp23/explicit-obj-diagnostics11.C | 48 ++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index a5d3426b70c4..40cb582acc70 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -11855,7 +11855,7 @@ build_new_method_call (tree instance, tree fns, vec **args, fn); } - if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE + if (DECL_OBJECT_MEMBER_FUNCTION_P (fn) && !DECL_CONSTRUCTOR_P (fn) && is_dummy_object (instance)) { diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics11.C b/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics11.C new file mode 100644 index ..cc2571f62a2d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics11.C @@ -0,0 +1,48 @@ +// PR c++/115783 +// { dg-do compile { target c++23 } } + +struct A { + int f(this auto); + + static void s() { +f(); // { dg-error "without object" } + } +}; + +int n = A::f(); // { dg-error "without object" } + +struct B { + void ns() { +A::f(); // { dg-error "without object" } + } + + static void s() { +A::f(); // { dg-error "without object" } + } +}; + +template +struct C { + void ns() { +A::f(); // { dg-error "without object" } +T::f(); // { dg-error "without object" } + } + + static void s() { +A::f(); // { dg-error "without object" } +T::f(); // { dg-error "without object" } + }; +}; + +template struct C; + +template +struct D : T { + void ns() { +A::f(); // { dg-error "without object" } +T::f(); // { dg-error "not a member of 'B'" } + } +}; + +template struct D; // { dg-message "required from here" } +template struct D; // { dg-bogus "required from here" }
[gcc r15-2154] c++: add fixed testcase [PR109464]
https://gcc.gnu.org/g:58a9f3ded1a0ccc2c8b0a42f976950041734798e commit r15-2154-g58a9f3ded1a0ccc2c8b0a42f976950041734798e Author: Patrick Palka Date: Fri Jul 19 11:08:09 2024 -0400 c++: add fixed testcase [PR109464] Seems to be fixed by r15-521-g6ad7ca1bb90573. PR c++/109464 gcc/testsuite/ChangeLog: * g++.dg/template/explicit-instantiation8.C: New test. Diff: --- .../g++.dg/template/explicit-instantiation8.C | 24 ++ 1 file changed, 24 insertions(+) diff --git a/gcc/testsuite/g++.dg/template/explicit-instantiation8.C b/gcc/testsuite/g++.dg/template/explicit-instantiation8.C new file mode 100644 index ..92152a2992e9 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/explicit-instantiation8.C @@ -0,0 +1,24 @@ +// PR c++/109464 +// { dg-do compile { target c++11 } } + +template +struct shallow + { + int len; + constexpr shallow() : len(0) { } + }; + +template +struct use_shallow + { + static constexpr shallow s_zstr = { }; + static_assert(s_zstr.len == 0, ""); + }; + +extern template struct shallow; +extern template struct use_shallow; + +template struct shallow; +template struct use_shallow; + +// { dg-final { scan-assembler "_ZN7shallowIcEC2Ev" } }
[gcc r15-2120] c++: prev declared hidden tmpl friend inst [PR112288]
https://gcc.gnu.org/g:30dd420a06ad7d2adf4a672d176caee632f8168a commit r15-2120-g30dd420a06ad7d2adf4a672d176caee632f8168a Author: Patrick Palka Date: Wed Jul 17 21:02:52 2024 -0400 c++: prev declared hidden tmpl friend inst [PR112288] When partially instantiating a previously declared hidden template friend definition (at class template scope) such as slot_allocated in the first testcase below, tsubst_friend_function needs to go through all existing specializations thereof and make them point to the new definition. But when the previous declaration was also at class template scope, old_decl is not the most general template, instead it's the partial instantiation, and since instantiations are relative to the most general template, old_decl's DECL_TEMPLATE_INSTANTIATIONS is empty. So we to consistently use the most general template here. And when adjusting DECL_TI_ARGS to match, only the innermost template arguments should be preserved; the outer ones should correspond to the new definition. Otherwise we fail a checking-only sanity check in instantiate_decl in the first testcase, and in the second/third we end up emitting multiple definitions of the template friend instantiation, resulting in a link failure. PR c++/112288 gcc/cp/ChangeLog: * pt.cc (tsubst_friend_function): When adjusting existing specializations after defining a previously declared template friend, consider the most general template and correct DECL_TI_ARGS adjustment. gcc/testsuite/ChangeLog: * g++.dg/template/friend80.C: New test. * g++.dg/template/friend81.C: New test. * g++.dg/template/friend81a.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/pt.cc | 13 +++-- gcc/testsuite/g++.dg/template/friend80.C | 25 + gcc/testsuite/g++.dg/template/friend81.C | 28 gcc/testsuite/g++.dg/template/friend81a.C | 30 ++ 4 files changed, 90 insertions(+), 6 deletions(-) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 0620c8c023a2..057797f213f5 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -11582,6 +11582,7 @@ tsubst_friend_function (tree decl, tree args) ; else { + tree old_template = most_general_template (old_decl); tree new_template = TI_TEMPLATE (new_friend_template_info); tree new_args = TI_ARGS (new_friend_template_info); @@ -11619,7 +11620,7 @@ tsubst_friend_function (tree decl, tree args) /* Reassign any specializations already in the hash table to the new more general template, and add the additional template args. */ - for (t = DECL_TEMPLATE_INSTANTIATIONS (old_decl); + for (t = DECL_TEMPLATE_INSTANTIATIONS (old_template); t != NULL_TREE; t = TREE_CHAIN (t)) { @@ -11632,15 +11633,15 @@ tsubst_friend_function (tree decl, tree args) decl_specializations->remove_elt (&elt); - DECL_TI_ARGS (spec) - = add_outermost_template_args (new_args, - DECL_TI_ARGS (spec)); + tree& spec_args = DECL_TI_ARGS (spec); + spec_args = add_outermost_template_args + (new_args, INNERMOST_TEMPLATE_ARGS (spec_args)); register_specialization - (spec, new_template, DECL_TI_ARGS (spec), true, 0); + (spec, new_template, spec_args, true, 0); } - DECL_TEMPLATE_INSTANTIATIONS (old_decl) = NULL_TREE; + DECL_TEMPLATE_INSTANTIATIONS (old_template) = NULL_TREE; } } diff --git a/gcc/testsuite/g++.dg/template/friend80.C b/gcc/testsuite/g++.dg/template/friend80.C new file mode 100644 index ..5c417e12dd0c --- /dev/null +++ b/gcc/testsuite/g++.dg/template/friend80.C @@ -0,0 +1,25 @@ +// PR c++/112288 +// { dg-do compile { target c++11 } } + +template +struct slot { + template + friend constexpr bool slot_allocated(slot, U); +}; + +template +struct allocate_slot { + template + friend constexpr bool slot_allocated(slot, U) { return true; } +}; + +template{}, 42)> +constexpr int next(int) { return 1; } + +template +constexpr int next(...) { return (allocate_slot{}, 0); } + +// slot_allocated, int>() not defined yet +static_assert(next(0) == 0, ""); +// now it's defined, need to make existing spec point to defn or else ICE +static_assert(next(0) == 1, ""); diff --git a/gcc/testsuite/g++.dg/template/friend81.C b/gcc/testsuite/g++.dg/template/friend81.C new file
[gcc r15-2118] c++: missing -Wunused-value for ! [PR114104]
https://gcc.gnu.org/g:144b6099cdaa9ac1b298687c0cfdb06a970e338b commit r15-2118-g144b6099cdaa9ac1b298687c0cfdb06a970e338b Author: Patrick Palka Date: Wed Jul 17 20:57:54 2024 -0400 c++: missing -Wunused-value for ! [PR114104] Here we're neglecting to issue a -Wunused-value warning for suitable ! operator expressions, and in turn for != operator expressions that are rewritten as !(x == y), only because we don't call warn_if_unused_value on TRUTH_NOT_EXPR since its class is tcc_expression. This patch makes us also consider warning for TRUTH_NOT_EXPR and also for ADDR_EXPR. PR c++/114104 gcc/cp/ChangeLog: * cvt.cc (convert_to_void): Call warn_if_unused_value for TRUTH_NOT_EXPR and ADDR_EXPR as well. gcc/testsuite/ChangeLog: * g++.dg/warn/Wunused-20.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/cvt.cc | 2 ++ gcc/testsuite/g++.dg/warn/Wunused-20.C | 19 +++ 2 files changed, 21 insertions(+) diff --git a/gcc/cp/cvt.cc b/gcc/cp/cvt.cc index db086c017e89..d95e01c118c4 100644 --- a/gcc/cp/cvt.cc +++ b/gcc/cp/cvt.cc @@ -1664,6 +1664,8 @@ convert_to_void (tree expr, impl_conv_void implicit, tsubst_flags_t complain) if (tclass == tcc_comparison || tclass == tcc_unary || tclass == tcc_binary + || code == TRUTH_NOT_EXPR + || code == ADDR_EXPR || code == VEC_PERM_EXPR || code == VEC_COND_EXPR) warn_if_unused_value (e, loc); diff --git a/gcc/testsuite/g++.dg/warn/Wunused-20.C b/gcc/testsuite/g++.dg/warn/Wunused-20.C new file mode 100644 index ..31b1920adcdd --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wunused-20.C @@ -0,0 +1,19 @@ +// PR c++/114104 +// { dg-additional-options "-Wunused-value" } + +bool f(); +struct A { int i; }; +A& g(); + +void h() { + !f(); // { dg-warning "value computed is not used" } + &g().i; // { dg-warning "value computed is not used" } +} + +#if __cplusplus >= 202002L +[[nodiscard]] bool operator==(A&, int); + +void h(A a) { + a != 0; // { dg-warning "value computed is not used" "" { target c++20 } } +} +#endif
[gcc r14-10450] c++: alias template with dependent attributes [PR115897]
https://gcc.gnu.org/g:2249c6348835c817f43c9fc55eac66e54ac1efeb commit r14-10450-g2249c6348835c817f43c9fc55eac66e54ac1efeb Author: Patrick Palka Date: Mon Jul 15 18:07:55 2024 -0400 c++: alias template with dependent attributes [PR115897] Here we're prematurely stripping the dependent alias template-id A to its defining-type-id T when used as a template argument, which in turn causes us to essentially ignore A's vector_size attribute in the outer template-id. This has always been a problem for class template-ids it seems, and after r14-2170 variable template-ids are affected as well. This patch marks alias templates that have a dependent attribute as complex (as with e.g. constrained alias templates) so that we don't look through them prematurely. PR c++/115897 gcc/cp/ChangeLog: * pt.cc (complex_alias_template_p): Return true for an alias template with attributes. (get_underlying_template): Don't look through an alias template with attributes. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/alias-decl-77.C: New test. Reviewed-by: Jason Merrill (cherry picked from commit 7954bb4fcb6fa80f6bb840133314885011821188) Diff: --- gcc/cp/pt.cc | 10 ++ gcc/testsuite/g++.dg/cpp0x/alias-decl-77.C | 32 ++ 2 files changed, 42 insertions(+) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 580c3fc2cb2b..83638fd74b4d 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -6655,6 +6655,11 @@ complex_alias_template_p (const_tree tmpl, tree *seen_out) if (get_constraints (tmpl)) return true; + /* An alias with dependent type attributes is complex. */ + if (any_dependent_type_attributes_p (DECL_ATTRIBUTES + (DECL_TEMPLATE_RESULT (tmpl +return true; + if (!complex_alias_tmpl_info) complex_alias_tmpl_info = hash_map::create_ggc (13); @@ -6807,6 +6812,11 @@ get_underlying_template (tree tmpl) if (!at_least_as_constrained (underlying, tmpl)) break; + /* If TMPL adds dependent type attributes, it isn't equivalent. */ + if (any_dependent_type_attributes_p (DECL_ATTRIBUTES + (DECL_TEMPLATE_RESULT (tmpl + break; + /* Alias is equivalent. Strip it and repeat. */ tmpl = underlying; } diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-77.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-77.C new file mode 100644 index ..f72e4cc26538 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-77.C @@ -0,0 +1,32 @@ +// PR c++/115897 +// { dg-do compile { target c++11 } } + +template +struct is_same { static constexpr bool value = __is_same(T, U); }; + +#if __cpp_variable_templates +template +constexpr bool is_same_v = __is_same(T, U); +#endif + +template +using A [[gnu::vector_size(16)]] = T; + +template +using B = T; + +template +using C [[gnu::vector_size(16)]] = B; + +template +void f() { + static_assert(!is_same>::value, ""); + static_assert(is_same, A>::value, ""); + +#if __cpp_variable_templates + static_assert(!is_same_v>, ""); + static_assert(is_same_v, A>, ""); +#endif +}; + +template void f();
[gcc r14-10451] c++: constrained partial spec type context [PR111890]
https://gcc.gnu.org/g:1bbfe788d1a76979e5be14169248bc34106e9c03 commit r14-10451-g1bbfe788d1a76979e5be14169248bc34106e9c03 Author: Patrick Palka Date: Wed Jul 17 11:08:35 2024 -0400 c++: constrained partial spec type context [PR111890] maybe_new_partial_specialization wasn't propagating TYPE_CONTEXT when creating a new class type corresponding to a constrained partial spec, which do_friend relies on via template_class_depth to distinguish a template friend from a non-template friend, and so in the below testcase we were incorrectly instantiating the non-template operator+ as if it were a template leading to an ICE. PR c++/111890 gcc/cp/ChangeLog: * pt.cc (maybe_new_partial_specialization): Propagate TYPE_CONTEXT to the newly created partial specialization. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-partial-spec15.C: New test. Reviewed-by: Jason Merrill (cherry picked from commit 247335823f420eb1dd56f4bf32ac78d441f5ccc2) Diff: --- gcc/cp/pt.cc | 1 + gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec15.C | 20 2 files changed, 21 insertions(+) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 83638fd74b4d..80d0ca6d0dde 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -994,6 +994,7 @@ maybe_new_partial_specialization (tree& type) tree t = make_class_type (TREE_CODE (type)); CLASSTYPE_DECLARED_CLASS (t) = CLASSTYPE_DECLARED_CLASS (type); SET_TYPE_TEMPLATE_INFO (t, build_template_info (tmpl, args)); + TYPE_CONTEXT (t) = TYPE_CONTEXT (type); /* We only need a separate type node for storing the definition of this partial specialization; uses of S are unconstrained, so all are diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec15.C b/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec15.C new file mode 100644 index ..ad01a390fefd --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec15.C @@ -0,0 +1,20 @@ +// PR c++/111890 +// { dg-do compile { target c++20 } } + +template +struct A { + template + struct B { }; + + template requires T::value + struct B { }; + + template requires (sizeof(T) == sizeof(int)) + struct B { +friend void operator+(B&, int) { } + }; +}; + +void f(A::B b) { + b + 0; +}
[gcc r14-10449] c++: bad 'this' conversion for nullary memfn [PR106760]
https://gcc.gnu.org/g:79c5a09f959dc63824bd005522a072424f16d89d commit r14-10449-g79c5a09f959dc63824bd005522a072424f16d89d Author: Patrick Palka Date: Fri Jun 28 19:45:21 2024 -0400 c++: bad 'this' conversion for nullary memfn [PR106760] Here we notice the 'this' conversion for the call f() is bad, so we correctly defer deduction for the template candidate, but we end up never adding it to 'bad_cands' since missing_conversion_p for it returns false (its only argument is 'this' which has already been determined to be bad). This is not a huge deal, but it causes us to longer accept the call with -fpermissive in release builds, and a tree check ICE in checking builds. So if we have a non-strictly viable template candidate that has not been instantiated, then we need to add it to 'bad_cands' even if no argument conversion is missing. PR c++/106760 gcc/cp/ChangeLog: * call.cc (add_candidates): Relax test for adding a candidate to 'bad_cands' to also accept an uninstantiated template candidate that has no missing conversions. gcc/testsuite/ChangeLog: * g++.dg/ext/conv3.C: New test. Reviewed-by: Jason Merrill (cherry picked from commit 50073ffae0a9b8feb9b36fdafdebd9885f6d7dc8) Diff: --- gcc/cp/call.cc | 3 ++- gcc/testsuite/g++.dg/ext/conv3.C | 13 + 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index f5584c92efb8..844a7e2b35d7 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -6742,7 +6742,8 @@ add_candidates (tree fns, tree first_arg, const vec *args, if (cand->viable == -1 && shortcut_bad_convs - && missing_conversion_p (cand)) + && (missing_conversion_p (cand) + || TREE_CODE (cand->fn) == TEMPLATE_DECL)) { /* This candidate has been tentatively marked non-strictly viable, and we didn't compute all argument conversions for it (having diff --git a/gcc/testsuite/g++.dg/ext/conv3.C b/gcc/testsuite/g++.dg/ext/conv3.C new file mode 100644 index ..7324d5600561 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/conv3.C @@ -0,0 +1,13 @@ +// PR c++/106760 +// { dg-additional-options "-fpermissive" } + +struct S { + template int f(); + template int g(...); +}; + +int main() { + const S s; + s.f(); // { dg-warning "discards qualifiers" } + s.g(); // { dg-warning "discards qualifiers" } +}
[gcc r15-2098] c++: constrained partial spec type context [PR111890]
https://gcc.gnu.org/g:247335823f420eb1dd56f4bf32ac78d441f5ccc2 commit r15-2098-g247335823f420eb1dd56f4bf32ac78d441f5ccc2 Author: Patrick Palka Date: Wed Jul 17 11:08:35 2024 -0400 c++: constrained partial spec type context [PR111890] maybe_new_partial_specialization wasn't propagating TYPE_CONTEXT when creating a new class type corresponding to a constrained partial spec, which do_friend relies on via template_class_depth to distinguish a template friend from a non-template friend, and so in the below testcase we were incorrectly instantiating the non-template operator+ as if it were a template leading to an ICE. PR c++/111890 gcc/cp/ChangeLog: * pt.cc (maybe_new_partial_specialization): Propagate TYPE_CONTEXT to the newly created partial specialization. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-partial-spec15.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/pt.cc | 1 + gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec15.C | 20 2 files changed, 21 insertions(+) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 4d72ff60cb8e..0620c8c023a2 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -992,6 +992,7 @@ maybe_new_partial_specialization (tree& type) tree t = make_class_type (TREE_CODE (type)); CLASSTYPE_DECLARED_CLASS (t) = CLASSTYPE_DECLARED_CLASS (type); SET_TYPE_TEMPLATE_INFO (t, build_template_info (tmpl, args)); + TYPE_CONTEXT (t) = TYPE_CONTEXT (type); /* We only need a separate type node for storing the definition of this partial specialization; uses of S are unconstrained, so all are diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec15.C b/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec15.C new file mode 100644 index ..ad01a390fefd --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec15.C @@ -0,0 +1,20 @@ +// PR c++/111890 +// { dg-do compile { target c++20 } } + +template +struct A { + template + struct B { }; + + template requires T::value + struct B { }; + + template requires (sizeof(T) == sizeof(int)) + struct B { +friend void operator+(B&, int) { } + }; +}; + +void f(A::B b) { + b + 0; +}
[gcc r15-2047] c++: alias template with dependent attributes [PR115897]
https://gcc.gnu.org/g:7954bb4fcb6fa80f6bb840133314885011821188 commit r15-2047-g7954bb4fcb6fa80f6bb840133314885011821188 Author: Patrick Palka Date: Mon Jul 15 18:07:55 2024 -0400 c++: alias template with dependent attributes [PR115897] Here we're prematurely stripping the dependent alias template-id A to its defining-type-id T when used as a template argument, which in turn causes us to essentially ignore A's vector_size attribute in the outer template-id. This has always been a problem for class template-ids it seems, and after r14-2170 variable template-ids are affected as well. This patch marks alias templates that have a dependent attribute as complex (as with e.g. constrained alias templates) so that we don't look through them prematurely. PR c++/115897 gcc/cp/ChangeLog: * pt.cc (complex_alias_template_p): Return true for an alias template with attributes. (get_underlying_template): Don't look through an alias template with attributes. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/alias-decl-77.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/pt.cc | 10 ++ gcc/testsuite/g++.dg/cpp0x/alias-decl-77.C | 32 ++ 2 files changed, 42 insertions(+) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index e38e02488be1..4d72ff60cb8e 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -6628,6 +6628,11 @@ complex_alias_template_p (const_tree tmpl, tree *seen_out) if (get_constraints (tmpl)) return true; + /* An alias with dependent type attributes is complex. */ + if (any_dependent_type_attributes_p (DECL_ATTRIBUTES + (DECL_TEMPLATE_RESULT (tmpl +return true; + if (!complex_alias_tmpl_info) complex_alias_tmpl_info = hash_map::create_ggc (13); @@ -6780,6 +6785,11 @@ get_underlying_template (tree tmpl) if (!at_least_as_constrained (underlying, tmpl)) break; + /* If TMPL adds dependent type attributes, it isn't equivalent. */ + if (any_dependent_type_attributes_p (DECL_ATTRIBUTES + (DECL_TEMPLATE_RESULT (tmpl + break; + /* Alias is equivalent. Strip it and repeat. */ tmpl = underlying; } diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-77.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-77.C new file mode 100644 index ..f72e4cc26538 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-77.C @@ -0,0 +1,32 @@ +// PR c++/115897 +// { dg-do compile { target c++11 } } + +template +struct is_same { static constexpr bool value = __is_same(T, U); }; + +#if __cpp_variable_templates +template +constexpr bool is_same_v = __is_same(T, U); +#endif + +template +using A [[gnu::vector_size(16)]] = T; + +template +using B = T; + +template +using C [[gnu::vector_size(16)]] = B; + +template +void f() { + static_assert(!is_same>::value, ""); + static_assert(is_same, A>::value, ""); + +#if __cpp_variable_templates + static_assert(!is_same_v>, ""); + static_assert(is_same_v, A>, ""); +#endif +}; + +template void f();
[gcc r15-1717] c++: bad 'this' conversion for nullary memfn [PR106760]
https://gcc.gnu.org/g:50073ffae0a9b8feb9b36fdafdebd9885f6d7dc8 commit r15-1717-g50073ffae0a9b8feb9b36fdafdebd9885f6d7dc8 Author: Patrick Palka Date: Fri Jun 28 19:45:21 2024 -0400 c++: bad 'this' conversion for nullary memfn [PR106760] Here we notice the 'this' conversion for the call f() is bad, so we correctly defer deduction for the template candidate, but we end up never adding it to 'bad_cands' since missing_conversion_p for it returns false (its only argument is 'this' which has already been determined to be bad). This is not a huge deal, but it causes us to longer accept the call with -fpermissive in release builds, and a tree check ICE in checking builds. So if we have a non-strictly viable template candidate that has not been instantiated, then we need to add it to 'bad_cands' even if no argument conversion is missing. PR c++/106760 gcc/cp/ChangeLog: * call.cc (add_candidates): Relax test for adding a candidate to 'bad_cands' to also accept an uninstantiated template candidate that has no missing conversions. gcc/testsuite/ChangeLog: * g++.dg/ext/conv3.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/call.cc | 3 ++- gcc/testsuite/g++.dg/ext/conv3.C | 13 + 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 7bbc1fb0c78..83070b2f633 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -6742,7 +6742,8 @@ add_candidates (tree fns, tree first_arg, const vec *args, if (cand->viable == -1 && shortcut_bad_convs - && missing_conversion_p (cand)) + && (missing_conversion_p (cand) + || TREE_CODE (cand->fn) == TEMPLATE_DECL)) { /* This candidate has been tentatively marked non-strictly viable, and we didn't compute all argument conversions for it (having diff --git a/gcc/testsuite/g++.dg/ext/conv3.C b/gcc/testsuite/g++.dg/ext/conv3.C new file mode 100644 index 000..7324d560056 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/conv3.C @@ -0,0 +1,13 @@ +// PR c++/106760 +// { dg-additional-options "-fpermissive" } + +struct S { + template int f(); + template int g(...); +}; + +int main() { + const S s; + s.f(); // { dg-warning "discards qualifiers" } + s.g(); // { dg-warning "discards qualifiers" } +}
[gcc r14-10359] c++: decltype of capture proxy of ref [PR115504]
https://gcc.gnu.org/g:e6b115be1c392de415925282a38f28cd78cb6c35 commit r14-10359-ge6b115be1c392de415925282a38f28cd78cb6c35 Author: Patrick Palka Date: Tue Jun 25 20:07:15 2024 -0400 c++: decltype of capture proxy of ref [PR115504] The finish_decltype_type capture proxy handling added in r14-5330 was incorrectly stripping references in the type of the captured variable. PR c++/115504 gcc/cp/ChangeLog: * semantics.cc (finish_decltype_type): Don't strip the reference type (if any) of a capture proxy's captured variable. gcc/testsuite/ChangeLog: * g++.dg/cpp1y/decltype-auto8.C: New test. Reviewed-by: Jason Merrill (cherry picked from commit 737449e5f233feb682b5dd2cc153892ad90a79bd) Diff: --- gcc/cp/semantics.cc | 1 - gcc/testsuite/g++.dg/cpp1y/decltype-auto8.C | 22 ++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index d944decd329..b18fc7c61be 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -11904,7 +11904,6 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p, { expr = DECL_CAPTURED_VARIABLE (expr); type = TREE_TYPE (expr); - type = non_reference (type); } else { diff --git a/gcc/testsuite/g++.dg/cpp1y/decltype-auto8.C b/gcc/testsuite/g++.dg/cpp1y/decltype-auto8.C new file mode 100644 index 000..55135cecf72 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/decltype-auto8.C @@ -0,0 +1,22 @@ +// PR c++/115504 +// { dg-do compile { target c++14 } } + +void f(int& x, const int& y) { + [&x]() { +decltype(auto) a = x; +using type = decltype(x); +using type = decltype(a); +using type = int&; // not 'int' + }; + + [x]() { +decltype(auto) a = x; // { dg-error "discards qualifiers" } + }; + + [x]() mutable { +decltype(auto) a = x; +using type = decltype(x); +using type = decltype(a); +using type = int&; + }; +}
[gcc r14-10357] c++: using non-dep array var of unknown bound [PR115358]
https://gcc.gnu.org/g:33a9c4dd5fcac7e3f5d835b35fe787126339dd2b commit r14-10357-g33a9c4dd5fcac7e3f5d835b35fe787126339dd2b Author: Patrick Palka Date: Tue Jun 25 10:42:21 2024 -0400 c++: using non-dep array var of unknown bound [PR115358] For a non-dependent array variable of unknown bound, it seems we need to try instantiating its definition upon use in a template context for sake of proper checking and typing of the overall expression, like we do for function specializations with deduced return type. PR c++/115358 gcc/cp/ChangeLog: * decl2.cc (mark_used): Call maybe_instantiate_decl for an array variable with unknown bound. * semantics.cc (finish_decltype_type): Remove now redundant handling of array variables with unknown bound. * typeck.cc (cxx_sizeof_expr): Likewise. gcc/testsuite/ChangeLog: * g++.dg/template/array37.C: New test. Reviewed-by: Jason Merrill (cherry picked from commit e3915c1ad56591cbd68229a64c941c38330abd69) Diff: --- gcc/cp/decl2.cc | 2 ++ gcc/cp/semantics.cc | 7 --- gcc/cp/typeck.cc| 7 --- gcc/testsuite/g++.dg/template/array37.C | 14 ++ 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc index 88933be732d..af2e08c8a63 100644 --- a/gcc/cp/decl2.cc +++ b/gcc/cp/decl2.cc @@ -5952,6 +5952,8 @@ mark_used (tree decl, tsubst_flags_t complain /* = tf_warning_or_error */) find out its type. For OpenMP user defined reductions, we need them instantiated for reduction clauses which inline them by hand directly. */ if (undeduced_auto_decl (decl) + || (VAR_P (decl) + && VAR_HAD_UNKNOWN_BOUND (decl)) || (TREE_CODE (decl) == FUNCTION_DECL && DECL_OMP_DECLARE_REDUCTION_P (decl))) maybe_instantiate_decl (decl); diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index 4513066d2ed..d944decd329 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -11835,13 +11835,6 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p, return error_mark_node; } - /* To get the size of a static data member declared as an array of - unknown bound, we need to instantiate it. */ - if (VAR_P (expr) - && VAR_HAD_UNKNOWN_BOUND (expr) - && DECL_TEMPLATE_INSTANTIATION (expr)) -instantiate_decl (expr, /*defer_ok*/true, /*expl_inst_mem*/false); - if (id_expression_or_member_access_p) { /* If e is an id-expression or a class member access (5.2.5 diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc index 42578beb85b..21436f836fa 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -2128,13 +2128,6 @@ cxx_sizeof_expr (location_t loc, tree e, tsubst_flags_t complain) location_t e_loc = cp_expr_loc_or_loc (e, loc); STRIP_ANY_LOCATION_WRAPPER (e); - /* To get the size of a static data member declared as an array of - unknown bound, we need to instantiate it. */ - if (VAR_P (e) - && VAR_HAD_UNKNOWN_BOUND (e) - && DECL_TEMPLATE_INSTANTIATION (e)) -instantiate_decl (e, /*defer_ok*/true, /*expl_inst_mem*/false); - if (TREE_CODE (e) == PARM_DECL && DECL_ARRAY_PARAMETER_P (e) && (complain & tf_warning)) diff --git a/gcc/testsuite/g++.dg/template/array37.C b/gcc/testsuite/g++.dg/template/array37.C new file mode 100644 index 000..c5c11663a4d --- /dev/null +++ b/gcc/testsuite/g++.dg/template/array37.C @@ -0,0 +1,14 @@ +// PR c++/115358 + +template +struct A { static int STR[]; }; + +template +int A::STR[] = {1,2,3}; + +void f(int(&)[3]); + +template +void g() { + f(A::STR); // { dg-bogus "int []" } +}
[gcc r14-10358] c++: alias CTAD and copy deduction guide [PR115198]
https://gcc.gnu.org/g:a00a8d46ea6ff7130e2493e7bd9824e28e2509b7 commit r14-10358-ga00a8d46ea6ff7130e2493e7bd9824e28e2509b7 Author: Patrick Palka Date: Tue Jun 25 12:59:24 2024 -0400 c++: alias CTAD and copy deduction guide [PR115198] Here we're neglecting to update DECL_NAME during the alias CTAD guide transformation, which causes copy_guide_p to return false for the transformed copy deduction guide since DECL_NAME is still __dguide_C with TREE_TYPE C but it should be __dguide_A with TREE_TYPE A (i.e. C). This ultimately results in ambiguity during overload resolution between the copy deduction guide vs copy ctor guide. This patch makes us update DECL_NAME of a transformed guide accordingly during alias/inherited CTAD. PR c++/115198 gcc/cp/ChangeLog: * pt.cc (alias_ctad_tweaks): Update DECL_NAME of the transformed guides. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/class-deduction-alias22.C: New test. Reviewed-by: Jason Merrill (cherry picked from commit 06ebb7c6f31fe42ffdea6f51ac1ba1f6b058c090) Diff: --- gcc/cp/pt.cc | 6 +- gcc/testsuite/g++.dg/cpp2a/class-deduction-alias22.C | 14 ++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index c7aee66f068..580c3fc2cb2 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -30338,13 +30338,14 @@ alias_ctad_tweaks (tree tmpl, tree uguides) any). */ enum { alias, inherited } ctad_kind; - tree atype, fullatparms, utype; + tree atype, fullatparms, utype, name; if (TREE_CODE (tmpl) == TEMPLATE_DECL) { ctad_kind = alias; atype = TREE_TYPE (tmpl); fullatparms = DECL_TEMPLATE_PARMS (tmpl); utype = DECL_ORIGINAL_TYPE (DECL_TEMPLATE_RESULT (tmpl)); + name = dguide_name (tmpl); } else { @@ -30352,6 +30353,8 @@ alias_ctad_tweaks (tree tmpl, tree uguides) atype = NULL_TREE; fullatparms = TREE_PURPOSE (tmpl); utype = TREE_VALUE (tmpl); + name = dguide_name (TPARMS_PRIMARY_TEMPLATE + (INNERMOST_TEMPLATE_PARMS (fullatparms))); } tsubst_flags_t complain = tf_warning_or_error; @@ -30447,6 +30450,7 @@ alias_ctad_tweaks (tree tmpl, tree uguides) } if (g == error_mark_node) continue; + DECL_NAME (g) = name; if (nfparms == 0) { /* The targs are all non-dependent, so g isn't a template. */ diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias22.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias22.C new file mode 100644 index 000..9c6c841166a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias22.C @@ -0,0 +1,14 @@ +// PR c++/115198 +// { dg-do compile { target c++20 } } + +template +struct C { + C() = default; + C(const C&) = default; +}; + +template +using A = C; + +C c; +A a = c; // { dg-bogus "ambiguous" }
[gcc r15-1631] c++: decltype of capture proxy of ref [PR115504]
https://gcc.gnu.org/g:737449e5f233feb682b5dd2cc153892ad90a79bd commit r15-1631-g737449e5f233feb682b5dd2cc153892ad90a79bd Author: Patrick Palka Date: Tue Jun 25 20:07:15 2024 -0400 c++: decltype of capture proxy of ref [PR115504] The finish_decltype_type capture proxy handling added in r14-5330 was incorrectly stripping references in the type of the captured variable. PR c++/115504 gcc/cp/ChangeLog: * semantics.cc (finish_decltype_type): Don't strip the reference type (if any) of a capture proxy's captured variable. gcc/testsuite/ChangeLog: * g++.dg/cpp1y/decltype-auto8.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/semantics.cc | 1 - gcc/testsuite/g++.dg/cpp1y/decltype-auto8.C | 22 ++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index 8e3e4e23b72..44de4c9a529 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -12071,7 +12071,6 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p, { expr = DECL_CAPTURED_VARIABLE (expr); type = TREE_TYPE (expr); - type = non_reference (type); } else { diff --git a/gcc/testsuite/g++.dg/cpp1y/decltype-auto8.C b/gcc/testsuite/g++.dg/cpp1y/decltype-auto8.C new file mode 100644 index 000..55135cecf72 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/decltype-auto8.C @@ -0,0 +1,22 @@ +// PR c++/115504 +// { dg-do compile { target c++14 } } + +void f(int& x, const int& y) { + [&x]() { +decltype(auto) a = x; +using type = decltype(x); +using type = decltype(a); +using type = int&; // not 'int' + }; + + [x]() { +decltype(auto) a = x; // { dg-error "discards qualifiers" } + }; + + [x]() mutable { +decltype(auto) a = x; +using type = decltype(x); +using type = decltype(a); +using type = int&; + }; +}
[gcc r15-1615] c++: alias CTAD and copy deduction guide [PR115198]
https://gcc.gnu.org/g:06ebb7c6f31fe42ffdea6f51ac1ba1f6b058c090 commit r15-1615-g06ebb7c6f31fe42ffdea6f51ac1ba1f6b058c090 Author: Patrick Palka Date: Tue Jun 25 12:59:24 2024 -0400 c++: alias CTAD and copy deduction guide [PR115198] Here we're neglecting to update DECL_NAME during the alias CTAD guide transformation, which causes copy_guide_p to return false for the transformed copy deduction guide since DECL_NAME is still __dguide_C with TREE_TYPE C but it should be __dguide_A with TREE_TYPE A (i.e. C). This ultimately results in ambiguity during overload resolution between the copy deduction guide vs copy ctor guide. This patch makes us update DECL_NAME of a transformed guide accordingly during alias/inherited CTAD. PR c++/115198 gcc/cp/ChangeLog: * pt.cc (alias_ctad_tweaks): Update DECL_NAME of the transformed guides. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/class-deduction-alias22.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/pt.cc | 6 +- gcc/testsuite/g++.dg/cpp2a/class-deduction-alias22.C | 14 ++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 607753ae6b7..daa8ac386dc 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -30342,13 +30342,14 @@ alias_ctad_tweaks (tree tmpl, tree uguides) any). */ enum { alias, inherited } ctad_kind; - tree atype, fullatparms, utype; + tree atype, fullatparms, utype, name; if (TREE_CODE (tmpl) == TEMPLATE_DECL) { ctad_kind = alias; atype = TREE_TYPE (tmpl); fullatparms = DECL_TEMPLATE_PARMS (tmpl); utype = DECL_ORIGINAL_TYPE (DECL_TEMPLATE_RESULT (tmpl)); + name = dguide_name (tmpl); } else { @@ -30356,6 +30357,8 @@ alias_ctad_tweaks (tree tmpl, tree uguides) atype = NULL_TREE; fullatparms = TREE_PURPOSE (tmpl); utype = TREE_VALUE (tmpl); + name = dguide_name (TPARMS_PRIMARY_TEMPLATE + (INNERMOST_TEMPLATE_PARMS (fullatparms))); } tsubst_flags_t complain = tf_warning_or_error; @@ -30451,6 +30454,7 @@ alias_ctad_tweaks (tree tmpl, tree uguides) } if (g == error_mark_node) continue; + DECL_NAME (g) = name; if (nfparms == 0) { /* The targs are all non-dependent, so g isn't a template. */ diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias22.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias22.C new file mode 100644 index 000..9c6c841166a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias22.C @@ -0,0 +1,14 @@ +// PR c++/115198 +// { dg-do compile { target c++20 } } + +template +struct C { + C() = default; + C(const C&) = default; +}; + +template +using A = C; + +C c; +A a = c; // { dg-bogus "ambiguous" }
[gcc r15-1614] c++: using non-dep array var of unknown bound [PR115358]
https://gcc.gnu.org/g:e3915c1ad56591cbd68229a64c941c38330abd69 commit r15-1614-ge3915c1ad56591cbd68229a64c941c38330abd69 Author: Patrick Palka Date: Tue Jun 25 10:42:21 2024 -0400 c++: using non-dep array var of unknown bound [PR115358] For a non-dependent array variable of unknown bound, it seems we need to try instantiating its definition upon use in a template context for sake of proper checking and typing of the overall expression, like we do for function specializations with deduced return type. PR c++/115358 gcc/cp/ChangeLog: * decl2.cc (mark_used): Call maybe_instantiate_decl for an array variable with unknown bound. * semantics.cc (finish_decltype_type): Remove now redundant handling of array variables with unknown bound. * typeck.cc (cxx_sizeof_expr): Likewise. gcc/testsuite/ChangeLog: * g++.dg/template/array37.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/decl2.cc | 2 ++ gcc/cp/semantics.cc | 7 --- gcc/cp/typeck.cc| 7 --- gcc/testsuite/g++.dg/template/array37.C | 14 ++ 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc index 6c3ef60d51f..cdd2b8aada2 100644 --- a/gcc/cp/decl2.cc +++ b/gcc/cp/decl2.cc @@ -6001,6 +6001,8 @@ mark_used (tree decl, tsubst_flags_t complain /* = tf_warning_or_error */) find out its type. For OpenMP user defined reductions, we need them instantiated for reduction clauses which inline them by hand directly. */ if (undeduced_auto_decl (decl) + || (VAR_P (decl) + && VAR_HAD_UNKNOWN_BOUND (decl)) || (TREE_CODE (decl) == FUNCTION_DECL && DECL_OMP_DECLARE_REDUCTION_P (decl))) maybe_instantiate_decl (decl); diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index 08f5f245e7d..6c1813d37c6 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -12002,13 +12002,6 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p, return error_mark_node; } - /* To get the size of a static data member declared as an array of - unknown bound, we need to instantiate it. */ - if (VAR_P (expr) - && VAR_HAD_UNKNOWN_BOUND (expr) - && DECL_TEMPLATE_INSTANTIATION (expr)) -instantiate_decl (expr, /*defer_ok*/true, /*expl_inst_mem*/false); - if (id_expression_or_member_access_p) { /* If e is an id-expression or a class member access (5.2.5 diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc index 717eb63eb98..50f48768a95 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -2130,13 +2130,6 @@ cxx_sizeof_expr (location_t loc, tree e, tsubst_flags_t complain) location_t e_loc = cp_expr_loc_or_loc (e, loc); STRIP_ANY_LOCATION_WRAPPER (e); - /* To get the size of a static data member declared as an array of - unknown bound, we need to instantiate it. */ - if (VAR_P (e) - && VAR_HAD_UNKNOWN_BOUND (e) - && DECL_TEMPLATE_INSTANTIATION (e)) -instantiate_decl (e, /*defer_ok*/true, /*expl_inst_mem*/false); - if (TREE_CODE (e) == PARM_DECL && DECL_ARRAY_PARAMETER_P (e) && (complain & tf_warning)) diff --git a/gcc/testsuite/g++.dg/template/array37.C b/gcc/testsuite/g++.dg/template/array37.C new file mode 100644 index 000..c5c11663a4d --- /dev/null +++ b/gcc/testsuite/g++.dg/template/array37.C @@ -0,0 +1,14 @@ +// PR c++/115358 + +template +struct A { static int STR[]; }; + +template +int A::STR[] = {1,2,3}; + +void f(int(&)[3]); + +template +void g() { + f(A::STR); // { dg-bogus "int []" } +}
[gcc r14-10320] c++: undeclared identifier in requires-clause [PR99678]
https://gcc.gnu.org/g:20cda2e85c307096a3856f7f27215b8a28982fb6 commit r14-10320-g20cda2e85c307096a3856f7f27215b8a28982fb6 Author: Patrick Palka Date: Thu Jun 13 10:16:10 2024 -0400 c++: undeclared identifier in requires-clause [PR99678] Since the terms of a requires-clause are grammatically primary-expressions and not e.g. postfix-expressions, it seems we need to explicitly handle and diagnose the case where a term parses to a bare unresolved identifier, like cp_parser_postfix_expression does, since cp_parser_primary_expression leaves that up to its callers. Otherwise we incorrectly accept the first three requires-clauses below. Note that the only occurrences of primary-expression in the grammar are postfix-expression and constraint-logical-and-expression, so it's not too surprising that we need this special handling here. PR c++/99678 gcc/cp/ChangeLog: * parser.cc (cp_parser_constraint_primary_expression): Diagnose a bare unresolved unqualified-id. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-requires38.C: New test. Reviewed-by: Jason Merrill (cherry picked from commit d387ecb2b2f44f33fd6a7c5ec7eadaf6dd70efc9) Diff: --- gcc/cp/parser.cc | 2 ++ gcc/testsuite/g++.dg/cpp2a/concepts-requires38.C | 14 ++ 2 files changed, 16 insertions(+) diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 598380dda089..6b786ed8266f 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -31225,6 +31225,8 @@ cp_parser_constraint_primary_expression (cp_parser *parser, bool lambda_p) } if (pce == pce_ok) { + if (idk == CP_ID_KIND_UNQUALIFIED && identifier_p (expr)) + expr = unqualified_name_lookup_error (expr); cp_lexer_commit_tokens (parser->lexer); return finish_constraint_primary_expr (expr); } diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires38.C b/gcc/testsuite/g++.dg/cpp2a/concepts-requires38.C new file mode 100644 index ..663195b79cc7 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires38.C @@ -0,0 +1,14 @@ +// PR c++/99678 +// { dg-do compile { target c++20 } } + +template +void f1() requires undeclared_identifier; // { dg-error "not declared" } + +template +void f2() requires true && undeclared_identifier; // { dg-error "not declared" } + +template +void f3() requires false || undeclared_identifier; // { dg-error "not declared" } + +template +void f4() requires undeclared_identifier(T{}); // { dg-error "must be enclosed in parentheses" }
[gcc r14-10319] c++: ICE w/ ambig and non-strictly-viable cands [PR115239]
https://gcc.gnu.org/g:4df86402990e2f45e02a367f1734a22ebc041e98 commit r14-10319-g4df86402990e2f45e02a367f1734a22ebc041e98 Author: Patrick Palka Date: Thu Jun 13 10:02:43 2024 -0400 c++: ICE w/ ambig and non-strictly-viable cands [PR115239] Here during overload resolution we have two strictly viable ambiguous candidates #1 and #2, and two non-strictly viable candidates #3 and #4 which we hold on to ever since r14-6522. These latter candidates have an empty second arg conversion since the first arg conversion was deemed bad, and this trips up joust when called on #3 and #4 which assumes all arg conversions are there. We can fix this by making joust robust to empty arg conversions, but in this situation we shouldn't need to compare #3 and #4 at all given that we have a strictly viable candidate. To that end, this patch makes tourney shortcut considering non-strictly viable candidates upon encountering ambiguity between two strictly viable candidates (taking advantage of the fact that the candidates list is sorted according to viability via splice_viable). PR c++/115239 gcc/cp/ChangeLog: * call.cc (tourney): Don't consider a non-strictly viable candidate as the champ if there was ambiguity between two strictly viable candidates. gcc/testsuite/ChangeLog: * g++.dg/overload/error7.C: New test. Reviewed-by: Jason Merrill (cherry picked from commit 7fed7e9bbc57d502e141e079a6be2706bdbd4560) Diff: --- gcc/cp/call.cc | 3 ++- gcc/testsuite/g++.dg/overload/error7.C | 10 ++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 38b9c4f08601..f5584c92efb8 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -13488,7 +13488,8 @@ tourney (struct z_candidate *candidates, tsubst_flags_t complain) { previous_worse_champ = nullptr; champ = &(*challenger)->next; - if (!*champ || !(*champ)->viable) + if (!*champ || !(*champ)->viable + || (*champ)->viable < (*challenger)->viable) { champ = nullptr; break; diff --git a/gcc/testsuite/g++.dg/overload/error7.C b/gcc/testsuite/g++.dg/overload/error7.C new file mode 100644 index ..de50ce5f66e4 --- /dev/null +++ b/gcc/testsuite/g++.dg/overload/error7.C @@ -0,0 +1,10 @@ +// PR c++/115239 + +bool foo(char *, long); // #1, strictly viable, ambig with #2 +bool foo(char *, unsigned); // #2, strictly viable, ambig with #1 +bool foo(char, long); // #3, non-strictly viable +bool foo(char, unsigned); // #4, non-strictly viable + +int main() { + foo((char *)0, 0); // { dg-error "ambiguous" } +}
[gcc r14-10318] c++: visibility wrt concept-id as targ [PR115283]
https://gcc.gnu.org/g:9583f781e17d4da881ee64db43af939402331413 commit r14-10318-g9583f781e17d4da881ee64db43af939402331413 Author: Patrick Palka Date: Wed Jun 12 20:05:05 2024 -0400 c++: visibility wrt concept-id as targ [PR115283] Like with alias templates, it seems we don't maintain visibility flags for concepts either, so min_vis_expr_r should ignore them for now. Otherwise after r14-6789 we may incorrectly give a function template that uses a concept-id in its signature internal linkage. PR c++/115283 gcc/cp/ChangeLog: * decl2.cc (min_vis_expr_r) : Ignore concepts. gcc/testsuite/ChangeLog: * g++.dg/template/linkage5.C: New test. Reviewed-by: Jason Merrill (cherry picked from commit b1fe718cbe0c8883af89f52e0aad3ebf913683de) Diff: --- gcc/cp/decl2.cc | 5 +++-- gcc/testsuite/g++.dg/template/linkage5.C | 14 ++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc index 806a2a4bc69d..88933be732db 100644 --- a/gcc/cp/decl2.cc +++ b/gcc/cp/decl2.cc @@ -2710,9 +2710,10 @@ min_vis_expr_r (tree *tp, int */*walk_subtrees*/, void *data) break; case TEMPLATE_DECL: - if (DECL_ALIAS_TEMPLATE_P (t)) + if (DECL_ALIAS_TEMPLATE_P (t) || standard_concept_p (t)) /* FIXME: We don't maintain TREE_PUBLIC / DECL_VISIBILITY for - alias templates so we can't trust it here (PR107906). */ + alias templates so we can't trust it here (PR107906). Ditto + for concepts. */ break; t = DECL_TEMPLATE_RESULT (t); /* Fall through. */ diff --git a/gcc/testsuite/g++.dg/template/linkage5.C b/gcc/testsuite/g++.dg/template/linkage5.C new file mode 100644 index ..7e8f93f546f1 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/linkage5.C @@ -0,0 +1,14 @@ +// PR c++/115283 +// { dg-final { scan-assembler "(weak|glob)\[^\n\]*_Z1fIiEv1AIX1CIT_EEE" } } +// { dg-do compile { target c++20 } } + +template +concept C = true; + +template +struct A { }; + +template +void f(A>) { } + +template void f(A);
[gcc r15-1294] c++: undeclared identifier in requires-clause [PR99678]
https://gcc.gnu.org/g:d387ecb2b2f44f33fd6a7c5ec7eadaf6dd70efc9 commit r15-1294-gd387ecb2b2f44f33fd6a7c5ec7eadaf6dd70efc9 Author: Patrick Palka Date: Thu Jun 13 10:16:10 2024 -0400 c++: undeclared identifier in requires-clause [PR99678] Since the terms of a requires-clause are grammatically primary-expressions and not e.g. postfix-expressions, it seems we need to explicitly handle and diagnose the case where a term parses to a bare unresolved identifier, like cp_parser_postfix_expression does, since cp_parser_primary_expression leaves that up to its callers. Otherwise we incorrectly accept the first three requires-clauses below. Note that the only occurrences of primary-expression in the grammar are postfix-expression and constraint-logical-and-expression, so it's not too surprising that we need this special handling here. PR c++/99678 gcc/cp/ChangeLog: * parser.cc (cp_parser_constraint_primary_expression): Diagnose a bare unresolved unqualified-id. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-requires38.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/parser.cc | 2 ++ gcc/testsuite/g++.dg/cpp2a/concepts-requires38.C | 14 ++ 2 files changed, 16 insertions(+) diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 01a19080d6c7..e7409b856f11 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -31525,6 +31525,8 @@ cp_parser_constraint_primary_expression (cp_parser *parser, bool lambda_p) } if (pce == pce_ok) { + if (idk == CP_ID_KIND_UNQUALIFIED && identifier_p (expr)) + expr = unqualified_name_lookup_error (expr); cp_lexer_commit_tokens (parser->lexer); return finish_constraint_primary_expr (expr); } diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires38.C b/gcc/testsuite/g++.dg/cpp2a/concepts-requires38.C new file mode 100644 index ..663195b79cc7 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires38.C @@ -0,0 +1,14 @@ +// PR c++/99678 +// { dg-do compile { target c++20 } } + +template +void f1() requires undeclared_identifier; // { dg-error "not declared" } + +template +void f2() requires true && undeclared_identifier; // { dg-error "not declared" } + +template +void f3() requires false || undeclared_identifier; // { dg-error "not declared" } + +template +void f4() requires undeclared_identifier(T{}); // { dg-error "must be enclosed in parentheses" }
[gcc r15-1292] c++: ICE w/ ambig and non-strictly-viable cands [PR115239]
https://gcc.gnu.org/g:7fed7e9bbc57d502e141e079a6be2706bdbd4560 commit r15-1292-g7fed7e9bbc57d502e141e079a6be2706bdbd4560 Author: Patrick Palka Date: Thu Jun 13 10:02:43 2024 -0400 c++: ICE w/ ambig and non-strictly-viable cands [PR115239] Here during overload resolution we have two strictly viable ambiguous candidates #1 and #2, and two non-strictly viable candidates #3 and #4 which we hold on to ever since r14-6522. These latter candidates have an empty second arg conversion since the first arg conversion was deemed bad, and this trips up joust when called on #3 and #4 which assumes all arg conversions are there. We can fix this by making joust robust to empty arg conversions, but in this situation we shouldn't need to compare #3 and #4 at all given that we have a strictly viable candidate. To that end, this patch makes tourney shortcut considering non-strictly viable candidates upon encountering ambiguity between two strictly viable candidates (taking advantage of the fact that the candidates list is sorted according to viability via splice_viable). PR c++/115239 gcc/cp/ChangeLog: * call.cc (tourney): Don't consider a non-strictly viable candidate as the champ if there was ambiguity between two strictly viable candidates. gcc/testsuite/ChangeLog: * g++.dg/overload/error7.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/call.cc | 3 ++- gcc/testsuite/g++.dg/overload/error7.C | 10 ++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 85536fc25ff2..7bbc1fb0c789 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -13490,7 +13490,8 @@ tourney (struct z_candidate *candidates, tsubst_flags_t complain) { previous_worse_champ = nullptr; champ = &(*challenger)->next; - if (!*champ || !(*champ)->viable) + if (!*champ || !(*champ)->viable + || (*champ)->viable < (*challenger)->viable) { champ = nullptr; break; diff --git a/gcc/testsuite/g++.dg/overload/error7.C b/gcc/testsuite/g++.dg/overload/error7.C new file mode 100644 index ..de50ce5f66e4 --- /dev/null +++ b/gcc/testsuite/g++.dg/overload/error7.C @@ -0,0 +1,10 @@ +// PR c++/115239 + +bool foo(char *, long); // #1, strictly viable, ambig with #2 +bool foo(char *, unsigned); // #2, strictly viable, ambig with #1 +bool foo(char, long); // #3, non-strictly viable +bool foo(char, unsigned); // #4, non-strictly viable + +int main() { + foo((char *)0, 0); // { dg-error "ambiguous" } +}
[gcc r15-1227] c++: visibility wrt concept-id as targ [PR115283]
https://gcc.gnu.org/g:b1fe718cbe0c8883af89f52e0aad3ebf913683de commit r15-1227-gb1fe718cbe0c8883af89f52e0aad3ebf913683de Author: Patrick Palka Date: Wed Jun 12 20:05:05 2024 -0400 c++: visibility wrt concept-id as targ [PR115283] Like with alias templates, it seems we don't maintain visibility flags for concepts either, so min_vis_expr_r should ignore them for now. Otherwise after r14-6789 we may incorrectly give a function template that uses a concept-id in its signature internal linkage. PR c++/115283 gcc/cp/ChangeLog: * decl2.cc (min_vis_expr_r) : Ignore concepts. gcc/testsuite/ChangeLog: * g++.dg/template/linkage5.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/decl2.cc | 5 +++-- gcc/testsuite/g++.dg/template/linkage5.C | 14 ++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc index 7baff46a1921..6c3ef60d51f8 100644 --- a/gcc/cp/decl2.cc +++ b/gcc/cp/decl2.cc @@ -2723,9 +2723,10 @@ min_vis_expr_r (tree *tp, int */*walk_subtrees*/, void *data) break; case TEMPLATE_DECL: - if (DECL_ALIAS_TEMPLATE_P (t)) + if (DECL_ALIAS_TEMPLATE_P (t) || standard_concept_p (t)) /* FIXME: We don't maintain TREE_PUBLIC / DECL_VISIBILITY for - alias templates so we can't trust it here (PR107906). */ + alias templates so we can't trust it here (PR107906). Ditto + for concepts. */ break; t = DECL_TEMPLATE_RESULT (t); /* Fall through. */ diff --git a/gcc/testsuite/g++.dg/template/linkage5.C b/gcc/testsuite/g++.dg/template/linkage5.C new file mode 100644 index ..7e8f93f546f1 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/linkage5.C @@ -0,0 +1,14 @@ +// PR c++/115283 +// { dg-final { scan-assembler "(weak|glob)\[^\n\]*_Z1fIiEv1AIX1CIT_EEE" } } +// { dg-do compile { target c++20 } } + +template +concept C = true; + +template +struct A { }; + +template +void f(A>) { } + +template void f(A);
[gcc r14-10301] c++: lambda in pack expansion [PR115378]
https://gcc.gnu.org/g:ff8105b4910f7dbee326cb36b01c16ac9bf10c4b commit r14-10301-gff8105b4910f7dbee326cb36b01c16ac9bf10c4b Author: Patrick Palka Date: Fri Jun 7 12:12:30 2024 -0400 c++: lambda in pack expansion [PR115378] Here find_parameter_packs_r is incorrectly treating the 'auto' return type of a lambda as a parameter pack due to Concepts-TS specific logic added in r6-4517, leading to confusion later when expanding the pattern. Since we intend on removing Concepts TS support soon anyway, this patch fixes this by restricting the problematic logic with flag_concepts_ts. Doing so revealed that add_capture was relying on this logic to set TEMPLATE_TYPE_PARAMETER_PACK for the 'auto' type of an pack expansion init-capture, which we now need to do explicitly. PR c++/115378 gcc/cp/ChangeLog: * lambda.cc (lambda_capture_field_type): Set TEMPLATE_TYPE_PARAMETER_PACK on the auto type of an init-capture pack expansion. * pt.cc (find_parameter_packs_r) : Restrict TEMPLATE_TYPE_PARAMETER_PACK promotion with flag_concepts_ts. gcc/testsuite/ChangeLog: * g++.dg/cpp1y/decltype-auto-103497.C: Adjust expected diagnostic. * g++.dg/template/pr95672.C: Likewise. * g++.dg/cpp2a/lambda-targ5.C: New test. Reviewed-by: Jason Merrill (cherry picked from commit 5c761395402a730535983a5e49ef1775561ebc61) Diff: --- gcc/cp/lambda.cc | 3 ++- gcc/cp/pt.cc | 2 +- gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C | 2 +- gcc/testsuite/g++.dg/cpp2a/lambda-targ5.C | 15 +++ gcc/testsuite/g++.dg/template/pr95672.C | 2 +- 5 files changed, 20 insertions(+), 4 deletions(-) diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc index 4b1f9391fee..5b5e31c141e 100644 --- a/gcc/cp/lambda.cc +++ b/gcc/cp/lambda.cc @@ -223,7 +223,8 @@ lambda_capture_field_type (tree expr, bool explicit_init_p, outermost CV qualifiers of EXPR. */ type = build_reference_type (type); if (uses_parameter_packs (expr)) - /* Stick with 'auto' even if the type could be deduced. */; + /* Stick with 'auto' even if the type could be deduced. */ + TEMPLATE_TYPE_PARAMETER_PACK (auto_node) = true; else type = do_auto_deduction (type, expr, auto_node); } diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index d3f61e90422..c7aee66f068 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -3942,7 +3942,7 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data) parameter pack (14.6.3), or the type-specifier-seq of a type-id that is a pack expansion, the invented template parameter is a template parameter pack. */ - if (ppd->type_pack_expansion_p && is_auto (t) + if (flag_concepts_ts && ppd->type_pack_expansion_p && is_auto (t) && TEMPLATE_TYPE_LEVEL (t) != 0) TEMPLATE_TYPE_PARAMETER_PACK (t) = true; if (TEMPLATE_TYPE_PARAMETER_PACK (t)) diff --git a/gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C b/gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C index cedd661710c..4162361d14f 100644 --- a/gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C +++ b/gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C @@ -1,7 +1,7 @@ // PR c++/103497 // { dg-do compile { target c++14 } } -void foo(decltype(auto)... args); // { dg-error "cannot declare a parameter with .decltype.auto.." } +void foo(decltype(auto)... args); // { dg-error "contains no parameter packs" } int main() { foo(); diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-targ5.C b/gcc/testsuite/g++.dg/cpp2a/lambda-targ5.C new file mode 100644 index 000..efd4bb45d58 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/lambda-targ5.C @@ -0,0 +1,15 @@ +// PR c++/115378 +// { dg-do compile { target c++20 } } + +struct tt {}; + +template +constexpr auto __counter = 1; + +template +using _as_base = tt; + +template +struct env : _as_base>... {}; + +env t; diff --git a/gcc/testsuite/g++.dg/template/pr95672.C b/gcc/testsuite/g++.dg/template/pr95672.C index c752b4a2c08..d97b8db2e97 100644 --- a/gcc/testsuite/g++.dg/template/pr95672.C +++ b/gcc/testsuite/g++.dg/template/pr95672.C @@ -1,3 +1,3 @@ // PR c++/95672 // { dg-do compile { target c++14 } } -struct g_class : decltype (auto) ... { }; // { dg-error "invalid use of pack expansion" } +struct g_class : decltype (auto) ... { }; // { dg-error "contains no parameter packs" }
[gcc r15-1103] c++: lambda in pack expansion [PR115378]
https://gcc.gnu.org/g:5c761395402a730535983a5e49ef1775561ebc61 commit r15-1103-g5c761395402a730535983a5e49ef1775561ebc61 Author: Patrick Palka Date: Fri Jun 7 12:12:30 2024 -0400 c++: lambda in pack expansion [PR115378] Here find_parameter_packs_r is incorrectly treating the 'auto' return type of a lambda as a parameter pack due to Concepts-TS specific logic added in r6-4517, leading to confusion later when expanding the pattern. Since we intend on removing Concepts TS support soon anyway, this patch fixes this by restricting the problematic logic with flag_concepts_ts. Doing so revealed that add_capture was relying on this logic to set TEMPLATE_TYPE_PARAMETER_PACK for the 'auto' type of an pack expansion init-capture, which we now need to do explicitly. PR c++/115378 gcc/cp/ChangeLog: * lambda.cc (lambda_capture_field_type): Set TEMPLATE_TYPE_PARAMETER_PACK on the auto type of an init-capture pack expansion. * pt.cc (find_parameter_packs_r) : Restrict TEMPLATE_TYPE_PARAMETER_PACK promotion with flag_concepts_ts. gcc/testsuite/ChangeLog: * g++.dg/cpp1y/decltype-auto-103497.C: Adjust expected diagnostic. * g++.dg/template/pr95672.C: Likewise. * g++.dg/cpp2a/lambda-targ5.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/lambda.cc | 3 ++- gcc/cp/pt.cc | 2 +- gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C | 2 +- gcc/testsuite/g++.dg/cpp2a/lambda-targ5.C | 15 +++ gcc/testsuite/g++.dg/template/pr95672.C | 2 +- 5 files changed, 20 insertions(+), 4 deletions(-) diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc index 630cc4eade1..0770417810e 100644 --- a/gcc/cp/lambda.cc +++ b/gcc/cp/lambda.cc @@ -223,7 +223,8 @@ lambda_capture_field_type (tree expr, bool explicit_init_p, outermost CV qualifiers of EXPR. */ type = build_reference_type (type); if (uses_parameter_packs (expr)) - /* Stick with 'auto' even if the type could be deduced. */; + /* Stick with 'auto' even if the type could be deduced. */ + TEMPLATE_TYPE_PARAMETER_PACK (auto_node) = true; else type = do_auto_deduction (type, expr, auto_node); } diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index abbba7c6746..607753ae6b7 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -3940,7 +3940,7 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data) parameter pack (14.6.3), or the type-specifier-seq of a type-id that is a pack expansion, the invented template parameter is a template parameter pack. */ - if (ppd->type_pack_expansion_p && is_auto (t) + if (flag_concepts_ts && ppd->type_pack_expansion_p && is_auto (t) && TEMPLATE_TYPE_LEVEL (t) != 0) TEMPLATE_TYPE_PARAMETER_PACK (t) = true; if (TEMPLATE_TYPE_PARAMETER_PACK (t)) diff --git a/gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C b/gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C index cedd661710c..4162361d14f 100644 --- a/gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C +++ b/gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C @@ -1,7 +1,7 @@ // PR c++/103497 // { dg-do compile { target c++14 } } -void foo(decltype(auto)... args); // { dg-error "cannot declare a parameter with .decltype.auto.." } +void foo(decltype(auto)... args); // { dg-error "contains no parameter packs" } int main() { foo(); diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-targ5.C b/gcc/testsuite/g++.dg/cpp2a/lambda-targ5.C new file mode 100644 index 000..efd4bb45d58 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/lambda-targ5.C @@ -0,0 +1,15 @@ +// PR c++/115378 +// { dg-do compile { target c++20 } } + +struct tt {}; + +template +constexpr auto __counter = 1; + +template +using _as_base = tt; + +template +struct env : _as_base>... {}; + +env t; diff --git a/gcc/testsuite/g++.dg/template/pr95672.C b/gcc/testsuite/g++.dg/template/pr95672.C index c752b4a2c08..d97b8db2e97 100644 --- a/gcc/testsuite/g++.dg/template/pr95672.C +++ b/gcc/testsuite/g++.dg/template/pr95672.C @@ -1,3 +1,3 @@ // PR c++/95672 // { dg-do compile { target c++14 } } -struct g_class : decltype (auto) ... { }; // { dg-error "invalid use of pack expansion" } +struct g_class : decltype (auto) ... { }; // { dg-error "contains no parameter packs" }
[gcc r15-892] c++: canonicity of fn types w/ instantiated eh specs [PR115223]
https://gcc.gnu.org/g:58b8c87b7fb281e35a6817cc91a292096fdc02dc commit r15-892-g58b8c87b7fb281e35a6817cc91a292096fdc02dc Author: Patrick Palka Date: Wed May 29 04:49:37 2024 -0400 c++: canonicity of fn types w/ instantiated eh specs [PR115223] When propagating structural equality in build_cp_fntype_variant, we should consider structural equality of the exception-less variant, not of the given type which might use structural equality only because it has a (complex) noexcept-spec that we're intending to replace, as in maybe_instantiate_noexcept which calls build_exception_variant using the deferred-noexcept function type. Otherwise we might pessimistically use structural equality for a function type with a simple instantiated noexcept-spec, leading to a LTO-triggered type verification failure if we later use that (structural-equality) type as the canonical version of some other variant. PR c++/115223 gcc/cp/ChangeLog: * tree.cc (build_cp_fntype_variant): Propagate structural equality of the exception-less variant. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/noexcept87.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/tree.cc | 4 gcc/testsuite/g++.dg/cpp0x/noexcept87.C | 11 +++ 2 files changed, 15 insertions(+) diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc index fe3f034d000..72dd46e1bd1 100644 --- a/gcc/cp/tree.cc +++ b/gcc/cp/tree.cc @@ -2796,6 +2796,10 @@ build_cp_fntype_variant (tree type, cp_ref_qualifier rqual, bool complex_eh_spec_p = (cr && cr != noexcept_true_spec && !UNPARSED_NOEXCEPT_SPEC_P (cr)); + if (!complex_eh_spec_p && TYPE_RAISES_EXCEPTIONS (type)) +/* We want to consider structural equality of the exception-less + variant since we'll be replacing the exception specification. */ +type = build_cp_fntype_variant (type, rqual, /*raises=*/NULL_TREE, late); if (TYPE_STRUCTURAL_EQUALITY_P (type) || complex_eh_spec_p) /* Propagate structural equality. And always use structural equality for function types with a complex noexcept-spec since their identity diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept87.C b/gcc/testsuite/g++.dg/cpp0x/noexcept87.C new file mode 100644 index 000..339569d15ae --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/noexcept87.C @@ -0,0 +1,11 @@ +// PR c++/115223 +// { dg-do compile { target c++11 } } +// { dg-additional-options -flto } + +template +void f() noexcept(bool(T() || true)); + +void g() { f(); } + +using type = void; +type callDestructorIfNecessary() noexcept {}
[gcc r15-779] c++: canonicity of fn types w/ complex eh specs [PR115159]
https://gcc.gnu.org/g:3c98d06a9016a0fa3a806879bd168f13b8a606f8 commit r15-779-g3c98d06a9016a0fa3a806879bd168f13b8a606f8 Author: Patrick Palka Date: Wed May 22 17:45:04 2024 -0400 c++: canonicity of fn types w/ complex eh specs [PR115159] Here the member functions QList::g and QList::h are given the same function type by build_cp_fntype_variant since their noexcept-specs are equivalent according to cp_tree_equal. In doing so however this means that the function type of QList::h refers to a function parameter from QList::g, which ends up confusing modules streaming. I'm not sure if modules can be fixed to handle this situation, but regardless it seems weird in principle that a function parameter can escape in such a way. The analogous situation with a trailing return type and decltype auto g(QList &other) -> decltype(f(other)); auto h(QList &other) -> decltype(f(other)); behaves better because we don't canonicalize decltype, and so the function types of g and h are non-canonical and therefore not shared. In light of this, it seems natural to treat function types with complex noexcept-specs as non-canonical as well so that each such function declaration is given a unique function type node. (The main benefit of type canonicalization is to speed up repeated type comparisons, but it should be rare to repeatedly compare two otherwise compatible function types with complex noexcept-specs.) To that end, this patch strengthens the ce_exact case of comp_except_specs to require identity instead of equivalence of the noexcept-spec so that build_cp_fntype_variant doesn't reuse a variant when it shouldn't. In turn we need to use structural equality for types with a complex eh spec. This lets us get rid of the tricky handling of canonical types when updating unparsed noexcept-spec variants. PR c++/115159 gcc/cp/ChangeLog: * tree.cc (build_cp_fntype_variant): Always use structural equality for types with a complex exception specification. (fixup_deferred_exception_variants): Use structural equality for adjusted variants. * typeck.cc (comp_except_specs): Require == instead of cp_tree_equal for ce_exact noexcept-spec comparison. gcc/testsuite/ChangeLog: * g++.dg/modules/noexcept-2_a.H: New test. * g++.dg/modules/noexcept-2_b.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/tree.cc | 48 ++--- gcc/cp/typeck.cc| 4 ++- gcc/testsuite/g++.dg/modules/noexcept-2_a.H | 24 +++ gcc/testsuite/g++.dg/modules/noexcept-2_b.C | 4 +++ 4 files changed, 41 insertions(+), 39 deletions(-) diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc index 9d37d255d8d..4d87661b4ad 100644 --- a/gcc/cp/tree.cc +++ b/gcc/cp/tree.cc @@ -2793,9 +2793,13 @@ build_cp_fntype_variant (tree type, cp_ref_qualifier rqual, /* Canonicalize the exception specification. */ tree cr = flag_noexcept_type ? canonical_eh_spec (raises) : NULL_TREE; + bool complex_eh_spec_p = (cr && cr != noexcept_true_spec + && !UNPARSED_NOEXCEPT_SPEC_P (cr)); - if (TYPE_STRUCTURAL_EQUALITY_P (type)) -/* Propagate structural equality. */ + if (TYPE_STRUCTURAL_EQUALITY_P (type) || complex_eh_spec_p) +/* Propagate structural equality. And always use structural equality + for function types with a complex noexcept-spec since their identity + may depend on e.g. whether comparing_specializations is set. */ SET_TYPE_STRUCTURAL_EQUALITY (v); else if (TYPE_CANONICAL (type) != type || cr != raises || late) /* Build the underlying canonical type, since it is different @@ -2812,55 +2816,23 @@ build_cp_fntype_variant (tree type, cp_ref_qualifier rqual, /* TYPE is a function or method type with a deferred exception specification that has been parsed to RAISES. Fixup all the type variants that are affected in place. Via decltype &| noexcept - tricks, the unparsed spec could have escaped into the type system. - The general case is hard to fixup canonical types for. */ + tricks, the unparsed spec could have escaped into the type system. */ void fixup_deferred_exception_variants (tree type, tree raises) { tree original = TYPE_RAISES_EXCEPTIONS (type); - tree cr = flag_noexcept_type ? canonical_eh_spec (raises) : NULL_TREE; gcc_checking_assert (UNPARSED_NOEXCEPT_SPEC_P (original)); - /* Though sucky, this walk will process the canonical variants - first. */ - tree prev = NULL_TREE; for (tree variant = TYPE_MAIN_VARIANT (type); - variant; prev = variant, variant = TYPE_NEXT_VARIANT (variant)) + variant; variant = TYPE_NEXT_VARIANT (variant)) if (TYPE_RAISES_EXCEPTIONS (variant) == o
[gcc r14-10226] c++: folding non-dep enumerator from current inst [PR115139]
https://gcc.gnu.org/g:caf43cc9e5c0b3265b55e5a0dc77fc55e9618c77 commit r14-10226-gcaf43cc9e5c0b3265b55e5a0dc77fc55e9618c77 Author: Patrick Palka Date: Tue May 21 15:54:10 2024 -0400 c++: folding non-dep enumerator from current inst [PR115139] After the tsubst_copy removal r14-4796-g3e3d73ed5e85e7 GCC 14 ICEs during fold_non_dependent_expr for 'e1 | e2' below ultimately because we no longer exit early when substituting the CONST_DECLs for e1 and e2 with args=NULL_TREE and instead proceed to substitute the class context A (also with args=NULL_TREE) which ends up ICEing from tsubst_pack_expansion (due to processing_template_decl being cleared). Incidentally, the ICE went away on trunk ever since the tsubst_aggr_type removal r15-123-gf04dc89a991ddc since it changed the CONST_DECL case of tsubst_expr to use tsubst to substitute the context, which short circuits for empty args and so avoids the ICE. This patch fixes this ICE for GCC 14 by narrowly restoring the early exit for empty args that would've happened in tsubst_copy when substituting an enumerator CONST_DECL. We might as well apply this to trunk too, as a small optimization. PR c++/115139 gcc/cp/ChangeLog: * pt.cc (tsubst_expr) : Exit early if args is empty. gcc/testsuite/ChangeLog: * g++.dg/template/non-dependent33.C: New test. Reviewed-by: Marek Polacek Reviewed-by: Jason Merrill (cherry picked from commit f0c0bced62b9c728ed1e672747aa234d918da22c) Diff: --- gcc/cp/pt.cc| 2 +- gcc/testsuite/g++.dg/template/non-dependent33.C | 13 + 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index e9882f2a3e0..ba47620ec59 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -21524,7 +21524,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) if (DECL_TEMPLATE_PARM_P (t)) RETURN (RECUR (DECL_INITIAL (t))); - if (!uses_template_parms (DECL_CONTEXT (t))) + if (!args || !uses_template_parms (DECL_CONTEXT (t))) RETURN (t); /* Unfortunately, we cannot just call lookup_name here. diff --git a/gcc/testsuite/g++.dg/template/non-dependent33.C b/gcc/testsuite/g++.dg/template/non-dependent33.C new file mode 100644 index 000..ea5b41fba93 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/non-dependent33.C @@ -0,0 +1,13 @@ +// PR c++/115139 +// { dg-do compile { target c++11 } } + +template +class A { + enum E { +e1 = 1, +e2 = 2, +e3 = e1 | e2, + }; +}; + +template class A;
[gcc r15-759] c++: folding non-dep enumerator from current inst [PR115139]
https://gcc.gnu.org/g:f0c0bced62b9c728ed1e672747aa234d918da22c commit r15-759-gf0c0bced62b9c728ed1e672747aa234d918da22c Author: Patrick Palka Date: Tue May 21 15:54:10 2024 -0400 c++: folding non-dep enumerator from current inst [PR115139] After the tsubst_copy removal r14-4796-g3e3d73ed5e85e7 GCC 14 ICEs during fold_non_dependent_expr for 'e1 | e2' below ultimately because we no longer exit early when substituting the CONST_DECLs for e1 and e2 with args=NULL_TREE and instead proceed to substitute the class context A (also with args=NULL_TREE) which ends up ICEing from tsubst_pack_expansion (due to processing_template_decl being cleared). Incidentally, the ICE went away on trunk ever since the tsubst_aggr_type removal r15-123-gf04dc89a991ddc since it changed the CONST_DECL case of tsubst_expr to use tsubst to substitute the context, which short circuits for empty args and so avoids the ICE. This patch fixes this ICE for GCC 14 by narrowly restoring the early exit for empty args that would've happened in tsubst_copy when substituting an enumerator CONST_DECL. We might as well apply this to trunk too, as a small optimization. PR c++/115139 gcc/cp/ChangeLog: * pt.cc (tsubst_expr) : Exit early if args is empty. gcc/testsuite/ChangeLog: * g++.dg/template/non-dependent33.C: New test. Reviewed-by: Marek Polacek Reviewed-by: Jason Merrill Diff: --- gcc/cp/pt.cc| 2 +- gcc/testsuite/g++.dg/template/non-dependent33.C | 13 + 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index e77c48e463e..a95ce6eb3da 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -21519,7 +21519,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) if (DECL_TEMPLATE_PARM_P (t)) RETURN (RECUR (DECL_INITIAL (t))); - if (!uses_template_parms (DECL_CONTEXT (t))) + if (!args || !uses_template_parms (DECL_CONTEXT (t))) RETURN (t); /* Unfortunately, we cannot just call lookup_name here. diff --git a/gcc/testsuite/g++.dg/template/non-dependent33.C b/gcc/testsuite/g++.dg/template/non-dependent33.C new file mode 100644 index 000..ea5b41fba93 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/non-dependent33.C @@ -0,0 +1,13 @@ +// PR c++/115139 +// { dg-do compile { target c++11 } } + +template +class A { + enum E { +e1 = 1, +e2 = 2, +e3 = e1 | e2, + }; +}; + +template class A;
[gcc r14-10221] c++: aggregate CTAD w/ paren init and bases [PR115114]
https://gcc.gnu.org/g:a9837934203d41c96b5cf05e34f68c0d3311c973 commit r14-10221-ga9837934203d41c96b5cf05e34f68c0d3311c973 Author: Patrick Palka Date: Fri May 17 09:02:52 2024 -0400 c++: aggregate CTAD w/ paren init and bases [PR115114] During aggregate CTAD with paren init, we're accidentally overlooking base classes since TYPE_FIELDS of a template type doesn't contain corresponding base fields. So we need to consider them separately. PR c++/115114 gcc/cp/ChangeLog: * pt.cc (maybe_aggr_guide): Consider bases in the paren init case. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/class-deduction-aggr15.C: New test. Reviewed-by: Jason Merrill (cherry picked from commit 5aaf47cb1987bbc5508c4b9b7dad5ea7d69af2c2) Diff: --- gcc/cp/pt.cc | 7 +++ .../g++.dg/cpp2a/class-deduction-aggr15.C | 23 ++ 2 files changed, 30 insertions(+) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index b5c494e8d15e..e9882f2a3e0a 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -30205,6 +30205,13 @@ maybe_aggr_guide (tree tmpl, tree init, vec *args) else if (TREE_CODE (init) == TREE_LIST) { int len = list_length (init); + for (tree binfo : BINFO_BASE_BINFOS (TYPE_BINFO (template_type))) + { + if (!len) + break; + parms = tree_cons (NULL_TREE, BINFO_TYPE (binfo), parms); + --len; + } for (tree field = TYPE_FIELDS (template_type); len; --len, field = DECL_CHAIN (field)) diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr15.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr15.C new file mode 100644 index ..16dc0f52b64c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr15.C @@ -0,0 +1,23 @@ +// PR c++/115114 +// { dg-do compile { target c++20 } } + +struct X {} x; +struct Y {} y; + +template +struct A : T { + U m; +}; + +using ty1 = decltype(A{x, 42}); // OK +using ty1 = decltype(A(x, 42)); // OK, used to fail +using ty1 = A; + +template +struct B : T, V { + U m = 42; +}; + +using ty2 = decltype(B{x, y}); // OK +using ty2 = decltype(B(x, y)); // OK, used to fail +using ty2 = B;
[gcc r14-10220] c++: lvalueness of non-dependent assignment expr [PR114994]
https://gcc.gnu.org/g:b3399b445ba7495b0479d43f2389e64d48de870e commit r14-10220-gb3399b445ba7495b0479d43f2389e64d48de870e Author: Patrick Palka Date: Tue May 14 22:55:16 2024 -0400 c++: lvalueness of non-dependent assignment expr [PR114994] r14-4111-g6e92a6a2a72d3b made us check non-dependent simple assignment expressions ahead of time and give them a type, as was already done for compound assignments. Unlike for compound assignments however, if a simple assignment resolves to an operator overload we represent it as a (typed) MODOP_EXPR instead of a CALL_EXPR to the selected overload. (I reckoned this was at worst a pessimization -- we'll just have to repeat overload resolution at instantiatiation time.) But this turns out to break the below testcase ultimately because MODOP_EXPR (of non-reference type) is always treated as an lvalue according to lvalue_kind, which is incorrect for the MODOP_EXPR representing x=42. We can fix this by representing such class assignment expressions as CALL_EXPRs as well, but this turns out to require some tweaking of our -Wparentheses warning logic and may introduce other fallout making it unsuitable for backporting. So this patch instead fixes lvalue_kind to consider the type of a MODOP_EXPR representing a class assignment. PR c++/114994 gcc/cp/ChangeLog: * tree.cc (lvalue_kind) : For a class assignment, consider the result type. gcc/testsuite/ChangeLog: * g++.dg/template/non-dependent32.C: New test. Reviewed-by: Jason Merrill (cherry picked from commit c6cc6d4741a880109c4e0e64d5a189687fb526f6) Diff: --- gcc/cp/tree.cc | 5 - gcc/testsuite/g++.dg/template/non-dependent32.C | 18 ++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc index f1a23ffe8179..9d37d255d8d5 100644 --- a/gcc/cp/tree.cc +++ b/gcc/cp/tree.cc @@ -275,7 +275,10 @@ lvalue_kind (const_tree ref) /* We expect to see unlowered MODOP_EXPRs only during template processing. */ gcc_assert (processing_template_decl); - return clk_ordinary; + if (CLASS_TYPE_P (TREE_TYPE (TREE_OPERAND (ref, 0 + goto default_; + else + return clk_ordinary; case MODIFY_EXPR: case TYPEID_EXPR: diff --git a/gcc/testsuite/g++.dg/template/non-dependent32.C b/gcc/testsuite/g++.dg/template/non-dependent32.C new file mode 100644 index ..54252c7dfaf9 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/non-dependent32.C @@ -0,0 +1,18 @@ +// PR c++/114994 +// { dg-do compile { target c++11 } } + +struct udl_arg { + udl_arg operator=(int); +}; + +void f(udl_arg&&); + +template +void g() { + udl_arg x; + f(x=42); // { dg-bogus "cannot bind" } +} + +int main() { + g(); +}
[gcc r15-630] c++: aggregate CTAD w/ paren init and bases [PR115114]
https://gcc.gnu.org/g:5aaf47cb1987bbc5508c4b9b7dad5ea7d69af2c2 commit r15-630-g5aaf47cb1987bbc5508c4b9b7dad5ea7d69af2c2 Author: Patrick Palka Date: Fri May 17 09:02:52 2024 -0400 c++: aggregate CTAD w/ paren init and bases [PR115114] During aggregate CTAD with paren init, we're accidentally overlooking base classes since TYPE_FIELDS of a template type doesn't contain corresponding base fields. So we need to consider them separately. PR c++/115114 gcc/cp/ChangeLog: * pt.cc (maybe_aggr_guide): Consider bases in the paren init case. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/class-deduction-aggr15.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/pt.cc | 7 +++ .../g++.dg/cpp2a/class-deduction-aggr15.C | 23 ++ 2 files changed, 30 insertions(+) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 32640f8e946d..e77c48e463e2 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -30200,6 +30200,13 @@ maybe_aggr_guide (tree tmpl, tree init, vec *args) else if (TREE_CODE (init) == TREE_LIST) { int len = list_length (init); + for (tree binfo : BINFO_BASE_BINFOS (TYPE_BINFO (template_type))) + { + if (!len) + break; + parms = tree_cons (NULL_TREE, BINFO_TYPE (binfo), parms); + --len; + } for (tree field = TYPE_FIELDS (template_type); len; --len, field = DECL_CHAIN (field)) diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr15.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr15.C new file mode 100644 index ..16dc0f52b64c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr15.C @@ -0,0 +1,23 @@ +// PR c++/115114 +// { dg-do compile { target c++20 } } + +struct X {} x; +struct Y {} y; + +template +struct A : T { + U m; +}; + +using ty1 = decltype(A{x, 42}); // OK +using ty1 = decltype(A(x, 42)); // OK, used to fail +using ty1 = A; + +template +struct B : T, V { + U m = 42; +}; + +using ty2 = decltype(B{x, y}); // OK +using ty2 = decltype(B(x, y)); // OK, used to fail +using ty2 = B;
[gcc r15-498] c++: lvalueness of non-dependent assignment expr [PR114994]
https://gcc.gnu.org/g:c6cc6d4741a880109c4e0e64d5a189687fb526f6 commit r15-498-gc6cc6d4741a880109c4e0e64d5a189687fb526f6 Author: Patrick Palka Date: Tue May 14 22:55:16 2024 -0400 c++: lvalueness of non-dependent assignment expr [PR114994] r14-4111-g6e92a6a2a72d3b made us check non-dependent simple assignment expressions ahead of time and give them a type, as was already done for compound assignments. Unlike for compound assignments however, if a simple assignment resolves to an operator overload we represent it as a (typed) MODOP_EXPR instead of a CALL_EXPR to the selected overload. (I reckoned this was at worst a pessimization -- we'll just have to repeat overload resolution at instantiatiation time.) But this turns out to break the below testcase ultimately because MODOP_EXPR (of non-reference type) is always treated as an lvalue according to lvalue_kind, which is incorrect for the MODOP_EXPR representing x=42. We can fix this by representing such class assignment expressions as CALL_EXPRs as well, but this turns out to require some tweaking of our -Wparentheses warning logic and may introduce other fallout making it unsuitable for backporting. So this patch instead fixes lvalue_kind to consider the type of a MODOP_EXPR representing a class assignment. PR c++/114994 gcc/cp/ChangeLog: * tree.cc (lvalue_kind) : For a class assignment, consider the result type. gcc/testsuite/ChangeLog: * g++.dg/template/non-dependent32.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/tree.cc | 5 - gcc/testsuite/g++.dg/template/non-dependent32.C | 18 ++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc index f1a23ffe8179..9d37d255d8d5 100644 --- a/gcc/cp/tree.cc +++ b/gcc/cp/tree.cc @@ -275,7 +275,10 @@ lvalue_kind (const_tree ref) /* We expect to see unlowered MODOP_EXPRs only during template processing. */ gcc_assert (processing_template_decl); - return clk_ordinary; + if (CLASS_TYPE_P (TREE_TYPE (TREE_OPERAND (ref, 0 + goto default_; + else + return clk_ordinary; case MODIFY_EXPR: case TYPEID_EXPR: diff --git a/gcc/testsuite/g++.dg/template/non-dependent32.C b/gcc/testsuite/g++.dg/template/non-dependent32.C new file mode 100644 index ..54252c7dfaf9 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/non-dependent32.C @@ -0,0 +1,18 @@ +// PR c++/114994 +// { dg-do compile { target c++11 } } + +struct udl_arg { + udl_arg operator=(int); +}; + +void f(udl_arg&&); + +template +void g() { + udl_arg x; + f(x=42); // { dg-bogus "cannot bind" } +} + +int main() { + g(); +}
[gcc r13-8767] c++: build_extra_args recapturing local specs [PR114303]
https://gcc.gnu.org/g:47cac09307874ff1d640392e3d986453f34f7bcb commit r13-8767-g47cac09307874ff1d640392e3d986453f34f7bcb Author: Patrick Palka Date: Thu Apr 11 10:16:41 2024 -0400 c++: build_extra_args recapturing local specs [PR114303] r13-6452-g341e6cd8d603a3 made build_extra_args walk evaluated contexts first so that we prefer processing a local specialization in an evaluated context even if its first use is in an unevaluated context. But this means we need to avoid walking a tree that already has extra args/specs saved because the list of saved specs appears to be an evaluated context which we'll now walk first. It seems then that we should be calculating the saved specs from scratch each time, rather than potentially walking the saved specs list from an earlier partial instantiation when calling build_extra_args a second time around. PR c++/114303 gcc/cp/ChangeLog: * constraint.cc (tsubst_requires_expr): Clear REQUIRES_EXPR_EXTRA_ARGS before calling build_extra_args. * pt.cc (tree_extra_args): Define. (extract_locals_r): Assert *_EXTRA_ARGS is empty. (tsubst_stmt) : Clear IF_SCOPE on the new IF_STMT. Call build_extra_args on the new IF_STMT instead of t which might already have IF_STMT_EXTRA_ARGS. gcc/testsuite/ChangeLog: * g++.dg/cpp1z/constexpr-if-lambda6.C: New test. Reviewed-by: Jason Merrill (cherry picked from commit b262b17636e47ae969a74f16e86ccb00678d5e88) Diff: --- gcc/cp/constraint.cc | 1 + gcc/cp/pt.cc | 31 ++- gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C | 16 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 83df57dc6fd7..67fe2ae17cd8 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -2370,6 +2370,7 @@ tsubst_requires_expr (tree t, tree args, sat_info info) matching or dguide constraint rewriting), in which case we need to partially substitute. */ t = copy_node (t); + REQUIRES_EXPR_EXTRA_ARGS (t) = NULL_TREE; REQUIRES_EXPR_EXTRA_ARGS (t) = build_extra_args (t, args, info.complain); return t; } diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index fa660fcf49ee..3af705c647a0 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -3861,6 +3861,24 @@ has_extra_args_mechanism_p (const_tree t) && IF_STMT_CONSTEXPR_P (t))); /* IF_STMT_EXTRA_ARGS */ } +/* Return *_EXTRA_ARGS of the given supported tree T. */ + +static tree& +tree_extra_args (tree t) +{ + gcc_checking_assert (has_extra_args_mechanism_p (t)); + + if (PACK_EXPANSION_P (t)) +return PACK_EXPANSION_EXTRA_ARGS (t); + else if (TREE_CODE (t) == REQUIRES_EXPR) +return REQUIRES_EXPR_EXTRA_ARGS (t); + else if (TREE_CODE (t) == IF_STMT + && IF_STMT_CONSTEXPR_P (t)) +return IF_STMT_EXTRA_ARGS (t); + + gcc_unreachable (); +} + /* Structure used to track the progress of find_parameter_packs_r. */ struct find_parameter_pack_data { @@ -13185,6 +13203,16 @@ extract_locals_r (tree *tp, int *walk_subtrees, void *data_) /* Remember local typedefs (85214). */ tp = &TYPE_NAME (*tp); + if (has_extra_args_mechanism_p (*tp)) +/* Assert *_EXTRA_ARGS is empty, because we don't want to walk it and + potentially see a previously captured local in an evaluated context + that's really only used in an unevaluated context (PR114303). This + means callers of build_extra_args need to clear *_EXTRA_ARGS of the + outermost tree. Nested *_EXTRA_ARGS should naturally be empty since + the outermost (extra-args) tree will intercept any substitution before + a nested tree can. */ +gcc_checking_assert (tree_extra_args (*tp) == NULL_TREE); + if (TREE_CODE (*tp) == DECL_EXPR) { tree decl = DECL_EXPR_DECL (*tp); @@ -19189,10 +19217,11 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) of the constexpr if is still dependent. Don't substitute into the branches now, just remember the template arguments. */ do_poplevel (IF_SCOPE (stmt)); + IF_SCOPE (stmt) = NULL_TREE; IF_COND (stmt) = IF_COND (t); THEN_CLAUSE (stmt) = THEN_CLAUSE (t); ELSE_CLAUSE (stmt) = ELSE_CLAUSE (t); - IF_STMT_EXTRA_ARGS (stmt) = build_extra_args (t, args, complain); + IF_STMT_EXTRA_ARGS (stmt) = build_extra_args (stmt, args, complain); add_stmt (stmt); break; } diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C new file mode 100644 index ..038c2a41210f --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C @@ -0,0 +1,16 @@ +// PR c
[gcc r15-438] c++: replace tf_norm with a local flag
https://gcc.gnu.org/g:67476ba8adb432033993f429b1aa4ee5689fa046 commit r15-438-g67476ba8adb432033993f429b1aa4ee5689fa046 Author: Patrick Palka Date: Mon May 13 15:46:55 2024 -0400 c++: replace tf_norm with a local flag The tf_norm flag controlling whether to build diagnostic information during constraint normalization doesn't need to be a global tsubst flag, and is confusingly named. This patch replaces it with a boolean flag local to normalization. gcc/cp/ChangeLog: * constraint.cc (norm_info::norm_info): Take a bool instead of tsubst_flags_t. (norm_info::generate_diagnostics): Turn this predicate function into a bool data member. (normalize_logical_operation): Adjust after norm_info changes. (normalize_concept_check): Likewise. (normalize_atom): Likewise. (get_normalized_constraints_from_info): Likewise. (normalize_concept_definition): Likewise. (normalize_constraint_expression): Likewise. (normalize_placeholder_type_constraints): Likewise. (satisfy_nondeclaration_constraints): Likewise. * cp-tree.h (enum tsubst_flags): Remove tf_norm. Reviewed-by: Jason Merrill Diff: --- gcc/cp/constraint.cc | 40 gcc/cp/cp-tree.h | 3 +-- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 8679d3ce658d..ebf4255e546e 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -622,33 +622,29 @@ parameter_mapping_equivalent_p (tree t1, tree t2) struct norm_info : subst_info { - explicit norm_info (tsubst_flags_t cmp) -: norm_info (NULL_TREE, cmp) + explicit norm_info (bool diag) +: norm_info (NULL_TREE, diag) {} /* Construct a top-level context for DECL. */ - norm_info (tree in_decl, tsubst_flags_t complain) -: subst_info (tf_warning_or_error | complain, in_decl) + norm_info (tree in_decl, bool diag) +: subst_info (tf_warning_or_error, in_decl), + generate_diagnostics (diag) { if (in_decl) { initial_parms = DECL_TEMPLATE_PARMS (in_decl); - if (generate_diagnostics ()) + if (generate_diagnostics) context = build_tree_list (NULL_TREE, in_decl); } else initial_parms = current_template_parms; } - bool generate_diagnostics() const - { -return complain & tf_norm; - } - void update_context(tree expr, tree args) { -if (generate_diagnostics ()) +if (generate_diagnostics) { tree map = build_parameter_mapping (expr, args, ctx_parms ()); context = tree_cons (map, expr, context); @@ -679,6 +675,10 @@ struct norm_info : subst_info template parameters of ORIG_DECL. */ tree initial_parms = NULL_TREE; + + /* Whether to build diagnostic information during normalization. */ + + bool generate_diagnostics; }; static tree normalize_expression (tree, tree, norm_info); @@ -693,7 +693,7 @@ normalize_logical_operation (tree t, tree args, tree_code c, norm_info info) tree t1 = normalize_expression (TREE_OPERAND (t, 1), args, info); /* Build a new info object for the constraint. */ - tree ci = info.generate_diagnostics() + tree ci = info.generate_diagnostics ? build_tree_list (t, info.context) : NULL_TREE; @@ -777,7 +777,7 @@ normalize_concept_check (tree check, tree args, norm_info info) if (!norm_cache) norm_cache = hash_table::create_ggc (31); norm_entry *entry = nullptr; - if (!info.generate_diagnostics ()) + if (!info.generate_diagnostics) { /* Cache the normal form of the substituted concept-id (when not diagnosing). */ @@ -831,7 +831,7 @@ normalize_atom (tree t, tree args, norm_info info) if (info.in_decl && concept_definition_p (info.in_decl)) ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P (atom) = true; - if (!info.generate_diagnostics ()) + if (!info.generate_diagnostics) { /* Cache the ATOMIC_CONSTRs that we return, so that sat_hasher::equal later can cheaply compare two atoms using just pointer equality. */ @@ -910,7 +910,7 @@ get_normalized_constraints_from_info (tree ci, tree in_decl, bool diag = false) /* Substitution errors during normalization are fatal. */ ++processing_template_decl; - norm_info info (in_decl, diag ? tf_norm : tf_none); + norm_info info (in_decl, diag); tree t = get_normalized_constraints (CI_ASSOCIATED_CONSTRAINTS (ci), info); --processing_template_decl; @@ -1012,7 +1012,7 @@ normalize_concept_definition (tree tmpl, bool diag) gcc_assert (TREE_CODE (tmpl) == TEMPLATE_DECL); tree def = get_concept_definition (DECL_TEMPLATE_RESULT (tmpl)); ++processing_template_decl; - norm_info info (tmpl, diag ? tf_norm : tf_none); + norm_info info (tmpl, diag); tree norm = get_normalized_constraints (def, info); --processing_
[gcc r13-8765] c++: constexpr union member access folding [PR114709]
https://gcc.gnu.org/g:d3659e2dfcc6db83391cd2c6d70097cba35eb4b9 commit r13-8765-gd3659e2dfcc6db83391cd2c6d70097cba35eb4b9 Author: Patrick Palka Date: Wed Apr 24 17:49:56 2024 -0400 c++: constexpr union member access folding [PR114709] The object/offset canonicalization performed in cxx_fold_indirect_ref is undesirable for union member accesses because it loses information about the member being accessed which we may later need to diagnose an inactive-member access. So this patch restricts the canonicalization accordingly. PR c++/114709 gcc/cp/ChangeLog: * constexpr.cc (cxx_fold_indirect_ref): Restrict object/offset canonicalization to RECORD_TYPE member accesses. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/constexpr-union8.C: New test. Reviewed-by: Jason Merrill (cherry picked from commit 0844170e9ef60a8b2f6fba6786672f30ce1c2749) Diff: --- gcc/cp/constexpr.cc | 3 +++ gcc/testsuite/g++.dg/cpp0x/constexpr-union8.C | 8 2 files changed, 11 insertions(+) diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index acb5496085bb..12dd9010148e 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -5547,6 +5547,9 @@ cxx_fold_indirect_ref (const constexpr_ctx *ctx, location_t loc, tree type, more folding opportunities. */ auto canonicalize_obj_off = [] (tree& obj, tree& off) { while (TREE_CODE (obj) == COMPONENT_REF + /* We need to preserve union member accesses so that we can + later properly diagnose accessing the wrong member. */ + && TREE_CODE (TREE_TYPE (TREE_OPERAND (obj, 0))) == RECORD_TYPE && (tree_int_cst_sign_bit (off) || integer_zerop (off))) { tree field = TREE_OPERAND (obj, 1); diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-union8.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-union8.C new file mode 100644 index ..34c264944b68 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-union8.C @@ -0,0 +1,8 @@ +// PR c++/114709 +// { dg-do compile { target c++11 } } + +struct T1 { int a, b; }; +struct T2 { int c; double d; }; +union U { T1 t1; T2 t2; }; + +constexpr int v = U{{1,2}}.t2.*&T2::c; // { dg-error "accessing 'U::t2'" }
[gcc r14-10201] c++: nested aggregate/alias CTAD fixes [PR114974, PR114901, PR114903]
https://gcc.gnu.org/g:57cd8665fea4c339369a43be017583621aa82fed commit r14-10201-g57cd8665fea4c339369a43be017583621aa82fed Author: Patrick Palka Date: Mon May 13 09:53:40 2024 -0400 c++: nested aggregate/alias CTAD fixes [PR114974, PR114901, PR114903] During maybe_aggr_guide with a nested class template and paren init, like with list init we need to consider the generic template type rather than the partially instantiated type since partial instantiations don't have (partially instantiated) TYPE_FIELDS. In turn we need to partially substitute PARMs in the paren init case as well. As a drive-by improvement it seems better to use outer_template_args instead of DECL_TI_ARGS during this partial substitution so that we lower instead of substitute the innermost template parameters, which is generally more robust. And during alias_ctad_tweaks with a nested class template, even though the guides may be already partially instantiated we still need to substitute the outermost arguments into its constraints. PR c++/114974 PR c++/114901 PR c++/114903 gcc/cp/ChangeLog: * pt.cc (maybe_aggr_guide): Fix obtaining TYPE_FIELDS in the paren init case. Hoist out partial substitution logic to apply to the paren init case as well. (alias_ctad_tweaks): Substitute outer template arguments into a guide's constraints. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/class-deduction-aggr14.C: New test. * g++.dg/cpp2a/class-deduction-alias20.C: New test. * g++.dg/cpp2a/class-deduction-alias21.C: New test. Reviewed-by: Jason Merrill (cherry picked from commit 6d31a370e26eeb950c326332633b3e8e84b6630b) Diff: --- gcc/cp/pt.cc | 39 -- .../g++.dg/cpp2a/class-deduction-aggr14.C | 11 ++ .../g++.dg/cpp2a/class-deduction-alias20.C | 22 .../g++.dg/cpp2a/class-deduction-alias21.C | 38 + 4 files changed, 93 insertions(+), 17 deletions(-) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 3b2106dd3f65..b5c494e8d15e 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -30201,26 +30201,11 @@ maybe_aggr_guide (tree tmpl, tree init, vec *args) if (init == error_mark_node) return NULL_TREE; parms = collect_ctor_idx_types (init, parms); - /* If we're creating a deduction guide for a member class template, -we've used the original template pattern type for the reshape_init -above; this is done because we want PARMS to be a template parameter -type, something that can be deduced when used as a function template -parameter. At this point the outer class template has already been -partially instantiated (we deferred the deduction until the enclosing -scope is non-dependent). Therefore we have to partially instantiate -PARMS, so that its template level is properly reduced and we don't get -mismatches when deducing types using the guide with PARMS. */ - if (member_template_p) - { - ++processing_template_decl; - parms = tsubst (parms, DECL_TI_ARGS (tmpl), complain, init); - --processing_template_decl; - } } else if (TREE_CODE (init) == TREE_LIST) { int len = list_length (init); - for (tree field = TYPE_FIELDS (type); + for (tree field = TYPE_FIELDS (template_type); len; --len, field = DECL_CHAIN (field)) { @@ -30235,6 +30220,22 @@ maybe_aggr_guide (tree tmpl, tree init, vec *args) /* Aggregate initialization doesn't apply to an initializer expression. */ return NULL_TREE; + /* If we're creating a deduction guide for a member class template, + we've used the original template pattern type for the reshape_init + above; this is done because we want PARMS to be a template parameter + type, something that can be deduced when used as a function template + parameter. At this point the outer class template has already been + partially instantiated (we deferred the deduction until the enclosing + scope is non-dependent). Therefore we have to partially instantiate + PARMS, so that its template level is properly reduced and we don't get + mismatches when deducing types using the guide with PARMS. */ + if (member_template_p) +{ + ++processing_template_decl; + parms = tsubst (parms, outer_template_args (tmpl), complain, init); + --processing_template_decl; +} + if (parms) { tree last = parms; @@ -30426,7 +30427,11 @@ alias_ctad_tweaks (tree tmpl, tree uguides) /* Substitute the associated constraints. */ tree ci = get_constraints (f); if (ci) - ci = tsubst_constraint_info (ci, targs, complain, in_decl); +
[gcc r15-434] c++: nested aggregate/alias CTAD fixes [PR114974, PR114901, PR114903]
https://gcc.gnu.org/g:6d31a370e26eeb950c326332633b3e8e84b6630b commit r15-434-g6d31a370e26eeb950c326332633b3e8e84b6630b Author: Patrick Palka Date: Mon May 13 09:53:40 2024 -0400 c++: nested aggregate/alias CTAD fixes [PR114974, PR114901, PR114903] During maybe_aggr_guide with a nested class template and paren init, like with list init we need to consider the generic template type rather than the partially instantiated type since partial instantiations don't have (partially instantiated) TYPE_FIELDS. In turn we need to partially substitute PARMs in the paren init case as well. As a drive-by improvement it seems better to use outer_template_args instead of DECL_TI_ARGS during this partial substitution so that we lower instead of substitute the innermost template parameters, which is generally more robust. And during alias_ctad_tweaks with a nested class template, even though the guides may be already partially instantiated we still need to substitute the outermost arguments into its constraints. PR c++/114974 PR c++/114901 PR c++/114903 gcc/cp/ChangeLog: * pt.cc (maybe_aggr_guide): Fix obtaining TYPE_FIELDS in the paren init case. Hoist out partial substitution logic to apply to the paren init case as well. (alias_ctad_tweaks): Substitute outer template arguments into a guide's constraints. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/class-deduction-aggr14.C: New test. * g++.dg/cpp2a/class-deduction-alias20.C: New test. * g++.dg/cpp2a/class-deduction-alias21.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/pt.cc | 39 -- .../g++.dg/cpp2a/class-deduction-aggr14.C | 11 ++ .../g++.dg/cpp2a/class-deduction-alias20.C | 22 .../g++.dg/cpp2a/class-deduction-alias21.C | 38 + 4 files changed, 93 insertions(+), 17 deletions(-) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index a7d9fcf930e2..4b71e199d27f 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -30194,26 +30194,11 @@ maybe_aggr_guide (tree tmpl, tree init, vec *args) if (init == error_mark_node) return NULL_TREE; parms = collect_ctor_idx_types (init, parms); - /* If we're creating a deduction guide for a member class template, -we've used the original template pattern type for the reshape_init -above; this is done because we want PARMS to be a template parameter -type, something that can be deduced when used as a function template -parameter. At this point the outer class template has already been -partially instantiated (we deferred the deduction until the enclosing -scope is non-dependent). Therefore we have to partially instantiate -PARMS, so that its template level is properly reduced and we don't get -mismatches when deducing types using the guide with PARMS. */ - if (member_template_p) - { - ++processing_template_decl; - parms = tsubst (parms, DECL_TI_ARGS (tmpl), complain, init); - --processing_template_decl; - } } else if (TREE_CODE (init) == TREE_LIST) { int len = list_length (init); - for (tree field = TYPE_FIELDS (type); + for (tree field = TYPE_FIELDS (template_type); len; --len, field = DECL_CHAIN (field)) { @@ -30228,6 +30213,22 @@ maybe_aggr_guide (tree tmpl, tree init, vec *args) /* Aggregate initialization doesn't apply to an initializer expression. */ return NULL_TREE; + /* If we're creating a deduction guide for a member class template, + we've used the original template pattern type for the reshape_init + above; this is done because we want PARMS to be a template parameter + type, something that can be deduced when used as a function template + parameter. At this point the outer class template has already been + partially instantiated (we deferred the deduction until the enclosing + scope is non-dependent). Therefore we have to partially instantiate + PARMS, so that its template level is properly reduced and we don't get + mismatches when deducing types using the guide with PARMS. */ + if (member_template_p) +{ + ++processing_template_decl; + parms = tsubst (parms, outer_template_args (tmpl), complain, init); + --processing_template_decl; +} + if (parms) { tree last = parms; @@ -30419,7 +30420,11 @@ alias_ctad_tweaks (tree tmpl, tree uguides) /* Substitute the associated constraints. */ tree ci = get_constraints (f); if (ci) - ci = tsubst_constraint_info (ci, targs, complain, in_decl); + { + if (tree outer_targs = outer_template_args (f)) +
[gcc r14-10176] c++/modules: imported spec befriending class tmpl [PR114889]
https://gcc.gnu.org/g:390bd23fd9c98dc40856beef05364f5d1c7b9d04 commit r14-10176-g390bd23fd9c98dc40856beef05364f5d1c7b9d04 Author: Patrick Palka Date: Mon Apr 29 21:27:59 2024 -0400 c++/modules: imported spec befriending class tmpl [PR114889] When adding to CLASSTYPE_BEFRIENDING_CLASSES as part of installing an imported class definition, we need to look through TEMPLATE_DECL like make_friend_class does. Otherwise in the below testcase we won't add _Hashtable to CLASSTYPE_BEFRIENDING_CLASSES of _Map_base, which leads to a bogus access check failure for _M_hash_code. PR c++/114889 gcc/cp/ChangeLog: * module.cc (trees_in::read_class_def): Look through TEMPLATE_DECL when adding to CLASSTYPE_BEFRIENDING_CLASSES. gcc/testsuite/ChangeLog: * g++.dg/modules/friend-8_a.H: New test. * g++.dg/modules/friend-8_b.C: New test. Reviewed-by: Jason Merrill (cherry picked from commit 22b20ac6c6aead2d3f36c413a77dd0b80adfec39) Diff: --- gcc/cp/module.cc | 2 ++ gcc/testsuite/g++.dg/modules/friend-8_a.H | 23 +++ gcc/testsuite/g++.dg/modules/friend-8_b.C | 9 + 3 files changed, 34 insertions(+) diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index c35e70b8cb8..3bf863e15d4 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -12498,6 +12498,8 @@ trees_in::read_class_def (tree defn, tree maybe_template) for (; friend_classes; friend_classes = TREE_CHAIN (friend_classes)) { tree f = TREE_VALUE (friend_classes); + if (TREE_CODE (f) == TEMPLATE_DECL) + f = TREE_TYPE (f); if (CLASS_TYPE_P (f)) { diff --git a/gcc/testsuite/g++.dg/modules/friend-8_a.H b/gcc/testsuite/g++.dg/modules/friend-8_a.H new file mode 100644 index 000..b07ea25adfb --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/friend-8_a.H @@ -0,0 +1,23 @@ +// PR c++/114889 +// { dg-additional-options "-fmodule-header" } +// { dg-module-cmi {} } + +template +struct _Hashtable; + +template +struct _Map_base { + void f() { +_Hashtable<_Key, _Val> __h; +__h._M_hash_code(0); + } +}; + +template +struct _Hashtable { + template friend struct _Map_base; +protected: + void _M_hash_code(int); +}; + +inline _Hashtable m; diff --git a/gcc/testsuite/g++.dg/modules/friend-8_b.C b/gcc/testsuite/g++.dg/modules/friend-8_b.C new file mode 100644 index 000..b04280bc91a --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/friend-8_b.C @@ -0,0 +1,9 @@ +// PR c++/114889 +// { dg-additional-options "-fmodules-ts" } + +import "friend-8_a.H"; + +int main() { + _Map_base m; + m.f(); +}
[gcc r15-123] c++: remove lookup_template_class's entering_scope flag
https://gcc.gnu.org/g:f04dc89a991ddc6c08ac92c8ad29c6915c4ecafa commit r15-123-gf04dc89a991ddc6c08ac92c8ad29c6915c4ecafa Author: Patrick Palka Date: Thu May 2 21:14:30 2024 -0400 c++: remove lookup_template_class's entering_scope flag lookup_template_class's entering_scope flag controls whether to prefer returning the primary template type A instead of the corresponding implicit instantiation A. When we want to set this flag as part of substitution, we need to use tsubst_aggr_type which also takes this flag as a parameter. But having this separate entry point to type substitution turned out to be subtly problematic because it doesn't reuse typedefs like tsubst does, which r13-4729-gbe124477b38a71 fixed in a way that respects the flag after the fact, by adjusting the entering_scope=false result of lookup_template_class as if entering_scope=true was passed. But if that's possible then it means lookup_template_class's entering_scope flag is not necessary after all -- we can just do the after-the-fact adjustment everywhere that we currently pass entering_scope=true to it and tsubst_aggr_type. To that end, this patch replaces this flag with an adjustment function adjust_type_for_entering_scope, to be used whereever we currently need the entering_scope=true behavior. In turn we can get rid of tsubst_aggr_type since the only reason we needed this entry point was to be able to pass entering_scope=true to lookup_template_class. gcc/cp/ChangeLog: * coroutines.cc (instantiate_coro_traits): Adjust call to lookup_template_class. (instantiate_coro_handle_for_promise_type): Likewise. * cp-tree.h (adjust_type_for_entering_scope): Declare. (lookup_template_class): Adjust declaration. * decl.cc (make_typename_type): Adjust call to lookup_template_class. Likewise. (get_tuple_size): Likewise. (get_tuple_element_type): Likewise. * pt.cc (adjust_type_for_entering_scope): Define. (tsubst_entering_scope): Define. (lookup_template_class): Remove entering_scope parameter. Replace tsubst_aggr_type call with tsubst_entering_scope. (tsubst_aggr_type): Remove. (tsubst_aggr_type_1): Inline into tsubst. (tsubst_function_decl): Replace tsubst_aggr_type call with tsubst_entering_scope. (tsubst_template_decl): Likewise. (tsubst_decl): Likewise. (tsubst) : Inlined from tsubst_aggr_type_1. : Adjust calls to lookup_template_class. : Replace tsubst_aggr_type call with tsubst_entering_scope. : Likewise. Increment processing_template_decl when substituting the context. (tsubst_expr) : Replace tsubst_aggr_type call with tsubst_entering_scope. : Likewise. (instantiate_template): Likewise. (resolve_typename_type): Adjust lookup_template_class call and call adjust_type_for_entering_scope afterward. (listify): Adjust lookup_template_class call. (alias_ctad_tweaks): Likewise. * semantics.cc (finish_template_type): Adjust lookup_template_class call and maybe call adjust_type_for_entering_scope afterward. Reviewed-by: Jason Merrill Diff: --- gcc/cp/coroutines.cc | 4 +- gcc/cp/cp-tree.h | 3 +- gcc/cp/decl.cc | 4 +- gcc/cp/pt.cc | 207 --- gcc/cp/semantics.cc | 4 +- 5 files changed, 88 insertions(+), 134 deletions(-) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index b05cb9eb330..97bc211ff67 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -353,7 +353,7 @@ instantiate_coro_traits (tree fndecl, location_t kw) tree traits_class = lookup_template_class (coro_traits_templ, targ, /*in_decl=*/NULL_TREE, /*context=*/NULL_TREE, -/*entering scope=*/false, tf_warning_or_error); +tf_warning_or_error); if (traits_class == error_mark_node) { @@ -400,7 +400,7 @@ instantiate_coro_handle_for_promise_type (location_t kw, tree promise_type) = lookup_template_class (coro_handle_identifier, targ, /* in_decl=*/NULL_TREE, /* context=*/std_node, -/* entering scope=*/false, tf_warning_or_error); +tf_warning_or_error); if (handle_type == error_mark_node) { diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 933504b4821..1ba7054f8bc 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7524,8 +7524,9 @@ extern tree push_template_decl(tree, bool is_frien
[gcc r13-8670] c++: problematic assert in reference_binding [PR113141]
https://gcc.gnu.org/g:c70abea054fe0021b7b2c2e07996afaadc17a07b commit r13-8670-gc70abea054fe0021b7b2c2e07996afaadc17a07b Author: Patrick Palka Date: Wed May 1 18:16:08 2024 -0400 c++: problematic assert in reference_binding [PR113141] r14-9946 / r14-9947 fixed this PR properly for GCC 14. For GCC 13, let's just remove the problematic assert. PR c++/113141 gcc/cp/ChangeLog: * call.cc (reference_binding): Remove badness criteria sanity check in the recursive case. gcc/testsuite/ChangeLog: * g++.dg/conversion/ref12.C: New test. * g++.dg/cpp0x/initlist-ref1.C: new test. Diff: --- gcc/cp/call.cc | 1 - gcc/testsuite/g++.dg/conversion/ref12.C| 13 + gcc/testsuite/g++.dg/cpp0x/initlist-ref1.C | 16 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index b10bdc62d38..70c7f6178b8 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -2017,7 +2017,6 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags, if (!new_second) return NULL; conv = merge_conversion_sequences (t, new_second); - gcc_assert (maybe_valid_p || conv->bad_p); return conv; } } diff --git a/gcc/testsuite/g++.dg/conversion/ref12.C b/gcc/testsuite/g++.dg/conversion/ref12.C new file mode 100644 index 000..633b7e48e47 --- /dev/null +++ b/gcc/testsuite/g++.dg/conversion/ref12.C @@ -0,0 +1,13 @@ +// PR c++/113141 + +struct Matrix { }; + +struct TPoint3 { operator const Matrix(); }; + +void f(Matrix&); + +int main() { + TPoint3 X; + Matrix& m = (Matrix &)X; + f((Matrix &)X); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-ref1.C b/gcc/testsuite/g++.dg/cpp0x/initlist-ref1.C new file mode 100644 index 000..f893f12dafa --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/initlist-ref1.C @@ -0,0 +1,16 @@ +// PR c++/113141 +// { dg-do compile { target c++11 } } + +struct ConvToRef { + operator int&(); +}; + +struct A { int& r; }; + +void f(A); + +int main() { + ConvToRef c; + A a{{c}}; + f({{c}}); +}
[gcc r15-57] c++/modules: imported spec befriending class tmpl [PR114889]
https://gcc.gnu.org/g:22b20ac6c6aead2d3f36c413a77dd0b80adfec39 commit r15-57-g22b20ac6c6aead2d3f36c413a77dd0b80adfec39 Author: Patrick Palka Date: Mon Apr 29 21:27:59 2024 -0400 c++/modules: imported spec befriending class tmpl [PR114889] When adding to CLASSTYPE_BEFRIENDING_CLASSES as part of installing an imported class definition, we need to look through TEMPLATE_DECL like make_friend_class does. Otherwise in the below testcase we won't add _Hashtable to CLASSTYPE_BEFRIENDING_CLASSES of _Map_base, which leads to a bogus access check failure for _M_hash_code. PR c++/114889 gcc/cp/ChangeLog: * module.cc (trees_in::read_class_def): Look through TEMPLATE_DECL when adding to CLASSTYPE_BEFRIENDING_CLASSES. gcc/testsuite/ChangeLog: * g++.dg/modules/friend-8_a.H: New test. * g++.dg/modules/friend-8_b.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/module.cc | 2 ++ gcc/testsuite/g++.dg/modules/friend-8_a.H | 23 +++ gcc/testsuite/g++.dg/modules/friend-8_b.C | 9 + 3 files changed, 34 insertions(+) diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index c35e70b8cb8..3bf863e15d4 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -12498,6 +12498,8 @@ trees_in::read_class_def (tree defn, tree maybe_template) for (; friend_classes; friend_classes = TREE_CHAIN (friend_classes)) { tree f = TREE_VALUE (friend_classes); + if (TREE_CODE (f) == TEMPLATE_DECL) + f = TREE_TYPE (f); if (CLASS_TYPE_P (f)) { diff --git a/gcc/testsuite/g++.dg/modules/friend-8_a.H b/gcc/testsuite/g++.dg/modules/friend-8_a.H new file mode 100644 index 000..b07ea25adfb --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/friend-8_a.H @@ -0,0 +1,23 @@ +// PR c++/114889 +// { dg-additional-options "-fmodule-header" } +// { dg-module-cmi {} } + +template +struct _Hashtable; + +template +struct _Map_base { + void f() { +_Hashtable<_Key, _Val> __h; +__h._M_hash_code(0); + } +}; + +template +struct _Hashtable { + template friend struct _Map_base; +protected: + void _M_hash_code(int); +}; + +inline _Hashtable m; diff --git a/gcc/testsuite/g++.dg/modules/friend-8_b.C b/gcc/testsuite/g++.dg/modules/friend-8_b.C new file mode 100644 index 000..b04280bc91a --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/friend-8_b.C @@ -0,0 +1,9 @@ +// PR c++/114889 +// { dg-additional-options "-fmodules-ts" } + +import "friend-8_a.H"; + +int main() { + _Map_base m; + m.f(); +}
[gcc r14-10149] c++: ICE with templated sizeof(E1) / sizeof(E2) [PR114888]
https://gcc.gnu.org/g:3c925ac349b03ae9439c632fb1c042cdc8d78f40 commit r14-10149-g3c925ac349b03ae9439c632fb1c042cdc8d78f40 Author: Patrick Palka Date: Mon Apr 29 21:14:18 2024 -0400 c++: ICE with templated sizeof(E1) / sizeof(E2) [PR114888] In the sizeof / sizeof operator expression handling we're missing a dependence check for the second operand. PR c++/114888 gcc/cp/ChangeLog: * typeck.cc (cp_build_binary_op) : Add missing dependence check for the second sizeof operand. gcc/testsuite/ChangeLog: * g++.dg/template/sizeof19.C: New test. Reviewed-by: Jason Merrill (cherry picked from commit 3900e944b0ac9db77380c5bb8635977dfd3b0691) Diff: --- gcc/cp/typeck.cc | 1 + gcc/testsuite/g++.dg/template/sizeof19.C | 8 2 files changed, 9 insertions(+) diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc index e5a52dc2b39..a25f8622651 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -5501,6 +5501,7 @@ cp_build_binary_op (const op_location_t &location, if (!TYPE_P (type1)) type1 = TREE_TYPE (type1); if (type0 + && type1 && INDIRECT_TYPE_P (type0) && same_type_p (TREE_TYPE (type0), type1)) { diff --git a/gcc/testsuite/g++.dg/template/sizeof19.C b/gcc/testsuite/g++.dg/template/sizeof19.C new file mode 100644 index 000..a1467995a9b --- /dev/null +++ b/gcc/testsuite/g++.dg/template/sizeof19.C @@ -0,0 +1,8 @@ +// PR c++/114888 + +template +struct A { + struct B {} *b; + static const int c = sizeof (b) / sizeof (b[0]); +}; +const int d = A::c;
[gcc r15-56] c++: ICE with templated sizeof(E1) / sizeof(E2) [PR114888]
https://gcc.gnu.org/g:3900e944b0ac9db77380c5bb8635977dfd3b0691 commit r15-56-g3900e944b0ac9db77380c5bb8635977dfd3b0691 Author: Patrick Palka Date: Mon Apr 29 21:14:18 2024 -0400 c++: ICE with templated sizeof(E1) / sizeof(E2) [PR114888] In the sizeof / sizeof operator expression handling we're missing a dependence check for the second operand. PR c++/114888 gcc/cp/ChangeLog: * typeck.cc (cp_build_binary_op) : Add missing dependence check for the second sizeof operand. gcc/testsuite/ChangeLog: * g++.dg/template/sizeof19.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/typeck.cc | 1 + gcc/testsuite/g++.dg/template/sizeof19.C | 8 2 files changed, 9 insertions(+) diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc index e5a52dc2b39..a25f8622651 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -5501,6 +5501,7 @@ cp_build_binary_op (const op_location_t &location, if (!TYPE_P (type1)) type1 = TREE_TYPE (type1); if (type0 + && type1 && INDIRECT_TYPE_P (type0) && same_type_p (TREE_TYPE (type0), type1)) { diff --git a/gcc/testsuite/g++.dg/template/sizeof19.C b/gcc/testsuite/g++.dg/template/sizeof19.C new file mode 100644 index 000..a1467995a9b --- /dev/null +++ b/gcc/testsuite/g++.dg/template/sizeof19.C @@ -0,0 +1,8 @@ +// PR c++/114888 + +template +struct A { + struct B {} *b; + static const int c = sizeof (b) / sizeof (b[0]); +}; +const int d = A::c;
[gcc r14-10140] c++: fix source printing for "required from here" message
https://gcc.gnu.org/g:c014cfd8853240827feb3a4cef92403e83cd4265 commit r14-10140-gc014cfd8853240827feb3a4cef92403e83cd4265 Author: Patrick Palka Date: Fri Apr 26 07:44:25 2024 -0400 c++: fix source printing for "required from here" message It seems the diagnostic machinery's source line printing respects the pretty printer prefix, but this is undesirable for the call to diagnostic_show_locus in print_instantiation_partial_context_line (added in r14-4388-g1c45319b66edc9) since the prefix may have been set when issuing an earlier, unrelated diagnostic and we just want to print an unprefixed source line. This patch naively fixes this by clearing the prefix before calling diagnostic_show_locus. Before this patch, for error60a.C below we'd print gcc/testsuite/g++.dg/template/error60a.C: In function ‘void usage()’: gcc/testsuite/g++.dg/template/error60a.C:24:3: error: ‘unrelated_error’ was not declared in this scope 24 | unrelated_error; // { dg-error "not declared" } | ^~~ gcc/testsuite/g++.dg/template/error60a.C: In instantiation of ‘void test(Foo) [with Foo = int]’: gcc/testsuite/g++.dg/template/error60a.C:25:13: required from here gcc/testsuite/g++.dg/template/error60a.C:24:3: error:25 | test (42); // { dg-message " required from here" } gcc/testsuite/g++.dg/template/error60a.C:24:3: error: | ~~^~~~ gcc/testsuite/g++.dg/template/error60a.C:19:24: error: invalid conversion from ‘int’ to ‘int*’ [-fpermissive] 19 | my_pointer ptr (val); // { dg-error "invalid conversion from 'int' to 'int\\*'" } |^~~ || |int gcc/testsuite/g++.dg/template/error60a.C:9:20: note: initializing argument 1 of ‘my_pointer::my_pointer(Foo*) [with Foo = int]’ 9 | my_pointer (Foo *ptr) // { dg-message " initializing argument 1" } | ~^~~ and afterward we print gcc/testsuite/g++.dg/template/error60a.C: In function ‘void usage()’: gcc/testsuite/g++.dg/template/error60a.C:24:3: error: ‘unrelated_error’ was not declared in this scope 24 | unrelated_error; // { dg-error "not declared" } | ^~~ gcc/testsuite/g++.dg/template/error60a.C: In instantiation of ‘void test(Foo) [with Foo = int]’: gcc/testsuite/g++.dg/template/error60a.C:25:13: required from here 25 | test (42); // { dg-message " required from here" } | ~~^~~~ gcc/testsuite/g++.dg/template/error60a.C:19:24: error: invalid conversion from ‘int’ to ‘int*’ [-fpermissive] 19 | my_pointer ptr (val); // { dg-error "invalid conversion from 'int' to 'int\\*'" } |^~~ || |int gcc/testsuite/g++.dg/template/error60a.C:9:20: note: initializing argument 1 of ‘my_pointer::my_pointer(Foo*) [with Foo = int]’ 9 | my_pointer (Foo *ptr) // { dg-message " initializing argument 1" } | ~^~~ gcc/cp/ChangeLog: * error.cc (print_instantiation_partial_context_line): Clear the pretty printer prefix around the call to diagnostic_show_locus. gcc/testsuite/ChangeLog: * g++.dg/concepts/diagnostic2.C: Expect source line printed for the "required from here" message. * g++.dg/template/error60a.C: New test. (cherry picked from commit 7d5479a2ecf6309281de10b747a7423169a2ff95) Diff: --- gcc/cp/error.cc | 2 ++ gcc/testsuite/g++.dg/concepts/diagnostic2.C | 6 +++- gcc/testsuite/g++.dg/template/error60a.C| 46 + 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc index 7074845154e..37987ccb570 100644 --- a/gcc/cp/error.cc +++ b/gcc/cp/error.cc @@ -3793,7 +3793,9 @@ print_instantiation_partial_context_line (diagnostic_context *context, : _("required from here\n")); } gcc_rich_location rich_loc (loc); + char *saved_prefix = pp_take_prefix (context->printer); diagnostic_show_locus (context, &rich_loc, DK_NOTE); + pp_set_prefix (context->printer, saved_prefix); } /* Same as print_instantiation_full_context but less verbose. */ diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic2.C b/gcc/testsuite/g++.dg/concepts/diagnostic2.C index 6550ed6b3bd..d6f5872de2c 100644 --- a/gcc/testsuite/g++.dg/concepts/diagnostic2.C +++ b/gcc/testsuite/g++.dg/concepts/diagnostic2.C @@ -23,7 +23,11 @@ void baz() { bar(); // { dg-error "no match" } -/* { dg-begin-multiline-output "" } +/* { dg-begin-multiline-output "for no match error" } + bar(); + ^~ + { dg-end-multiline-output "" } */ +/* { dg-begin-multiline-output "for required
[gcc r15-4] c++: fix source printing for "required from here" message
https://gcc.gnu.org/g:7d5479a2ecf6309281de10b747a7423169a2ff95 commit r15-4-g7d5479a2ecf6309281de10b747a7423169a2ff95 Author: Patrick Palka Date: Fri Apr 26 07:44:25 2024 -0400 c++: fix source printing for "required from here" message It seems the diagnostic machinery's source line printing respects the pretty printer prefix, but this is undesirable for the call to diagnostic_show_locus in print_instantiation_partial_context_line (added in r14-4388-g1c45319b66edc9) since the prefix may have been set when issuing an earlier, unrelated diagnostic and we just want to print an unprefixed source line. This patch naively fixes this by clearing the prefix before calling diagnostic_show_locus. Before this patch, for error60a.C below we'd print gcc/testsuite/g++.dg/template/error60a.C: In function ‘void usage()’: gcc/testsuite/g++.dg/template/error60a.C:24:3: error: ‘unrelated_error’ was not declared in this scope 24 | unrelated_error; // { dg-error "not declared" } | ^~~ gcc/testsuite/g++.dg/template/error60a.C: In instantiation of ‘void test(Foo) [with Foo = int]’: gcc/testsuite/g++.dg/template/error60a.C:25:13: required from here gcc/testsuite/g++.dg/template/error60a.C:24:3: error:25 | test (42); // { dg-message " required from here" } gcc/testsuite/g++.dg/template/error60a.C:24:3: error: | ~~^~~~ gcc/testsuite/g++.dg/template/error60a.C:19:24: error: invalid conversion from ‘int’ to ‘int*’ [-fpermissive] 19 | my_pointer ptr (val); // { dg-error "invalid conversion from 'int' to 'int\\*'" } |^~~ || |int gcc/testsuite/g++.dg/template/error60a.C:9:20: note: initializing argument 1 of ‘my_pointer::my_pointer(Foo*) [with Foo = int]’ 9 | my_pointer (Foo *ptr) // { dg-message " initializing argument 1" } | ~^~~ and afterward we print gcc/testsuite/g++.dg/template/error60a.C: In function ‘void usage()’: gcc/testsuite/g++.dg/template/error60a.C:24:3: error: ‘unrelated_error’ was not declared in this scope 24 | unrelated_error; // { dg-error "not declared" } | ^~~ gcc/testsuite/g++.dg/template/error60a.C: In instantiation of ‘void test(Foo) [with Foo = int]’: gcc/testsuite/g++.dg/template/error60a.C:25:13: required from here 25 | test (42); // { dg-message " required from here" } | ~~^~~~ gcc/testsuite/g++.dg/template/error60a.C:19:24: error: invalid conversion from ‘int’ to ‘int*’ [-fpermissive] 19 | my_pointer ptr (val); // { dg-error "invalid conversion from 'int' to 'int\\*'" } |^~~ || |int gcc/testsuite/g++.dg/template/error60a.C:9:20: note: initializing argument 1 of ‘my_pointer::my_pointer(Foo*) [with Foo = int]’ 9 | my_pointer (Foo *ptr) // { dg-message " initializing argument 1" } | ~^~~ gcc/cp/ChangeLog: * error.cc (print_instantiation_partial_context_line): Clear the pretty printer prefix around the call to diagnostic_show_locus. gcc/testsuite/ChangeLog: * g++.dg/concepts/diagnostic2.C: Expect source line printed for the "required from here" message. * g++.dg/template/error60a.C: New test. Diff: --- gcc/cp/error.cc | 2 ++ gcc/testsuite/g++.dg/concepts/diagnostic2.C | 6 +++- gcc/testsuite/g++.dg/template/error60a.C| 46 + 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc index 7074845154e..37987ccb570 100644 --- a/gcc/cp/error.cc +++ b/gcc/cp/error.cc @@ -3793,7 +3793,9 @@ print_instantiation_partial_context_line (diagnostic_context *context, : _("required from here\n")); } gcc_rich_location rich_loc (loc); + char *saved_prefix = pp_take_prefix (context->printer); diagnostic_show_locus (context, &rich_loc, DK_NOTE); + pp_set_prefix (context->printer, saved_prefix); } /* Same as print_instantiation_full_context but less verbose. */ diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic2.C b/gcc/testsuite/g++.dg/concepts/diagnostic2.C index 6550ed6b3bd..d6f5872de2c 100644 --- a/gcc/testsuite/g++.dg/concepts/diagnostic2.C +++ b/gcc/testsuite/g++.dg/concepts/diagnostic2.C @@ -23,7 +23,11 @@ void baz() { bar(); // { dg-error "no match" } -/* { dg-begin-multiline-output "" } +/* { dg-begin-multiline-output "for no match error" } + bar(); + ^~ + { dg-end-multiline-output "" } */ +/* { dg-begin-multiline-output "for required from here message" } bar(); ^~ { dg-end-multiline-output "" }
[gcc r14-10111] c++/modules testsuite: restrict expensive pr99023 test
https://gcc.gnu.org/g:26a3edbe2357cf975f345ad1b59b9f9a3444316e commit r14-10111-g26a3edbe2357cf975f345ad1b59b9f9a3444316e Author: Patrick Palka Date: Wed Apr 24 17:51:54 2024 -0400 c++/modules testsuite: restrict expensive pr99023 test The pr99023 testcase uses --param=ggc-min-expand=0 which forces a GC during every collection point and consequently is very slow to run, and ends up being the main bottleneck of the modules.exp testsuite. So this patch restricts this test to run once, in C++20 mode, instead of multiple times (C++17, C++20 and C++23 mode by default). After this patch the modules.exp testsuite finishes in 3m instead of 3m40s with -j8 on my machine. gcc/testsuite/ChangeLog: * g++.dg/modules/pr99023_a.X: Run only in C++20 mode. * g++.dg/modules/pr99023_b.X: Likewise. Reviewed-by: Jason Merrill Diff: --- gcc/testsuite/g++.dg/modules/pr99023_a.X | 1 + gcc/testsuite/g++.dg/modules/pr99023_b.X | 1 + 2 files changed, 2 insertions(+) diff --git a/gcc/testsuite/g++.dg/modules/pr99023_a.X b/gcc/testsuite/g++.dg/modules/pr99023_a.X index c872d15f792..507e9569535 100644 --- a/gcc/testsuite/g++.dg/modules/pr99023_a.X +++ b/gcc/testsuite/g++.dg/modules/pr99023_a.X @@ -1,4 +1,5 @@ // PR c++/99023, ICE +// { dg-require-effective-target c++20_only } // { dg-additional-options {-x c++-system-header initializer_list -fmodules-ts --param ggc-min-expand=0} } // { dg-prune-output {linker input file unused} } diff --git a/gcc/testsuite/g++.dg/modules/pr99023_b.X b/gcc/testsuite/g++.dg/modules/pr99023_b.X index ca5f32e5bcc..59d32bee8d5 100644 --- a/gcc/testsuite/g++.dg/modules/pr99023_b.X +++ b/gcc/testsuite/g++.dg/modules/pr99023_b.X @@ -1,4 +1,5 @@ // PR c++/99023, ICE +// { dg-require-effective-target c++20_only } // { dg-additional-options {-x c++-system-header iostream -fmodules-ts -flang-info-include-translate= --param ggc-min-expand=0} } // { dg-prune-output {linker input file unused} }
[gcc r14-10110] c++: constexpr union member access folding [PR114709]
https://gcc.gnu.org/g:0844170e9ef60a8b2f6fba6786672f30ce1c2749 commit r14-10110-g0844170e9ef60a8b2f6fba6786672f30ce1c2749 Author: Patrick Palka Date: Wed Apr 24 17:49:56 2024 -0400 c++: constexpr union member access folding [PR114709] The object/offset canonicalization performed in cxx_fold_indirect_ref is undesirable for union member accesses because it loses information about the member being accessed which we may later need to diagnose an inactive-member access. So this patch restricts the canonicalization accordingly. PR c++/114709 gcc/cp/ChangeLog: * constexpr.cc (cxx_fold_indirect_ref): Restrict object/offset canonicalization to RECORD_TYPE member accesses. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/constexpr-union8.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/constexpr.cc | 3 +++ gcc/testsuite/g++.dg/cpp0x/constexpr-union8.C | 8 2 files changed, 11 insertions(+) diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index 302b266809f..2e83d24dfda 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -5799,6 +5799,9 @@ cxx_fold_indirect_ref (const constexpr_ctx *ctx, location_t loc, tree type, more folding opportunities. */ auto canonicalize_obj_off = [] (tree& obj, tree& off) { while (TREE_CODE (obj) == COMPONENT_REF + /* We need to preserve union member accesses so that we can + later properly diagnose accessing the wrong member. */ + && TREE_CODE (TREE_TYPE (TREE_OPERAND (obj, 0))) == RECORD_TYPE && (tree_int_cst_sign_bit (off) || integer_zerop (off))) { tree field = TREE_OPERAND (obj, 1); diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-union8.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-union8.C new file mode 100644 index 000..34c264944b6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-union8.C @@ -0,0 +1,8 @@ +// PR c++/114709 +// { dg-do compile { target c++11 } } + +struct T1 { int a, b; }; +struct T2 { int c; double d; }; +union U { T1 t1; T2 t2; }; + +constexpr int v = U{{1,2}}.t2.*&T2::c; // { dg-error "accessing 'U::t2'" }
[gcc r14-10096] c++/modules: deduced return type merging [PR114795]
https://gcc.gnu.org/g:4f9401d1a802325e5dfa2db841945e1a9c59a980 commit r14-10096-g4f9401d1a802325e5dfa2db841945e1a9c59a980 Author: Patrick Palka Date: Tue Apr 23 14:01:22 2024 -0400 c++/modules: deduced return type merging [PR114795] When merging an imported function template specialization with an existing one, if the existing one has an undeduced return type and the imported one's is already deduced, we need to propagate the deduced type since once we install the imported definition we won't get a chance to deduce it by normal means. So this patch makes is_matching_decl propagate the deduced return type alongside our propagation of the exception specification. Another option would be to propagate it later when installing the imported definition from read_function_def, but it seems preferable to do it sooner rather than later. PR c++/114795 gcc/cp/ChangeLog: * module.cc (trees_in::is_matching_decl): Propagate deduced function return type. gcc/testsuite/ChangeLog: * g++.dg/modules/auto-4_a.H: New test. * g++.dg/modules/auto-4_b.C: New test. Reviewed-by: Jason Merrill Diff: --- gcc/cp/module.cc| 9 + gcc/testsuite/g++.dg/modules/auto-4_a.H | 14 ++ gcc/testsuite/g++.dg/modules/auto-4_b.C | 15 +++ 3 files changed, 38 insertions(+) diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index d94d8ff4df9..c35e70b8cb8 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -11537,6 +11537,15 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef) else if (!DEFERRED_NOEXCEPT_SPEC_P (d_spec) && !comp_except_specs (d_spec, e_spec, ce_type)) goto mismatch; + + /* Similarly if EXISTING has an undeduced return type, but DECL's +is already deduced. */ + if (undeduced_auto_decl (existing) && !undeduced_auto_decl (decl)) + { + dump (dumper::MERGE) + && dump ("Propagating deduced return type to %N", existing); + TREE_TYPE (existing) = change_return_type (TREE_TYPE (d_type), e_type); + } } else if (is_typedef) { diff --git a/gcc/testsuite/g++.dg/modules/auto-4_a.H b/gcc/testsuite/g++.dg/modules/auto-4_a.H new file mode 100644 index 000..0f7cd262dfa --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/auto-4_a.H @@ -0,0 +1,14 @@ +// PR c++/114795 +// { dg-additional-options "-fmodule-header" } +// { dg-module-cmi {} } + +template +struct A { + auto f() { return T(); } +}; + +template +void g() { + A a; + a.f(); +} diff --git a/gcc/testsuite/g++.dg/modules/auto-4_b.C b/gcc/testsuite/g++.dg/modules/auto-4_b.C new file mode 100644 index 000..378684ef6d0 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/auto-4_b.C @@ -0,0 +1,15 @@ +// PR c++/114795 +// { dg-additional-options "-fmodules-ts -fno-module-lazy" } + +template +struct A { + auto f() { return T(); } +}; + +A a; + +import "auto-4_a.H"; + +int main() { + g(); // { dg-bogus "before deduction of 'auto'" "" { target *-*-* } 0 } +}
[gcc r13-8608] c++: requires-exprs and partial constraint subst [PR110006]
https://gcc.gnu.org/g:38c2679ff9330d3ac1d5d86459294446733a435a commit r13-8608-g38c2679ff9330d3ac1d5d86459294446733a435a Author: Patrick Palka Date: Fri Feb 2 19:07:08 2024 -0500 c++: requires-exprs and partial constraint subst [PR110006] In r11-3261-gb28b621ac67bee we made tsubst_requires_expr never partially substitute into a requires-expression so as to avoid checking its requirements out of order during e.g. generic lambda regeneration. These PRs however illustrate that we still sometimes do need to partially substitute into a requires-expression, in particular when it appears in associated constraints that we're directly substituting for sake of declaration matching or dguide constraint rewriting. In these cases we're being called from tsubst_constraint during which processing_constraint_expression_p is true, so this patch checks this predicate to control whether we defer substitution or partially substitute. In turn, we now need to propagate semantic tsubst flags through tsubst_requires_expr rather than just using tf_none, notably for sake of dguide constraint rewriting which sets tf_dguide. PR c++/110006 PR c++/112769 gcc/cp/ChangeLog: * constraint.cc (subst_info::quiet): Accomodate non-diagnostic tsubst flags. (tsubst_valid_expression_requirement): Likewise. (tsubst_simple_requirement): Return a substituted _REQ node when processing_template_decl. (tsubst_type_requirement_1): Accomodate non-diagnostic tsubst flags. (tsubst_type_requirement): Return a substituted _REQ node when processing_template_decl. (tsubst_compound_requirement): Likewise. Accomodate non-diagnostic tsubst flags. (tsubst_nested_requirement): Likewise. (tsubst_requires_expr): Don't defer partial substitution when processing_constraint_expression_p is true, in which case return a substituted REQUIRES_EXPR. * pt.cc (tsubst_expr) : Accomodate non-diagnostic tsubst flags. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/class-deduction-alias18.C: New test. * g++.dg/cpp2a/concepts-friend16.C: New test. Reviewed-by: Jason Merrill (cherry picked from commit 686b5eb9c9ee623a604dde5c49fa11c23f384c62) Diff: --- gcc/cp/constraint.cc | 56 +- gcc/cp/pt.cc | 3 +- .../g++.dg/cpp2a/class-deduction-alias18.C | 13 + gcc/testsuite/g++.dg/cpp2a/concepts-friend16.C | 25 ++ 4 files changed, 84 insertions(+), 13 deletions(-) diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 273d15ab097..971619eabea 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -85,7 +85,7 @@ struct subst_info /* True if we should not diagnose errors. */ bool quiet() const { -return complain == tf_none; +return !(complain & tf_warning_or_error); } /* True if we should diagnose errors. */ @@ -1999,8 +1999,9 @@ hash_placeholder_constraint (tree c) static tree tsubst_valid_expression_requirement (tree t, tree args, sat_info info) { - tree r = tsubst_expr (t, args, tf_none, info.in_decl); - if (convert_to_void (r, ICV_STATEMENT, tf_none) != error_mark_node) + tsubst_flags_t quiet = info.complain & ~tf_warning_or_error; + tree r = tsubst_expr (t, args, quiet, info.in_decl); + if (convert_to_void (r, ICV_STATEMENT, quiet) != error_mark_node) return r; if (info.diagnose_unsatisfaction_p ()) @@ -2036,6 +2037,8 @@ tsubst_simple_requirement (tree t, tree args, sat_info info) tree expr = tsubst_valid_expression_requirement (t0, args, info); if (expr == error_mark_node) return error_mark_node; + if (processing_template_decl) +return finish_simple_requirement (EXPR_LOCATION (t), expr); return boolean_true_node; } @@ -2045,7 +2048,8 @@ tsubst_simple_requirement (tree t, tree args, sat_info info) static tree tsubst_type_requirement_1 (tree t, tree args, sat_info info, location_t loc) { - tree r = tsubst (t, args, tf_none, info.in_decl); + tsubst_flags_t quiet = info.complain & ~tf_warning_or_error; + tree r = tsubst (t, args, quiet, info.in_decl); if (r != error_mark_node) return r; @@ -2076,6 +2080,8 @@ tsubst_type_requirement (tree t, tree args, sat_info info) tree type = tsubst_type_requirement_1 (t0, args, info, EXPR_LOCATION (t)); if (type == error_mark_node) return error_mark_node; + if (processing_template_decl) +return finish_type_requirement (EXPR_LOCATION (t), type); return boolean_true_node; } @@ -2132,9 +2138,11 @@ tsubst_compound_requirement (tree t, tree args, sat_info info) location_t loc = cp_expr_loc_or_input_loc (expr); + subst_info quiet (info.complain & ~t
[gcc r14-9956] c++/modules: make bits_in/out move-constructible
https://gcc.gnu.org/g:da375baf54944298303f13c375a5756c6131d672 commit r14-9956-gda375baf54944298303f13c375a5756c6131d672 Author: Patrick Palka Date: Sat Apr 13 16:06:28 2024 -0400 c++/modules: make bits_in/out move-constructible gcc/cp/ChangeLog: * module.cc (struct bytes_in::bits_in): Define defaulted move ctor. (struct bytes_out::bits_out): Likewise. Diff: --- gcc/cp/module.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index bbed82652d4..c6f71e11515 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -706,6 +706,7 @@ struct bytes_in::bits_in { bflush (); } + bits_in(bits_in&&) = default; bits_in(const bits_in&) = delete; bits_in& operator=(const bits_in&) = delete; @@ -752,6 +753,7 @@ struct bytes_out::bits_out { bflush (); } + bits_out(bits_out&&) = default; bits_out(const bits_out&) = delete; bits_out& operator=(const bits_out&) = delete;
[gcc r14-9955] c++/modules: optimize tree flag streaming
https://gcc.gnu.org/g:436ab7e8e8b16866d8a807af242560ad4fdff0d6 commit r14-9955-g436ab7e8e8b16866d8a807af242560ad4fdff0d6 Author: Patrick Palka Date: Sat Apr 13 10:52:32 2024 -0400 c++/modules: optimize tree flag streaming One would expect consecutive calls to bytes_in/out::b for streaming adjacent bits, as is done for tree flag streaming, to at least be optimized by the compiler into individual bit operations using statically known bit positions (and ideally combined into larger sized reads/writes). Unfortunately this doesn't happen because the compiler has trouble tracking the values of this->bit_pos and this->bit_val across the calls, likely because the compiler doesn't know the value of 'this'. Thus for each consecutive bit stream operation, bit_pos and bit_val are loaded from 'this', checked if buffering is needed, and finally the bit is extracted from bit_val according to the (unknown) bit_pos, even though relative to the previous operation (if we didn't need to buffer) bit_val is unchanged and bit_pos is just 1 larger. This ends up being quite slow, with tree_node_bools taking 10% of time when streaming in the std module. This patch improves this by making tracking of bit_pos and bit_val easier for the compiler. Rather than bit_pos and bit_val being members of the (effectively global) bytes_in/out objects, this patch factors out the bit streaming code/state into separate classes bits_in/out that get constructed locally as needed for bit streaming. Since these objects are now clearly local, the compiler can more easily track their values and optimize away redundant buffering checks. And since bit streaming is intended to be batched it's natural for these new classes to be RAII-enabled such that the bit stream is flushed upon destruction. In order to make the most of this improved tracking of bit position, this patch changes parts where we conditionally stream a tree flag to unconditionally stream (the flag or a dummy value). That way the number of bits streamed and the respective bit positions are as statically known as reasonably possible. In lang_decl_bools and lang_type_bools this patch makes us flush the current bit buffer at the start so that subsequent bit positions are in turn statically known. And in core_bools, we can add explicit early exits utilizing invariants that the compiler can't figure out itself (e.g. a tree code can't have both TS_TYPE_COMMON and TS_DECL_COMMON, and if a tree code doesn't have TS_DECL_COMMON then it doesn't have TS_DECL_WITH_VIS). This patch also moves the definitions of the relevant streaming classes into anonymous namespaces so that the compiler can make more informed decisions about inlining their member functions. After this patch, compile time for a simple Hello World using the std module is reduced by 7% with a release compiler. The on-disk size of the std module increases by 0.4% (presumably due to the extra flushing done in lang_decl_bools and lang_type_bools). The bit stream out performance isn't improved as much as the stream in due to the spans/lengths instrumentation performed on stream out (which maybe should be disabled for release builds?) gcc/cp/ChangeLog: * module.cc: Update comment about classes defined within. (class data): Enclose in an anonymous namespace. (data::calc_crc): Moved from bytes::calc_crc. (class bytes): Remove. Move bit_flush to namespace scope. (class bytes_in): Enclose in an anonymous namespace. Inherit directly from data and adjust accordingly. Move b and bflush members to bits_in. (class bytes_out): As above. Remove is_set static data member. (bit_flush): Moved from class bytes. (struct bytes_in::bits_in): Define. (struct bytes_out::bits_out): Define. (bytes_in::stream_bits): Define. (bytes_out::stream_bits): Define. (bytes_out::bflush): Moved to bits_out/in. (bytes_in::bflush): Likewise (bytes_in::bfill): Removed. (bytes_out::b): Moved to bits_out/in. (bytes_in::b): Likewise. (class trees_in): Enclose in an anonymous namespace. (class trees_out): Enclose in an anonymous namespace. (trees_out::core_bools): Add bits_out/in parameter and use it. Unconditionally stream a bit for public_flag. Add early exits as appropriate. (trees_out::core_bools): Likewise. (trees_out::lang_decl_bools): Add bits_out/in parameter and use it. Flush the current bit buffer at the start. Unconditionally stream a bit for module_keyed_decls_p. (trees_in::lang_decl_bools)