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'

Reply via email to