https://gcc.gnu.org/g:a5d39331b959364c25908669194377bac19316b8
commit r16-9144-ga5d39331b959364c25908669194377bac19316b8 Author: Patrick Palka <[email protected]> Date: Mon Apr 27 17:56:18 2026 -0400 c++: fix decltype(id) for pointer-to-data-member access expr [PR124978] Here after substitution into decltype(X), X is the expanded but not constant-evaluated pointer-to-data-member access expression *((const int *) *cw<Divide{42}>::value + (sizetype) *cw<&Divide::value>::value) and finish_decltype_type wrongly strips the outermost INDIRECT_REF under the assumption that it's an implicit dereference of a reference, but here it's an explicit pointer dereference. This causes the decltype to yield const int* instead of the expected int. This patch fixes this particular bug by checking REFERENCE_REF_P instead of INDIRECT_REF_P which additionally verifies the dereferenced thing actually has reference type. The decltype now yields the correct type modulo an unnecessary const due to the separate bug PR115314. PR c++/124978 PR c++/115314 gcc/cp/ChangeLog: * semantics.cc (finish_decltype_type): Check REFERENCE_REF_P instead of INDIRECT_REF_P before stripping implicit dereferences. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/nontype-class74.C: New test. Reviewed-by: Jason Merrill <[email protected]> (cherry picked from commit c607c686100689e3e68487cd8097c2fbd3904168) Diff: --- gcc/cp/semantics.cc | 2 +- gcc/testsuite/g++.dg/cpp2a/nontype-class74.C | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index dfde8f1925b5..ca9a625d2998 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -13253,7 +13253,7 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p, is T , and decltype((r)) is const T&." */ expr = strip_contract_const_wrapper (expr); - if (INDIRECT_REF_P (expr) + if (REFERENCE_REF_P (expr) || TREE_CODE (expr) == VIEW_CONVERT_EXPR) /* This can happen when the expression is, e.g., "a.b". Just look at the underlying operand. */ diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class74.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class74.C new file mode 100644 index 000000000000..96850889558e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class74.C @@ -0,0 +1,15 @@ +// PR c++/124978 +// { dg-do compile { target c++20 } } + +template<auto X, class = decltype(X)> +struct cw { static constexpr const auto& value = X; }; + +template<class L, class R> +auto f(L, R) -> cw<(L::value ->* R::value)>; + +struct Divide { int value; }; +auto co = cw<&cw<Divide{42}>::value>{}; +auto cm = cw<&Divide::value>{}; + +using type = decltype(f(co, cm)); +using type = cw<42, const int>; // FIXME PR115314, unexpected 'const'
