[PATCH] c++: odr-use argument to a function NTTP [PR53164]

Jason Merrill jason@redhat.com
Wed Oct 6 00:38:03 GMT 2021


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



More information about the Gcc-patches mailing list