* [PATCH] c++: odr-use argument to a function NTTP [PR53164]
@ 2021-10-04 16:40 Patrick Palka
2021-10-05 19:17 ` Patrick Palka
0 siblings, 1 reply; 8+ messages in thread
From: Patrick Palka @ 2021-10-04 16:40 UTC (permalink / raw)
To: gcc-patches
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;
+}
+
+template void g<0>();
--
2.33.0.610.gcefe983a32
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] c++: odr-use argument to a function NTTP [PR53164]
2021-10-04 16:40 [PATCH] c++: odr-use argument to a function NTTP [PR53164] Patrick Palka
@ 2021-10-05 19:17 ` Patrick Palka
2021-10-06 0:38 ` Jason Merrill
0 siblings, 1 reply; 8+ messages in thread
From: Patrick Palka @ 2021-10-05 19:17 UTC (permalink / raw)
To: Patrick Palka; +Cc: gcc-patches, jason
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.
> +
> +template void g<0>();
> --
> 2.33.0.610.gcefe983a32
>
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] c++: odr-use argument to a function NTTP [PR53164]
2021-10-05 19:17 ` Patrick Palka
@ 2021-10-06 0:38 ` Jason Merrill
2021-10-06 16:25 ` Patrick Palka
0 siblings, 1 reply; 8+ messages in thread
From: Jason Merrill @ 2021-10-06 0:38 UTC (permalink / raw)
To: Patrick Palka; +Cc: gcc-patches
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
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] c++: odr-use argument to a function NTTP [PR53164]
2021-10-06 0:38 ` Jason Merrill
@ 2021-10-06 16:25 ` Patrick Palka
2021-10-06 19:52 ` Patrick Palka
0 siblings, 1 reply; 8+ messages in thread
From: Patrick Palka @ 2021-10-06 16:25 UTC (permalink / raw)
To: Jason Merrill; +Cc: Patrick Palka, gcc-patches
On Tue, 5 Oct 2021, Jason Merrill wrote:
> 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, makes sense.. I'm not sure where else we can mark the use, then.
Since we resolve the OVERLOAD f to the FUNCTION_DECL f<int> ahead of
time (during which mark_used doesn't actually instantiate f<int> because
we're inside a template), at instantiation time the type A<f> is already
non-dependent so tsubst_aggr_type avoids doing the work that would end
up calling convert_nontype_argument_function.
>
> 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
FWIW although Clang doesn't reject 'A<f> a;', it does reject
'using type = A<f>;' weirdly enough: https://godbolt.org/z/T9qEn6bWW
Shall we just go with the other more specific approach, that makes sure
the CALL_EXPR case of tsubst_expr calls mark_used when the callee is an
ADDR_EXPR? Something like (bootstrapped and regtested):
-- >8 --
PR c++/53164
gcc/cp/ChangeLog:
* pt.c (tsubst_copy_and_build) <case CALL_EXPR>: Look through
ADDR_EXPR after substituting into the callee.
gcc/testsuite/ChangeLog:
* g++.dg/template/fn-ptr3.C: New test.
---
gcc/cp/pt.c | 4 ++++
gcc/testsuite/g++.dg/template/fn-ptr3.C | 20 ++++++++++++++++++++
2 files changed, 24 insertions(+)
create mode 100644 gcc/testsuite/g++.dg/template/fn-ptr3.C
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 19e03369ffa..5af3a6472f8 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -20310,6 +20310,10 @@ tsubst_copy_and_build (tree t,
if (BASELINK_P (function))
qualified_p = true;
+
+ if (TREE_CODE (function) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL)
+ function = TREE_OPERAND (function, 0);
}
nargs = call_expr_nargs (t);
diff --git a/gcc/testsuite/g++.dg/template/fn-ptr3.C b/gcc/testsuite/g++.dg/template/fn-ptr3.C
new file mode 100644
index 00000000000..4aa193bd961
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/fn-ptr3.C
@@ -0,0 +1,20 @@
+// PR c++/53164
+
+template<class T>
+void f(T) {
+ T::fail; // { dg-error "not a member" }
+}
+
+template<void p(int)>
+struct A {
+ static void h() {
+ p(0);
+ }
+};
+
+template<int>
+void g() {
+ A<f>::h();
+}
+
+template void g<0>();
--
2.33.0.664.g0785eb7698
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] c++: odr-use argument to a function NTTP [PR53164]
2021-10-06 16:25 ` Patrick Palka
@ 2021-10-06 19:52 ` Patrick Palka
2021-10-06 22:19 ` Jason Merrill
0 siblings, 1 reply; 8+ messages in thread
From: Patrick Palka @ 2021-10-06 19:52 UTC (permalink / raw)
To: Patrick Palka; +Cc: Jason Merrill, gcc-patches
On Wed, 6 Oct 2021, Patrick Palka wrote:
> On Tue, 5 Oct 2021, Jason Merrill wrote:
>
> > 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, makes sense.. I'm not sure where else we can mark the use, then.
> Since we resolve the OVERLOAD f to the FUNCTION_DECL f<int> ahead of
> time (during which mark_used doesn't actually instantiate f<int> because
> we're inside a template), at instantiation time the type A<f> is already
> non-dependent so tsubst_aggr_type avoids doing the work that would end
> up calling convert_nontype_argument_function.
>
> >
> > 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
>
> FWIW although Clang doesn't reject 'A<f> a;', it does reject
> 'using type = A<f>;' weirdly enough: https://godbolt.org/z/T9qEn6bWW
>
>
> Shall we just go with the other more specific approach, that makes sure
> the CALL_EXPR case of tsubst_expr calls mark_used when the callee is an
> ADDR_EXPR? Something like (bootstrapped and regtested):
Err, this approach is wrong because by stripping the ADDR_EXPR here we
end up checking access of the unwrapped FUNCTION_DECL again after
substituting into the call. So we incorrectly reject e.g.
template<void P()>
void g() {
P(); // error: ‘static void A::h()’ is private within this context
}
struct A {
void f() {
g<h>();
}
private:
static void h();
};
since A::h isn't accessible from g.
>
> -- >8 --
>
> PR c++/53164
>
> gcc/cp/ChangeLog:
>
> * pt.c (tsubst_copy_and_build) <case CALL_EXPR>: Look through
> ADDR_EXPR after substituting into the callee.
>
> gcc/testsuite/ChangeLog:
>
> * g++.dg/template/fn-ptr3.C: New test.
> ---
> gcc/cp/pt.c | 4 ++++
> gcc/testsuite/g++.dg/template/fn-ptr3.C | 20 ++++++++++++++++++++
> 2 files changed, 24 insertions(+)
> create mode 100644 gcc/testsuite/g++.dg/template/fn-ptr3.C
>
> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> index 19e03369ffa..5af3a6472f8 100644
> --- a/gcc/cp/pt.c
> +++ b/gcc/cp/pt.c
> @@ -20310,6 +20310,10 @@ tsubst_copy_and_build (tree t,
>
> if (BASELINK_P (function))
> qualified_p = true;
> +
> + if (TREE_CODE (function) == ADDR_EXPR
> + && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL)
> + function = TREE_OPERAND (function, 0);
> }
>
> nargs = call_expr_nargs (t);
> diff --git a/gcc/testsuite/g++.dg/template/fn-ptr3.C b/gcc/testsuite/g++.dg/template/fn-ptr3.C
> new file mode 100644
> index 00000000000..4aa193bd961
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/template/fn-ptr3.C
> @@ -0,0 +1,20 @@
> +// PR c++/53164
> +
> +template<class T>
> +void f(T) {
> + T::fail; // { dg-error "not a member" }
> +}
> +
> +template<void p(int)>
> +struct A {
> + static void h() {
> + p(0);
> + }
> +};
> +
> +template<int>
> +void g() {
> + A<f>::h();
> +}
> +
> +template void g<0>();
> --
> 2.33.0.664.g0785eb7698
>
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] c++: odr-use argument to a function NTTP [PR53164]
2021-10-06 19:52 ` Patrick Palka
@ 2021-10-06 22:19 ` Jason Merrill
2021-10-07 15:17 ` Patrick Palka
0 siblings, 1 reply; 8+ messages in thread
From: Jason Merrill @ 2021-10-06 22:19 UTC (permalink / raw)
To: Patrick Palka; +Cc: gcc-patches
On 10/6/21 15:52, Patrick Palka wrote:
> On Wed, 6 Oct 2021, Patrick Palka wrote:
>
>> On Tue, 5 Oct 2021, Jason Merrill wrote:
>>
>>> 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, makes sense.. I'm not sure where else we can mark the use, then.
>> Since we resolve the OVERLOAD f to the FUNCTION_DECL f<int> ahead of
>> time (during which mark_used doesn't actually instantiate f<int> because
>> we're inside a template), at instantiation time the type A<f> is already
>> non-dependent so tsubst_aggr_type avoids doing the work that would end
>> up calling convert_nontype_argument_function.
>>
>>>
>>> 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
>>
>> FWIW although Clang doesn't reject 'A<f> a;', it does reject
>> 'using type = A<f>;' weirdly enough: https://godbolt.org/z/T9qEn6bWW
>>
>>
>> Shall we just go with the other more specific approach, that makes sure
>> the CALL_EXPR case of tsubst_expr calls mark_used when the callee is an
>> ADDR_EXPR? Something like (bootstrapped and regtested):
>
> Err, this approach is wrong because by stripping the ADDR_EXPR here we
> end up checking access of the unwrapped FUNCTION_DECL again after
> substituting into the call. So we incorrectly reject e.g.
>
> template<void P()>
> void g() {
> P(); // error: ‘static void A::h()’ is private within this context
> }
>
> struct A {
> void f() {
> g<h>();
> }
> private:
> static void h();
> };
>
> since A::h isn't accessible from g.
I guess you could call mark_used directly instead of stripping the
ADDR_EXPR.
Or for the general problem, perhaps we could mark the TEMPLATE_INFO or
TI_ARGS to indicate that we still need to mark_used the arguments when
we encounter A<f> again during instantiation?
>>
>> -- >8 --
>>
>> PR c++/53164
>>
>> gcc/cp/ChangeLog:
>>
>> * pt.c (tsubst_copy_and_build) <case CALL_EXPR>: Look through
>> ADDR_EXPR after substituting into the callee.
>>
>> gcc/testsuite/ChangeLog:
>>
>> * g++.dg/template/fn-ptr3.C: New test.
>> ---
>> gcc/cp/pt.c | 4 ++++
>> gcc/testsuite/g++.dg/template/fn-ptr3.C | 20 ++++++++++++++++++++
>> 2 files changed, 24 insertions(+)
>> create mode 100644 gcc/testsuite/g++.dg/template/fn-ptr3.C
>>
>> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
>> index 19e03369ffa..5af3a6472f8 100644
>> --- a/gcc/cp/pt.c
>> +++ b/gcc/cp/pt.c
>> @@ -20310,6 +20310,10 @@ tsubst_copy_and_build (tree t,
>>
>> if (BASELINK_P (function))
>> qualified_p = true;
>> +
>> + if (TREE_CODE (function) == ADDR_EXPR
>> + && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL)
>> + function = TREE_OPERAND (function, 0);
>> }
>>
>> nargs = call_expr_nargs (t);
>> diff --git a/gcc/testsuite/g++.dg/template/fn-ptr3.C b/gcc/testsuite/g++.dg/template/fn-ptr3.C
>> new file mode 100644
>> index 00000000000..4aa193bd961
>> --- /dev/null
>> +++ b/gcc/testsuite/g++.dg/template/fn-ptr3.C
>> @@ -0,0 +1,20 @@
>> +// PR c++/53164
>> +
>> +template<class T>
>> +void f(T) {
>> + T::fail; // { dg-error "not a member" }
>> +}
>> +
>> +template<void p(int)>
>> +struct A {
>> + static void h() {
>> + p(0);
>> + }
>> +};
>> +
>> +template<int>
>> +void g() {
>> + A<f>::h();
>> +}
>> +
>> +template void g<0>();
>> --
>> 2.33.0.664.g0785eb7698
>>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] c++: odr-use argument to a function NTTP [PR53164]
2021-10-06 22:19 ` Jason Merrill
@ 2021-10-07 15:17 ` Patrick Palka
2021-10-07 17:03 ` Jason Merrill
0 siblings, 1 reply; 8+ messages in thread
From: Patrick Palka @ 2021-10-07 15:17 UTC (permalink / raw)
To: Jason Merrill; +Cc: Patrick Palka, gcc-patches
On Wed, 6 Oct 2021, Jason Merrill wrote:
> On 10/6/21 15:52, Patrick Palka wrote:
> > On Wed, 6 Oct 2021, Patrick Palka wrote:
> >
> > > On Tue, 5 Oct 2021, Jason Merrill wrote:
> > >
> > > > 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, makes sense.. I'm not sure where else we can mark the use, then.
> > > Since we resolve the OVERLOAD f to the FUNCTION_DECL f<int> ahead of
> > > time (during which mark_used doesn't actually instantiate f<int> because
> > > we're inside a template), at instantiation time the type A<f> is already
> > > non-dependent so tsubst_aggr_type avoids doing the work that would end
> > > up calling convert_nontype_argument_function.
> > >
> > > >
> > > > 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
> > >
> > > FWIW although Clang doesn't reject 'A<f> a;', it does reject
> > > 'using type = A<f>;' weirdly enough: https://godbolt.org/z/T9qEn6bWW
> > >
> > >
> > > Shall we just go with the other more specific approach, that makes sure
> > > the CALL_EXPR case of tsubst_expr calls mark_used when the callee is an
> > > ADDR_EXPR? Something like (bootstrapped and regtested):
> >
> > Err, this approach is wrong because by stripping the ADDR_EXPR here we
> > end up checking access of the unwrapped FUNCTION_DECL again after
> > substituting into the call. So we incorrectly reject e.g.
> >
> > template<void P()>
> > void g() {
> > P(); // error: ‘static void A::h()’ is private within this context
> > }
> >
> > struct A {
> > void f() {
> > g<h>();
> > }
> > private:
> > static void h();
> > };
> >
> > since A::h isn't accessible from g.
>
> I guess you could call mark_used directly instead of stripping the ADDR_EXPR.
That seems to work nicely, how does the below look? Bootstrapped and
regtested on x86_64-pc-linux-gnu.
>
> Or for the general problem, perhaps we could mark the TEMPLATE_INFO or TI_ARGS
> to indicate that we still need to mark_used the arguments when we encounter
> A<f> again during instantiation?
That sounds plausible, though I suppose it might not be worth it only to
handle such a corner case..
-- >8 --
Subject: [PATCH] c++: function NTTP argument considered unused [PR53164]
Here at parse time the template argument f (an OVERLOAD) in A<f> gets
resolved ahead of time to the FUNCTION_DECL f<int>, and we defer marking
f<int> as used until instantiation (of g) as usual.
Later when instantiating g the type A<f> (where f has already been resolved)
is non-dependent, so tsubst_aggr_type avoids re-processing its template
arguments, and we end up never actually marking f<int> as used (which means
we never instantiate it) even though A<f>::h() calls it.
This patch works around this problem by making us look through ADDR_EXPR
when calling mark_used on the callee of a substituted CALL_EXPR.
PR c++/53164
gcc/cp/ChangeLog:
* pt.c (tsubst_copy_and_build) <case CALL_EXPR>: Look through an
ADDR_EXPR callee when calling mark_used.
gcc/testsuite/ChangeLog:
* g++.dg/template/fn-ptr3.C: New test.
---
gcc/cp/pt.c | 12 ++++++++----
gcc/testsuite/g++.dg/template/fn-ptr3.C | 20 ++++++++++++++++++++
2 files changed, 28 insertions(+), 4 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/template/fn-ptr3.C
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 1e52aa757e1..cd10340ce12 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -20508,10 +20508,14 @@ tsubst_copy_and_build (tree t,
}
/* Remember that there was a reference to this entity. */
- if (function != NULL_TREE
- && DECL_P (function)
- && !mark_used (function, complain) && !(complain & tf_error))
- RETURN (error_mark_node);
+ if (function)
+ {
+ tree sub = function;
+ if (TREE_CODE (sub) == ADDR_EXPR)
+ sub = TREE_OPERAND (sub, 0);
+ if (!mark_used (sub, complain) && !(complain & tf_error))
+ RETURN (error_mark_node);
+ }
if (!maybe_fold_fn_template_args (function, complain))
return error_mark_node;
diff --git a/gcc/testsuite/g++.dg/template/fn-ptr3.C b/gcc/testsuite/g++.dg/template/fn-ptr3.C
new file mode 100644
index 00000000000..fd7b31bf775
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/fn-ptr3.C
@@ -0,0 +1,20 @@
+// PR c++/53164
+
+template<class T>
+void f(T) {
+ T::fail; // { dg-error "'fail' is not a member of 'int'" }
+}
+
+template<void P(int)>
+struct A {
+ static void h() {
+ P(0);
+ }
+};
+
+template<int>
+void g() {
+ A<f>::h();
+}
+
+template void g<0>();
--
2.33.0.721.g106298f7f9
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] c++: odr-use argument to a function NTTP [PR53164]
2021-10-07 15:17 ` Patrick Palka
@ 2021-10-07 17:03 ` Jason Merrill
0 siblings, 0 replies; 8+ messages in thread
From: Jason Merrill @ 2021-10-07 17:03 UTC (permalink / raw)
To: Patrick Palka; +Cc: gcc-patches
On 10/7/21 11:17, Patrick Palka wrote:
> On Wed, 6 Oct 2021, Jason Merrill wrote:
>
>> On 10/6/21 15:52, Patrick Palka wrote:
>>> On Wed, 6 Oct 2021, Patrick Palka wrote:
>>>
>>>> On Tue, 5 Oct 2021, Jason Merrill wrote:
>>>>
>>>>> 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, makes sense.. I'm not sure where else we can mark the use, then.
>>>> Since we resolve the OVERLOAD f to the FUNCTION_DECL f<int> ahead of
>>>> time (during which mark_used doesn't actually instantiate f<int> because
>>>> we're inside a template), at instantiation time the type A<f> is already
>>>> non-dependent so tsubst_aggr_type avoids doing the work that would end
>>>> up calling convert_nontype_argument_function.
>>>>
>>>>>
>>>>> 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
>>>>
>>>> FWIW although Clang doesn't reject 'A<f> a;', it does reject
>>>> 'using type = A<f>;' weirdly enough: https://godbolt.org/z/T9qEn6bWW
>>>>
>>>>
>>>> Shall we just go with the other more specific approach, that makes sure
>>>> the CALL_EXPR case of tsubst_expr calls mark_used when the callee is an
>>>> ADDR_EXPR? Something like (bootstrapped and regtested):
>>>
>>> Err, this approach is wrong because by stripping the ADDR_EXPR here we
>>> end up checking access of the unwrapped FUNCTION_DECL again after
>>> substituting into the call. So we incorrectly reject e.g.
>>>
>>> template<void P()>
>>> void g() {
>>> P(); // error: ‘static void A::h()’ is private within this context
>>> }
>>>
>>> struct A {
>>> void f() {
>>> g<h>();
>>> }
>>> private:
>>> static void h();
>>> };
>>>
>>> since A::h isn't accessible from g.
>>
>> I guess you could call mark_used directly instead of stripping the ADDR_EXPR.
>
> That seems to work nicely, how does the below look? Bootstrapped and
> regtested on x86_64-pc-linux-gnu.
>
>>
>> Or for the general problem, perhaps we could mark the TEMPLATE_INFO or TI_ARGS
>> to indicate that we still need to mark_used the arguments when we encounter
>> A<f> again during instantiation?
>
> That sounds plausible, though I suppose it might not be worth it only to
> handle such a corner case..
Indeed. A lower-overhead possibility would be to remember, for a
template, decls that we wanted to mark_used but didn't because we were
in a template. But I wouldn't worry about it for now.
> -- >8 --
>
> Subject: [PATCH] c++: function NTTP argument considered unused [PR53164]
>
> Here at parse time the template argument f (an OVERLOAD) in A<f> gets
> resolved ahead of time to the FUNCTION_DECL f<int>, and we defer marking
> f<int> as used until instantiation (of g) as usual.
>
> Later when instantiating g the type A<f> (where f has already been resolved)
> is non-dependent, so tsubst_aggr_type avoids re-processing its template
> arguments, and we end up never actually marking f<int> as used (which means
> we never instantiate it) even though A<f>::h() calls it.
>
> This patch works around this problem by making us look through ADDR_EXPR
> when calling mark_used on the callee of a substituted CALL_EXPR.
>
> PR c++/53164
>
> gcc/cp/ChangeLog:
>
> * pt.c (tsubst_copy_and_build) <case CALL_EXPR>: Look through an
> ADDR_EXPR callee when calling mark_used.
>
> gcc/testsuite/ChangeLog:
>
> * g++.dg/template/fn-ptr3.C: New test.
> ---
> gcc/cp/pt.c | 12 ++++++++----
> gcc/testsuite/g++.dg/template/fn-ptr3.C | 20 ++++++++++++++++++++
> 2 files changed, 28 insertions(+), 4 deletions(-)
> create mode 100644 gcc/testsuite/g++.dg/template/fn-ptr3.C
>
> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> index 1e52aa757e1..cd10340ce12 100644
> --- a/gcc/cp/pt.c
> +++ b/gcc/cp/pt.c
> @@ -20508,10 +20508,14 @@ tsubst_copy_and_build (tree t,
> }
>
> /* Remember that there was a reference to this entity. */
> - if (function != NULL_TREE
> - && DECL_P (function)
> - && !mark_used (function, complain) && !(complain & tf_error))
> - RETURN (error_mark_node);
> + if (function)
> + {
> + tree sub = function;
> + if (TREE_CODE (sub) == ADDR_EXPR)
> + sub = TREE_OPERAND (sub, 0);
Let's add a comment about why this is needed. OK with that change.
> + if (!mark_used (sub, complain) && !(complain & tf_error))
> + RETURN (error_mark_node);
> + }
>
> if (!maybe_fold_fn_template_args (function, complain))
> return error_mark_node;
> diff --git a/gcc/testsuite/g++.dg/template/fn-ptr3.C b/gcc/testsuite/g++.dg/template/fn-ptr3.C
> new file mode 100644
> index 00000000000..fd7b31bf775
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/template/fn-ptr3.C
> @@ -0,0 +1,20 @@
> +// PR c++/53164
> +
> +template<class T>
> +void f(T) {
> + T::fail; // { dg-error "'fail' is not a member of 'int'" }
> +}
> +
> +template<void P(int)>
> +struct A {
> + static void h() {
> + P(0);
> + }
> +};
> +
> +template<int>
> +void g() {
> + A<f>::h();
> +}
> +
> +template void g<0>();
>
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2021-10-07 17:03 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-10-04 16:40 [PATCH] c++: odr-use argument to a function NTTP [PR53164] Patrick Palka
2021-10-05 19:17 ` Patrick Palka
2021-10-06 0:38 ` Jason Merrill
2021-10-06 16:25 ` Patrick Palka
2021-10-06 19:52 ` Patrick Palka
2021-10-06 22:19 ` Jason Merrill
2021-10-07 15:17 ` Patrick Palka
2021-10-07 17:03 ` Jason Merrill
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).