On 10/5/21 15:17, Patrick Palka wrote:
On Mon, 4 Oct 2021, Patrick Palka wrote:
When passing a function template as the argument to a function NTTP
inside a template, we resolve it to the right specialization ahead of
time via resolve_address_of_overloaded_function, though the call to
mark_used within defers odr-using it until instantiation time (as usual).
But at instantiation time we end up never calling mark_used on the
specialization.
This patch fixes this by adding a call to mark_used in
convert_nontype_argument_function.
PR c++/53164
gcc/cp/ChangeLog:
* pt.c (convert_nontype_argument_function): Call mark_used.
gcc/testsuite/ChangeLog:
* g++.dg/template/non-dependent16.C: New test.
---
gcc/cp/pt.c | 3 +++
gcc/testsuite/g++.dg/template/non-dependent16.C | 16 ++++++++++++++++
2 files changed, 19 insertions(+)
create mode 100644 gcc/testsuite/g++.dg/template/non-dependent16.C
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index f950f4a21b7..5e819c9598c 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -6668,6 +6668,9 @@ convert_nontype_argument_function (tree type, tree expr,
return NULL_TREE;
}
+ if (!mark_used (fn_no_ptr, complain) && !(complain & tf_error))
+ return NULL_TREE;
+
linkage = decl_linkage (fn_no_ptr);
if (cxx_dialect >= cxx11 ? linkage == lk_none : linkage != lk_external)
{
diff --git a/gcc/testsuite/g++.dg/template/non-dependent16.C
b/gcc/testsuite/g++.dg/template/non-dependent16.C
new file mode 100644
index 00000000000..b7dca8f6752
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/non-dependent16.C
@@ -0,0 +1,16 @@
+// PR c++/53164
+
+template<class T>
+void f(T) {
+ T::fail; // { dg-error "not a member" }
+}
+
+template<void(int)>
+struct A { };
+
+template<int>
+void g() {
+ A<f> a;
+}
I should mention that the original testcase in the PR was slightly
different than this one in that it also performed a call to the NTTP,
e.g.
template<void p(int)>
struct A {
static void h() {
p(0);
}
};
template<int>
void g() {
A<f>::h();
}
templated void g<0>();
and not even the call was enough to odr-use f, apparently because the
CALL_EXPR case of tsubst_expr calls mark_used on the callee only when
it's a FUNCTION_DECL, but in this case after substitution it's an
ADDR_EXPR of a FUNCTION_DECL. Fixing this by looking through the ADDR_EXPR
worked, but IIUC the call isn't necessary for f to be odr-used, simply
using f as a template argument should be sufficient, so it seems the
above is better fix.
I agree that pedantically the use happens when substituting into the use
of A<f>, but convert_nontype_argument_function seems like a weird place
to implement that; it's only called again during instantiation of A<f>,
when we instantiate the injected-class-name. If A<f> isn't
instantiated, e.g. if 'a' is a pointer to A<f>, we again don't
instantiate f<int>.
I see that clang doesn't reject your testcase, either, but MSVC and icc
do (even with 'a' a pointer): https://godbolt.org/z/MGE6TcMch
Jason