Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

issue compiling code with large constexpr arrays of function pointers #71888

Open
wheatman opened this issue Nov 10, 2023 · 4 comments
Open

issue compiling code with large constexpr arrays of function pointers #71888

wheatman opened this issue Nov 10, 2023 · 4 comments
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" rejects-valid

Comments

@wheatman
Copy link
Contributor

wheatman commented Nov 10, 2023

I am trying to make some large constexpr arrays of functions pointers, but when they get to a certain size they just seem to break and starts giving error messages about parts of the code which doesn't change with the size.

The code can be found at

working with a size of 1<<15
https://godbolt.org/z/15badTccs

broken with a size of 1<<16
https://godbolt.org/z/KMPGYbKcx

the timeouts from g++ are just from godbolt, when I compile the same code on my own machine it does finish without errors with g++

The code has been simplified down to

#include <array>
#include <type_traits>



  template <int enabled_blocks>
  static void foo() {
    return;
  }


  using fn_type = void();

  template <std::size_t... I>
  constexpr auto static make_helper(std::index_sequence<I...>) {
    return std::array<fn_type *, sizeof...(I)>{foo<I>...};
  }
  template <std::size_t MAX> static constexpr auto get_foos() {
    return make_helper(std::make_index_sequence<MAX>{});
  }

  static constexpr int num = 1UL << 15;  // it no longer compiles if this is changed to 16

  static constexpr std::array<fn_type *, num> foos =
      get_foos<num>();




int main(int argc, char *argv[]) {

  foos[argc]();
  return 0;
}

The error with the code that has 16 instead of 15 is

<source>:17:48: error: initializer for aggregate with no elements requires explicit braces
   17 |     return std::array<fn_type *, sizeof...(I)>{foo<I>...};
      |                                                ^
<source>:20:12: note: in instantiation of function template specialization 'make_helper<0UL, 1UL, 2UL, 3UL, 4UL, 
...
...
65530UL, 65531UL, 65532UL, 65533UL, 65534UL, 65535UL>' requested here
   20 |     return make_helper(std::make_index_sequence<MAX>{});
      |            ^
<source>:26:7: note: in instantiation of function template specialization 'get_foos<65536UL>' requested here
   26 |       get_foos<num>();
      |       ^
1 error generated.
Compiler returned: 1

I first guessed the issue had to do with one of the limits here https://clang.llvm.org/docs/UsersManual.html#controlling-implementation-limits

However, all but constexpr-steps seem to small to be related and I tried increasing it with -fconstexpr-steps=134217728 and it had no effect

@EugeneZelenko EugeneZelenko added the clang:frontend Language frontend issues, e.g. anything involving "Sema" label Nov 10, 2023
@llvmbot
Copy link
Collaborator

llvmbot commented Nov 10, 2023

@llvm/issue-subscribers-clang-frontend

Author: None (wheatman)

I am trying to make some large constexpr arrays of functions pointers, but when they get to a certain size they just seem to break and starts giving error messages about parts of the code which doesn't change with the size.

The code can be found at

working with a size of 1&lt;&lt;15
https://godbolt.org/z/15badTccs

broken with a size of 1&lt;&lt;16
https://godbolt.org/z/KMPGYbKcx

the timeouts from g++ are just from godbolt, when I compile the same code on my own machine it does finish without errors with g++

The code has been simplified down to


#include &lt;array&gt;
#include &lt;type_traits&gt;



  template &lt;int enabled_blocks&gt;
  static void foo() {
    return;
  }


  using fn_type = void();

  template &lt;std::size_t... I&gt;
  constexpr auto static make_helper(std::index_sequence&lt;I...&gt;) {
    return std::array&lt;fn_type *, sizeof...(I)&gt;{foo&lt;I&gt;...};
  }
  template &lt;std::size_t MAX&gt; static constexpr auto get_foos() {
    return make_helper(std::make_index_sequence&lt;MAX&gt;{});
  }

  static constexpr int num = 1UL &lt;&lt; 15;  // it no longer compiles if this is changed to 16

  static constexpr std::array&lt;fn_type *, num&gt; foos =
      get_foos&lt;num&gt;();




int main(int argc, char *argv[]) {

  foos[argc]();
  return 0;
}

The error with the code that has 16 instead of 15 is

&lt;source&gt;:17:48: error: initializer for aggregate with no elements requires explicit braces
   17 |     return std::array&lt;fn_type *, sizeof...(I)&gt;{foo&lt;I&gt;...};
      |                                                ^
&lt;source&gt;:20:12: note: in instantiation of function template specialization 'make_helper&lt;0UL, 1UL, 2UL, 3UL, 4UL, 
...
...
65530UL, 65531UL, 65532UL, 65533UL, 65534UL, 65535UL&gt;' requested here
   20 |     return make_helper(std::make_index_sequence&lt;MAX&gt;{});
      |            ^
&lt;source&gt;:26:7: note: in instantiation of function template specialization 'get_foos&lt;65536UL&gt;' requested here
   26 |       get_foos&lt;num&gt;();
      |       ^
1 error generated.
Compiler returned: 1

I first guessed the issue had to do with one of the limits here https://clang.llvm.org/docs/UsersManual.html#controlling-implementation-limits

However, all but constexpr-steps seem to small to be related and I tried increasing it with -fconstexpr-steps=134217728 and it had no effect

@tbaederr tbaederr changed the title issue compiling codes with large constexpr arrays of function pointers issue compiling code with large constexpr arrays of function pointers Nov 10, 2023
@tbaederr
Copy link
Contributor

Tracked this down to SubstNonTypeTemplateParmPackExpr simply just having 16 bits for the number of arguments:

unsigned NumArguments : 16;

Which we never check for before creating the expression.

@wheatman
Copy link
Contributor Author

It looks like the 32 bit to 16 bit conversion happens here

NumArguments(ArgPack.pack_size()), Index(Index), NameLoc(NameLoc) {

I feel like there should at least be some sort of error raised here instead of just silently cutting off the high bits.
Also, I can't find anything in the standard about the max size of a pack, seems to just say zero or more, so it would be nice if instead NumArguments could be made 32 bits

@wheatman
Copy link
Contributor Author

wheatman commented Dec 3, 2023

I added a patch to add the assert when the conversion happens as a temporary fix, this may also lead to some discovery if this case is common enough that large packs should be supported, I imagine they may be some time and space overhead of supporting larger packs

#74220

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" rejects-valid
Projects
None yet
Development

No branches or pull requests

4 participants