Skip to content

Address of class-type NTTP in a member template signature fails deduction after enclosing template is instantiated #423

Open

Description

@daveedvdv-nvidia

Issue Summary

When a class-type non-type template parameter V is substituted as part of instantiating an enclosing template (a class template, a partial specialization, or a function template containing a generic lambda), and &V appears in the signature of a member function template together with a still-dependent parameter, deducing the member template's arguments fails.

The substituted expression refers to the template parameter object, and when it is rescanned during deduction, make_operand_for_rescanned_identifier (src/expr.c) only rebuilds the object as an lvalue if the object's initializer is associated with a constant symbol. Otherwise, it falls back to make_constant_operand, which turns V into a prvalue, so &V is ill-formed and deduction fails.

GCC 15 and Clang 21 accept the code below. This is independent of #414 / #422: it fails the same way with and without that change.

Reproducing Source Code

struct A { int i = 0; };
constexpr A a1{1};

template <A V> struct S {
  template <typename T> static auto f(T t) -> decltype(t, &V);
};
using R1 = decltype(S<a1>::f(0));

template <A V> constexpr auto mk() {
  return [](auto t) -> decltype(t, &V) { return &V; };
}
static_assert(mk<a1>()(0) == mk<a1>()(0L));

template <typename T, typename U> struct X;
template <A V> struct Tag { };
template <A V, typename U> struct X<Tag<V>, U> {
  template <typename T> static auto f(T t) -> decltype(t, U(), &V);
};
using R3 = decltype(X<Tag<a1>, int>::f(0));

Command-line Options

cpfe --c++20 test.cpp

Type of Issue

[Front End] This code SHOULD compile with these options.

Additional Details

Current output:

"test.cpp", line 7: error: no instance of function template
          "S<V>::f [with V=A{1}]" matches the argument list
            argument types are: (int)
  using R1 = decltype(S<a1>::f(0));
                      ^
"test.cpp", line 5: note: candidate function template "S<V>::f
          [with V=A{1}]" failed deduction
    template <typename T> static auto f(T t) -> decltype(t, &V);
                                      ^

"test.cpp", line 12: error: no instance of function template
          "lambda [](auto)->decltype((<expression>))" matches the argument list
            argument types are: (int)
            object type is: lambda [](auto)->decltype((<expression>))
  static_assert(mk<a1>()(0) == mk<a1>()(0L));
                ^
"test.cpp", line 10: note: candidate function template "lambda
          [](auto)->decltype((<expression>))" failed deduction
    return [](auto t) -> decltype(t, &V) { return &V; };
             ^

"test.cpp", line 12: error: no instance of function template
          "lambda [](auto)->decltype((<expression>))" matches the argument list
            argument types are: (long)
            object type is: lambda [](auto)->decltype((<expression>))
  static_assert(mk<a1>()(0) == mk<a1>()(0L));
                               ^
"test.cpp", line 10: note: candidate function template "lambda
          [](auto)->decltype((<expression>))" failed deduction
    return [](auto t) -> decltype(t, &V) { return &V; };
             ^

"test.cpp", line 19: error: no instance of function template
          "X<Tag<V>, U>::f [with V=A{1}, U=int]" matches the argument list
            argument types are: (int)
  using R3 = decltype(X<Tag<a1>, int>::f(0));
                      ^
"test.cpp", line 17: note: candidate function template
          "X<Tag<V>, U>::f [with V=A{1}, U=int]" failed deduction
    template <typename T> static auto f(T t) -> decltype(t, U(), &V);
                                      ^

4 errors detected in the compilation of "test.cpp".

Expected: no errors. A quick experiment that makes the fallback in make_operand_for_rescanned_identifier produce a const lvalue for the template parameter object variable (instead of calling make_constant_operand) makes all three cases compile.

Reproducing (Standard) Configuration(s)

linux-gcc-debug

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions