Bug 83258 - Rejecting function pointer non-type template parameter without linkage
Summary: Rejecting function pointer non-type template parameter without linkage
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 8.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: rejects-valid
: 84981 85589 92320 (view as bug list)
Depends on:
Blocks:
 
Reported: 2017-12-02 22:22 UTC by Barry Revzin
Modified: 2020-03-17 18:17 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2017-12-04 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Barry Revzin 2017-12-02 22:22:47 UTC
Example from StackOverflow (https://stackoverflow.com/q/47606810/2069064):

template<void(*)()> struct A{};

int main()
{
    constexpr auto fp = +[]{};
    A<fp>{};
}

As of N4268, this should be accepted (linkage is no longer a requirement), but gcc rejects with:

prog.cc: In function 'int main()':
prog.cc:6:9: error: 'main()::<lambda()>::_FUN' is not a valid template argument for type 'void (*)()' because 'static constexpr void main()::<lambda()>::_FUN()' has no linkage
     A<fp>{};
         ^
Comment 1 Jonathan Wakely 2018-03-20 12:22:44 UTC
*** Bug 84981 has been marked as a duplicate of this bug. ***
Comment 2 Jonathan Wakely 2018-03-20 14:54:40 UTC
With this patch:

--- a/gcc/cp/pt.c                                                                                                                                                                                                                                                                                                            
+++ b/gcc/cp/pt.c                                                                                                                                                                                                                                                                                                            
@@ -6259,7 +6259,8 @@ convert_nontype_argument_function (tree type, tree expr,                                                                                                                                                                                                                                               
     }                                                                                                                                                                                                                                                                                                                       
                                                                                                                                                                                                                                                                                                                             
   linkage = decl_linkage (fn_no_ptr);                                                                                                                                                                                                                                                                                       
-  if (cxx_dialect >= cxx11 ? linkage == lk_none : linkage != lk_external)                                                                                                                                                                                                                                                   
+  if ((cxx_dialect < cxx11 && linkage != lk_external)
+      || (cxx_dialect < cxx17 && linkage == lk_none))
     {
       if (complain & tf_error)
        {

We accept Barry's testcase in C++17 mode.

I think we also need this for some non-type arguments without linkage:


@@ -6979,7 +6980,8 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
 
          /* DR 1155 allows internal linkage in C++11 and up.  */
          linkage_kind linkage = decl_linkage (expr);
-         if (linkage < (cxx_dialect >= cxx11 ? lk_internal : lk_external))
+         if ((cxx_dialect < cxx11 && linkage < lk_external)
+             || (cxx_dialect < cxx17 && linkage < lk_internal))
            {
              if (complain & tf_error)
                error ("%qE is not a valid template argument for type %qT "


but that second change causes a new ice-on-invalid for this in C++17 mode (but seems to correctly compile it when VALID is defined):


template <typename T, const T &val> struct TestClass
{
  TestClass() : _val(val) { }
  T _val;
};

extern constexpr float e = 2.72;    // external linkage
static constexpr float pi = 3.14;   // internal linkage

int main()
{
#ifdef VALID
  static
#endif
  constexpr float one = 1; // no linkage

  TestClass<float, e> test1;

  TestClass<float, pi> test2;

  TestClass<float, one> test3;
}


linkage.cc: In constructor 'TestClass<T, val>::TestClass() [with T = float; const T& val = one]':
linkage.cc:3:3: error: Local declaration from a different function
   TestClass() : _val(val) { }
   ^~~~~~~~~
one
linkage.cc:3:25: note: in statement
   TestClass() : _val(val) { }
                         ^
one.2_1 = one;
during GIMPLE pass: cfg
linkage.cc:3:3: internal compiler error: verify_gimple failed
   TestClass() : _val(val) { }
   ^~~~~~~~~
0xdfad0d verify_gimple_in_cfg(function*, bool)
        /home/jwakely/src/gcc/gcc/gcc/tree-cfg.c:5579
0xcc6956 execute_function_todo
        /home/jwakely/src/gcc/gcc/gcc/passes.c:1994
0xcc79d2 execute_todo
        /home/jwakely/src/gcc/gcc/gcc/passes.c:2048
Please submit a full bug report,
with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
See <https://gcc.gnu.org/bugs/> for instructions.
Comment 3 Jonathan Wakely 2018-05-01 17:14:58 UTC
*** Bug 85589 has been marked as a duplicate of this bug. ***
Comment 4 Jonathan Wakely 2018-05-01 17:15:43 UTC
Testcase from Bug 85589:

template<auto& v> struct foo {};

    int main() {
        static auto v = "str";
        (void) foo<v> {};
    }
Comment 5 S. Davis Herring 2019-11-18 23:58:27 UTC
As an anti-example, making the client a template works:

template<void(*)()> struct A{};

template<int=0>
void f()
{
    constexpr auto fp = +[]{};
    A<fp>{};
}

int main()
{
    f();
}
Comment 6 Eric Gallager 2019-11-19 23:46:16 UTC
*** Bug 92320 has been marked as a duplicate of this bug. ***
Comment 7 S. Davis Herring 2020-03-17 18:17:48 UTC
My example in Comment #5 works in 9.2 but not in (Compiler Explorer's) trunk.