Bug 97700 - Bogus error when a class containing a function pointer is used as a non-type template parameter
Summary: Bogus error when a class containing a function pointer is used as a non-type ...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 11.0
: P3 normal
Target Milestone: 13.2
Assignee: Patrick Palka
URL:
Keywords: rejects-valid
: 109168 (view as bug list)
Depends on:
Blocks: 103807
  Show dependency treegraph
 
Reported: 2020-11-03 14:14 UTC by ensadc
Modified: 2023-05-12 15:25 UTC (History)
8 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2021-12-03 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description ensadc 2020-11-03 14:14:56 UTC
Originally discovered by cigien on StackOverflow. See https://stackoverflow.com/questions/64655958/can-a-class-containing-a-function-pointer-be-used-as-a-non-type-template-parameter

GCC does not like this program:

````

struct S 
{ 
    void (*f)(); 
}; 

constexpr S s {[]{}};

template<S> struct X {};
using x = X<s>;

````

It complains with:

````
error: '<lambda()>::_FUN' is not a valid template argument of type 'void (*)()' because '<lambda()>::_FUN' is not a variable
using x = X<s>;
             ^
````

As mentioned in the StackOverflow post, it appears that `invalid_tparm_referent_p` (called by `get_template_parm_object`) fails to account for the pointer-to-function case.
Comment 1 ensadc 2020-11-03 14:21:08 UTC
The lambda is not needed to reproduce the bug. This also triggers the error:

void fun() {}
struct S 
{ 
    void (*f)(); 
}; 

template<S> struct X {};
using x = X<S{ fun }>;
Comment 2 Marek Polacek 2020-11-19 18:54:39 UTC
Confirmed.
Comment 3 Johel Ernesto Guerrero Peña 2021-03-13 21:42:16 UTC
This seems to be a duplicate of Bug 83258.
Comment 4 Andrew Pinski 2023-03-17 17:57:11 UTC
*** Bug 109168 has been marked as a duplicate of this bug. ***
Comment 5 Lukas Böger 2023-05-09 21:23:14 UTC
One part of this seems to be resolved with version 13. Below, only the lambda use case fails to compile, whereas prior to version 13, both type aliases are rejected:

```
void fun() {}
struct S 
{ 
    void (*f)(); 
}; 

template<S> struct X {};

using works = X<S{ fun }>;
using does_not_work = X<S{ []{}}>;
```

See https://godbolt.org/z/3E7WE6zKo
Comment 6 Patrick Palka 2023-05-10 13:13:29 UTC
Partially fixed by r13-6970-gb5e38b1c166357
Comment 7 GCC Commits 2023-05-11 14:05:05 UTC
The master branch has been updated by Patrick Palka <ppalka@gcc.gnu.org>:

https://gcc.gnu.org/g:c3afdb8ba8f1839544c414f57e41a58c8fda5349

commit r14-708-gc3afdb8ba8f1839544c414f57e41a58c8fda5349
Author: Patrick Palka <ppalka@redhat.com>
Date:   Thu May 11 10:04:25 2023 -0400

    c++: converted lambda as template argument [PR83258, ...]
    
    r8-1253-g3d2e25a240c711 removed the template argument linkage requirement
    in convert_nontype_argument for C++17 (which r9-3836-g4be5c72cf3ea3e later
    factored out into invalid_tparm_referent_p), but we need to also remove
    the one in convert_nontype_argument_function for benefit of the first and
    third testcase which we currently reject even in C++17/20 mode.
    
    And in invalid_tparm_referent_p we're inadvertendly returning false for
    the address of a lambda's static op() since it's DECL_ARTIFICIAL, which
    currently causes us to reject the second (C++20) testcase.  But this
    DECL_ARTIFICIAL check seems to be relevant only for VAR_DECL, and in fact
    this code path was originally reachable only for VAR_DECL until recently
    (r13-6970-gb5e38b1c166357).  So this patch restricts the check to VAR_DECL.
    
    Co-authored-by: Jonathan Wakely <jwakely@redhat.com>
    
            PR c++/83258
            PR c++/80488
            PR c++/97700
    
    gcc/cp/ChangeLog:
    
            * pt.cc (convert_nontype_argument_function): Remove linkage
            requirement for C++17 and later.
            (invalid_tparm_referent_p) <case ADDR_EXPR>: Restrict
            DECL_ARTIFICIAL rejection test to VAR_DECL.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/ext/visibility/anon8.C: Don't expect a "no linkage"
            error for the template argument &B2:fn in C++17 mode.
            * g++.dg/cpp0x/lambda/lambda-conv15.C: New test.
            * g++.dg/cpp2a/nontype-class56.C: New test.
            * g++.dg/template/function2.C: New test.
Comment 8 Patrick Palka 2023-05-11 14:25:41 UTC
Fixed on trunk so far.
Comment 9 GCC Commits 2023-05-12 15:08:03 UTC
The releases/gcc-13 branch has been updated by Patrick Palka <ppalka@gcc.gnu.org>:

https://gcc.gnu.org/g:42f9b481be3527b336b800128247d053fd18d121

commit r13-7324-g42f9b481be3527b336b800128247d053fd18d121
Author: Patrick Palka <ppalka@redhat.com>
Date:   Thu May 11 10:04:25 2023 -0400

    c++: converted lambda as template argument [PR83258, ...]
    
    r8-1253-g3d2e25a240c711 removed the template argument linkage requirement
    in convert_nontype_argument for C++17 (which r9-3836-g4be5c72cf3ea3e later
    factored out into invalid_tparm_referent_p), but we need to also remove
    the one in convert_nontype_argument_function for benefit of the first and
    third testcase which we currently reject even in C++17/20 mode.
    
    And in invalid_tparm_referent_p we're inadvertendly returning false for
    the address of a lambda's static op() since it's DECL_ARTIFICIAL, which
    currently causes us to reject the second (C++20) testcase.  But this
    DECL_ARTIFICIAL check seems to be relevant only for VAR_DECL, and in fact
    this code path was originally reachable only for VAR_DECL until recently
    (r13-6970-gb5e38b1c166357).  So this patch restricts the check to VAR_DECL.
    
    Co-authored-by: Jonathan Wakely <jwakely@redhat.com>
    
            PR c++/83258
            PR c++/80488
            PR c++/97700
    
    gcc/cp/ChangeLog:
    
            * pt.cc (convert_nontype_argument_function): Remove linkage
            requirement for C++17 and later.
            (invalid_tparm_referent_p) <case ADDR_EXPR>: Restrict
            DECL_ARTIFICIAL rejection test to VAR_DECL.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/ext/visibility/anon8.C: Don't expect a "no linkage"
            error for the template argument &B2:fn in C++17 mode.
            * g++.dg/cpp0x/lambda/lambda-conv15.C: New test.
            * g++.dg/cpp2a/nontype-class56.C: New test.
            * g++.dg/template/function2.C: New test.
    
    (cherry picked from commit c3afdb8ba8f1839544c414f57e41a58c8fda5349)
Comment 10 Patrick Palka 2023-05-12 15:25:28 UTC
Should be fully fixed for GCC 13.2