public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Jason Merrill <jason@redhat.com>
To: Patrick Palka <ppalka@redhat.com>
Cc: gcc-patches@gcc.gnu.org
Subject: Re: [PATCH] c++: function NTTP argument considered unused [PR53164, PR105848]
Date: Tue, 7 Jun 2022 16:09:05 -0400	[thread overview]
Message-ID: <ac511523-c36d-4fa9-4ce6-2c0bc81c0cbd@redhat.com> (raw)
In-Reply-To: <20cd91d1-38a1-03f9-3565-682542344347@idea>

On 6/7/22 15:18, Patrick Palka wrote:
> On Tue, 7 Jun 2022, Jason Merrill wrote:
> 
>> On 6/7/22 09:24, Patrick Palka wrote:
>>> On Mon, 6 Jun 2022, Jason Merrill wrote:
>>>
>>>> On 6/6/22 14:27, Patrick Palka wrote:
>>>>> On Thu, 7 Oct 2021, Jason Merrill wrote:
>>>>>
>>>>>> 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.
>>>>>
>>>>> Thanks.  I ended up neglecting to commit this patch for GCC 12, and
>>>>> turns out it also fixes the recently reported regression PR105848
>>>>> (which is essentially another manifestation of PR53164 exposed by the
>>>>> non-dependent overload set pruning patch r12-6075), so I'm going to
>>>>> commit this now.  I suppose it's also OK to backport to 12?
>>>>
>>>> What if the use is not as a call, but say assigning the address to a
>>>> global
>>>> pointer?
>>>>
>>>> I wonder about calling mark_used when substituting the
>>>> TEMPLATE_PARM_INDEX,
>>>> probably with tf_none or tf_error to avoid redundant deprecated warnings.
>>>
>>> Ah, that seems to work very nicely -- it even handles the case where there
>>> the
>>> only use is as a template argument and there is no "use" inside the body
>>> of the function, because we always have to substitute the
>>> TEMPLATE_PARM_INDEX
>>> in the generic template arguments.
>>>
>>> Like so?  Bootstrapped and tested on x86_64-pc-linux-gnu.  I'm not sure
>>> if it's worth also checking !processing_template_decl && !DECL_ODR_USED
>>> before calling mark_used here, since otherwise the call ought to be
>>> certainly redundant.
>>
>> Wouldn't hurt to benchmark that, but I wouldn't expect it to make a measurable
>> difference.
> 
> I suspect the same, but will benchmark to make sure.
> 
>>
>>> -- >8 --
>>>
>>> Subject: [PATCH] c++: improve "NTTP argument considered unused" fix
>>> [PR53164]
>>>
>>> 	PR c++/53164
>>> 	PR c++/105848
>>>
>>> gcc/cp/ChangeLog:
>>>
>>> 	* pt.cc (tsubst) <case TEMPLATE_PARM_INDEX>: Call mark_used on
>>> 	an ADDR_EXPR argument.
>>> 	(tsubst_copy_and_build) <case CALL_EXPR>: Revert r13-995 change.
>>>
>>> gcc/testsuite/ChangeLog:
>>>
>>> 	* g++.dg/template/fn-ptr3a.C: New test.
>>>
>>> Co-authored-by: Jason Merrill <jason@redhat.com>
>>> ---
>>>    gcc/cp/pt.cc                             | 40 +++++++++++++-----------
>>>    gcc/testsuite/g++.dg/template/fn-ptr3a.C | 25 +++++++++++++++
>>>    2 files changed, 46 insertions(+), 19 deletions(-)
>>>    create mode 100644 gcc/testsuite/g++.dg/template/fn-ptr3a.C
>>>
>>> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
>>> index dcacba56a1c..5863d83b4fd 100644
>>> --- a/gcc/cp/pt.cc
>>> +++ b/gcc/cp/pt.cc
>>> @@ -15858,9 +15858,23 @@ tsubst (tree t, tree args, tsubst_flags_t complain,
>>> tree in_decl)
>>>    	      }
>>>    	    else if (code == TEMPLATE_TEMPLATE_PARM)
>>>    	      return arg;
>>> -	    else
>>> -	      /* TEMPLATE_PARM_INDEX.  */
>>> -	      return convert_from_reference (unshare_expr (arg));
>>> +	    else /* if (code == TEMPLATE_PARM_INDEX)  */
>>> +	      {
>>> +		if (TREE_CODE (arg) == ADDR_EXPR
>>> +		    && DECL_P (TREE_OPERAND (arg, 0)))
>>
>> If the parameter is a reference to function, rather than a pointer, do we need
>> to look through a NOP_EXPR?
> 
> Ah yeah, NOP_EXPR as well as REFERENCE_REF_P it seems.  (And I guess in
> light of C++20 class NTTPs we might need to walk the entire argument in
> search of decls to call mark_used on, but that seems overkill, Clang
> doesn't seem to handle that either.)
> 
> I'm testing the following, which additionally handles/tests the
> reference-to-function case:

OK.

> -- >8 --
> 
> Subject: [PATCH] c++: improve "NTTP argument considered unused" fix [PR53164,
>   PR105848]
> 
> 	PR c++/53164
> 	PR c++/105848
> 
> gcc/cp/ChangeLog:
> 
> 	* pt.cc (tsubst) <case TEMPLATE_PARM_INDEX>: Call mark_used on
> 	an ADDR_EXPR argument.
> 	(tsubst_copy_and_build) <case CALL_EXPR>: Revert r13-995 change.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/template/fn-ptr3a.C: New test.
> 
> Co-authored-by: Jason Merrill <jason@redhat.com>
> ---
>   gcc/cp/pt.cc                             | 43 +++++++++++++-----------
>   gcc/testsuite/g++.dg/template/fn-ptr3a.C | 25 ++++++++++++++
>   2 files changed, 49 insertions(+), 19 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/template/fn-ptr3a.C
> 
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index dcacba56a1c..ac9b5a5bb04 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -15858,9 +15858,26 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
>   	      }
>   	    else if (code == TEMPLATE_TEMPLATE_PARM)
>   	      return arg;
> -	    else
> -	      /* TEMPLATE_PARM_INDEX.  */
> -	      return convert_from_reference (unshare_expr (arg));
> +	    else /* if (code == TEMPLATE_PARM_INDEX)  */
> +	      {
> +		tree sub = arg;
> +		while (CONVERT_EXPR_P (sub) || REFERENCE_REF_P (sub))
> +		  sub = TREE_OPERAND (sub, 0);
> +		if (TREE_CODE (sub) == ADDR_EXPR
> +		    && DECL_P (TREE_OPERAND (sub, 0)))
> +		  /* Remember that there was a reference to this entity.
> +		     We should already have called mark_used when taking
> +		     the address of this entity, but do so again to make
> +		     sure: at worst it's redundant, but if we so far only
> +		     called mark_used in a template context then we might
> +		     not have yet marked it odr-used (53164).  */
> +		  /* Mask out tf_warning_or_error so that we don't issue
> +		     redundant diagnostics -- we just want to make sure
> +		     this entity is odr-used.  */
> +		  mark_used (TREE_OPERAND (sub, 0),
> +			     complain & ~tf_warning_or_error);
> +		return convert_from_reference (unshare_expr (arg));
> +	      }
>   	  }
>   
>   	if (level == 1)
> @@ -20884,22 +20901,10 @@ tsubst_copy_and_build (tree t,
>   	  }
>   
>   	/* Remember that there was a reference to this entity.  */
> -	if (function != NULL_TREE)
> -	  {
> -	    tree inner = function;
> -	    if (TREE_CODE (inner) == ADDR_EXPR
> -		&& TREE_CODE (TREE_OPERAND (inner, 0)) == FUNCTION_DECL)
> -	      /* We should already have called mark_used when taking the
> -		 address of this function, but do so again anyway to make
> -		 sure it's odr-used: at worst this is a no-op, but if we
> -		 obtained this FUNCTION_DECL as part of ahead-of-time overload
> -		 resolution then that call to mark_used wouldn't have marked it
> -		 odr-used yet (53164).  */
> -	      inner = TREE_OPERAND (inner, 0);
> -	    if (DECL_P (inner)
> -		&& !mark_used (inner, complain) && !(complain & tf_error))
> -	      RETURN (error_mark_node);
> -	  }
> +	if (function != NULL_TREE
> +	    && DECL_P (function)
> +	    && !mark_used (function, 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-ptr3a.C b/gcc/testsuite/g++.dg/template/fn-ptr3a.C
> new file mode 100644
> index 00000000000..7456be5d51f
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/template/fn-ptr3a.C
> @@ -0,0 +1,25 @@
> +// PR c++/53164
> +// PR c++/105848
> +// A stricter version of fn-ptr3.C that verifies using f as a template
> +// argument alone constitutes an odr-use.
> +
> +template<class T>
> +void f(T) { T::fail; } // { dg-error "fail" }
> +
> +template<void (*P)(int)>
> +struct A {
> +  static void wrap();
> +};
> +
> +template<void (&P)(char)>
> +void wrap();
> +
> +template<int>
> +void g() {
> +  A<f>::wrap(); // { dg-message "required from here" }
> +  wrap<f>(); // { dg-message "required from here" }
> +}
> +
> +int main() {
> +  g<0>();
> +}


      reply	other threads:[~2022-06-07 20:09 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-06-06 18:27 Patrick Palka
2022-06-06 19:26 ` Jason Merrill
2022-06-07 13:24   ` Patrick Palka
2022-06-07 18:05     ` Jason Merrill
2022-06-07 19:18       ` Patrick Palka
2022-06-07 20:09         ` Jason Merrill [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=ac511523-c36d-4fa9-4ce6-2c0bc81c0cbd@redhat.com \
    --to=jason@redhat.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=ppalka@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).