add static_check_equal for easier to read compiler errors #19531

pull JeremyRubin wants to merge 1 commits into bitcoin:master from JeremyRubin:static_check changing 2 files +24 −1
  1. JeremyRubin commented at 9:17 PM on July 15, 2020: contributor

    I find myself reaching for this function all the time and re-implementing it. Maybe it makes sense to add to util/check.h and eventually replace uses of static_assert with this to save contributor time when diagnosing failing static_asserts.

    The benefit of

    static_check_equal(1, 2)
    

    is that it prints 1 and 2 in the compiler error.

    ./util/check.h: In instantiation of ‘static_check_equal_struct<T1, T2, value_1, value_2>::static_check_equal_struct() [with T1 = int; T2 = int; T1 value_1 = 1; T2 value_2 = 2]’:
    txmempool.cpp:29:5:   required from here
    ./util/check.h:63:31: error: static assertion failed: Equality check failed, value_1 != value_2.
       63 |         static_assert(value_1 == value_2, "Equality check failed, value_1 != value_2.");
    

    Compare to:

    static_assert(sizeof(int) == sizeof(size_t))
    

    which just gives

    txmempool.cpp:29:31: error: static assertion failed
       29 |     static_assert(sizeof(int) == sizeof(size_t));
    

    is that you don't actually get to see what size T and T2 actually are, which can make it annoying to debug what went wrong, so then you end up guessing and recompiling or having to run the code to print the size out.

  2. JeremyRubin renamed this:
    add static_check_equal
    add static_check_equal for easier to read compiler errors
    on Jul 15, 2020
  3. practicalswift commented at 9:29 PM on July 15, 2020: contributor

    Concept ACK

    Could introduce an usage of static_check_equal(…, …) too to make it technically in use? :)

  4. JeremyRubin commented at 10:24 PM on July 15, 2020: contributor

    Good point -- maybe we want to permit passing in an optional string so it matches existing static assert API?

  5. DrahtBot added the label Utils/log/libs on Jul 15, 2020
  6. in src/util/check.h:69 in 92fe0ba580 outdated
      64 | +    }
      65 | +};
      66 | +
      67 | +/** Check if the template arguments are equal at compile time. Compiler error prints values if
      68 | + * failure. **/
      69 | +#define static_check_equal(s1,s2) static_check_equal_struct<decltype(s1),decltype(s2),s1,s2>()
    


    jonatack commented at 5:18 AM on July 16, 2020:

    clang-format suggestion

    #define static_check_equal(s1, s2) static_check_equal_struct<decltype(s1), decltype(s2), s1, s2>()
    
  7. jonatack commented at 5:22 AM on July 16, 2020: contributor

    Tested Concept ACK.

    Perhaps place it somewhere that is always included to avoid the need to add #include <util/check.h> in the file where you want to use it.

  8. theStack commented at 8:17 PM on July 26, 2020: contributor

    Concept ACK

  9. laanwj commented at 12:39 PM on August 6, 2020: member

    Concept ACK (but it'd be nice to have one example use at least in the PR?)

    Perhaps place it somewhere that is always included to avoid the need to add #include <util/check.h> in the file where you want to use it.

    Dunno. Generally I like having independent things in different files and being explicit about it, instead of having "hotspots". But then I don't know how often this is going to be used.

  10. JeremyRubin force-pushed on Aug 6, 2020
  11. JeremyRubin force-pushed on Aug 6, 2020
  12. JeremyRubin commented at 6:17 PM on August 6, 2020: contributor

    I'd been kinda stuck figuring out how to pass the message to the static_assert because the message param has to be a literal string and string literals are forbidden for templates until later c++. But I realized it's not a problem to just ignore the message string as long as we have it in the source, it will be visible in the callsite error. And then I got stuck figuring out how to make it support common binary predicates without too much repetition when std::less and co aren't constexpr till after c++14. But I realized I can just pass the operator directly in the macro.

    Thus the updates, which have support for ==, !=, >, <, >=, <= and message or no message.

    I also added an example of where this is handy -- reviewers may wish to test by compiling this branch and tweaking the arguments +/- 1 to see that it fails, and removing the message.

  13. add static_check_equal 8047fed26d
  14. JeremyRubin force-pushed on Aug 6, 2020
  15. JeremyRubin closed this on Aug 7, 2020

  16. JeremyRubin reopened this on Aug 7, 2020

  17. DrahtBot commented at 6:28 AM on October 13, 2020: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    <!--174a7506f384e20aa4161008e828411d-->

    Conflicts

    No conflicts as of last run.

  18. maflcko commented at 11:36 AM on October 13, 2020: member

    review ACK 8047fed26dd5077dacd490b35e481c77cb00722a

  19. theStack approved
  20. theStack commented at 1:08 AM on December 20, 2021: contributor

    Tested ACK 8047fed26dd5077dacd490b35e481c77cb00722a

    Took me quite a bit to figure out how these preprocessor macros are constructed in a way to magically work both with and without message passed. Nice! Tested by modifying the introduced example in random.cpp to fail with various operators and removing the message (third parameter), works as expected.

  21. JeremyRubin commented at 3:22 AM on December 20, 2021: contributor

    i guess this is mergeable then? hooray for compile time errors :)

  22. ajtowns commented at 8:16 AM on August 29, 2022: contributor

    Approach ACK.

    You could simplify this a bit:

    template <auto value_1, auto value_2, bool b>     // C++17 lets the type params be implicit
    struct static_check_struct {
        static_assert(b);   // don't need to put static_assert in a function, don't need a dummy message
    };
    
    #define static_check(f, s1, s2, ...) static_check_struct<s1, s2, s1 f s2>()
    #define static_check_macro(...) static_check(__VA_ARGS__, "") // accept 0 or more comments instead of 0 or 1
    
    #define static_check_equal(...) static_check_macro(==, __VA_ARGS__)
    

    With those changes, clang's errors look like:

    In file included from random.cpp:22:
    ./util/check.h:100:5: error: static_assert failed
        static_assert(b);
        ^             ~
    random.cpp:413:9: note: in instantiation of template class 'static_check_struct<64UL, 65UL, false>' requested here
            static_check_equal(sizeof(buf), 1+CSHA512::OUTPUT_SIZE, "Buffer needs to have hasher's output size");
            ^
    

    (plus the "expanded from macro" notes)

  23. JeremyRubin commented at 4:45 PM on August 29, 2022: contributor

    Feel free to pick this branch and do the simplifications if you'd like, It's not really clear that even with those changes anything would lead to merge so I'm unlikely to spend time on it.

  24. maflcko commented at 8:45 AM on August 30, 2022: member

    Hmm, I was testing this and it looks like it doesn't work outside a function or class scope.

    I get:

    error: expected unqualified-id
    static_check_equal(1, 1);
    ^
    
  25. maflcko commented at 8:52 AM on August 30, 2022: member

    A hacky workaround for that might be to have a static constexpr bool TRUE{true}; dummy member in the struct and then wrap everything into another layer of static_assert (to ensure a two-way drop in replacement for static_assert in all scopes).

    #define static_check(f, s1, s2, ...) static_assert(static_check_struct<s1, s2, s1 f s2>{}.TRUE)
    
  26. ajtowns commented at 9:49 AM on August 30, 2022: contributor

    A hacky workaround for that might be to have a static constexpr bool TRUE{true}; dummy member in the struct and then wrap everything into another layer of static_assert (to ensure a two-way drop in replacement for static_assert in all scopes).

    template <auto value_1, auto value_2, bool b>
    struct static_check_struct {
        static constexpr bool value = b;
    }; 
    #define static_check_macro_msg(f, s1, s2, msg) static_assert(static_check_struct<s1, s2, s1 f s2>::value)
    

    seems to work fine:

    random.cpp:409:5: error: static_assert failed due to requirement 'static_check_struct<7, 8, false>::value'
        static_check_equal(7, 8, "whatwhat");
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    random.cpp:415:9: error: static_assert failed due to requirement 'static_check_struct<64UL, 65UL, false>::value'
            static_check_equal(sizeof(buf), 1+CSHA512::OUTPUT_SIZE, "Buffer needs to have hasher's output size");
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    

    You could pass the msg argument into static_assert that way too, if desired.

  27. achow101 commented at 6:12 PM on October 12, 2022: member

    Are you still working on this?

  28. maflcko commented at 7:00 AM on October 17, 2022: member

    Closing for now. This can be reopened or a new pull can be opened

  29. maflcko closed this on Oct 17, 2022

  30. bitcoin locked this on Oct 17, 2023

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-04-13 15:14 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me