bloomberg / clang-p2996

Experimental clang support for WG21 P2996 (Reflection).
https://github.com/bloomberg/clang-p2996/tree/p2996/P2996.md
51 stars 8 forks source link

return_type_of not a constant expression #66

Closed nilres closed 2 months ago

nilres commented 2 months ago

Describe the bug std::meta::return_type_of seems to never be a constant expression

To Reproduce Steps to reproduce the behavior:

https://godbolt.org/z/h95McPeh4

class simple_test_class {
public:
    int a;

    void f() {

    }
};

int main() {
    [:expand(std::meta::members_of(^simple_test_class)):] >> [&]<auto e> {
        if(std::meta::is_function(e)) {
            auto typeName = std::meta::return_type_of(e);
        }
    };

    return 0;
}

Results in:

<source>:34:5: error: call to immediate function '__impl::replicator_type<(reflection), (reflection), (reflection), (reflection), (reflection), (reflection), (reflection), (reflection)>::operator>><(lambda at <source>:34:62)>' is not a constant expression
   34 |     [:expand(std::meta::members_of(^simple_test_class)):] >> [&]<auto e> {
      |     ^
/opt/compiler-explorer/clang-bb-p2996-trunk-20240625/bin/../include/c++/v1/experimental/meta:1930:10: note: subexpression not valid in a constant expression
 1930 |   return __metafunction(detail::__metafn_return_type_of, r);
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:36:29: note: in call to 'return_type_of(^(declaration))'
   36 |             auto typeName = std::meta::return_type_of(e);
      |                             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:9:6: note: in call to 'body.operator()<(reflection)>()'
    9 |     (body.template operator()<vals>(), ...);
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:34:5: note: in call to '[: replicator :].operator>><(lambda at <source>:34:62)>({})'
   34 |     [:expand(std::meta::members_of(^simple_test_class)):] >> [&]<auto e> {
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   35 |         if(std::meta::is_function(e)) {
      |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   36 |             auto typeName = std::meta::return_type_of(e);
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   37 |         }
      |         ~
   38 |     };
      |     ~
1 error generated.
Compiler returned: 1

Expected behavior

Compiles without error messages.

Environment (please complete the following information):

Additional context -fparameter-reflection needs to be set

katzdm commented 2 months ago

Hey @nilres , thanks for the issue! There are two issues with the linked code:

  1. The lambda in your main() is not consteval, so auto typeName is a runtime variable. It is ill-formed to declare a runtime variable having a consteval-only type (the canonical example of which is std::meta::info). You can fix this by either declaring the lambda consteval, or by both declaring typeName as constexpr and changing the if-statement guarding its declaration into an if constexpr.
  2. I don't think it's specified yet in P3096, but return_type_of fails to be a constant expression if the provided reflection is of a constructor or destructor. I'd recommend adding checks for these to the if-statement guarding the declaration of typeName.

https://godbolt.org/z/r5P46Yzsj or https://godbolt.org/z/816vKr1Tb

Hope this helps!