saarraz / clang-concepts-monorepo

****** OBSOLETE - CONCEPTS HAS BEEN MERGED INTO CLANG TRUNK AND DEVELOPMENT CONTINUES THERE ****** This fork of llvm-project contains my implementation of C++2a Concepts for the Clang compiler, and will be updated regularly with bug fixes until the whole feature is merged to trunk. Follow the instructions here https://clang.llvm.org/get_started.html to build, then use the flags "-std=c++2a -Xclang -fconcepts-ts" to enable concepts.
27 stars 3 forks source link

[FEATURE] Attribute for detailed diagnostics #45

Open cjdb opened 4 years ago

cjdb commented 4 years ago

Motivation

Consider

template<class F, class... Args>
concept invocable = requires(F&& f, Args&&... args) {
  invoke(std::forward<F>(f), std::forward<Args>(args)...);
};

If a type does not satisfy the above requirement, then a diagnostic like this is presented..

../../../test/unit/range/access/size.cpp:43:2: note: because 'cjdb::invocable<cjdb::ranges::detail_size::size_fn, std::array<int, 100> &>' evaluated to false
../../../test/include/cjdb/test/range/access.hpp:90:21: note: expanded from macro 'DEFINE_CHECK_FOR_MEMBER_ACCESS'
static_assert(cjdb::invocable<cjdb::ranges::CJDB_TEST_CONCAT(detail_, base_cpo)::CJDB_TEST_CONCAT(base_cpo, _fn), std::array<int, 100>&>);                           \
                    ^
../../../include/cjdb/concepts/callable/invocable.hpp:19:3: note: because 'cjdb::invoke(std::forward<F>(f), std::forward<Args>(args)...)' would be invalid: no matching function for call to object of type 'const cjdb::detail_invoke::invoke_fn'
                cjdb::invoke(std::forward<F>(f), std::forward<Args>(args)...); // not required to be equality-preserving
                ^

This isn't exactly informative, since all it's told me is what I already knew: that invoke couldn't be invoked. Something more informative would involve explaining why invoke was unavailable, such as when one tries to manually call cjdb::detail_size::size_fn{}(some_array).

../../../test/unit/range/access/size.cpp:66:8: error: call to object of type 'const cjdb::ranges::detail_size::size_fn' is ambiguous
        (void)cjdb::ranges::size(x);
              ^~~~~~~~~~~~~~~~~~
../../../include/cjdb/detail/range/size.hpp:59:32: note: candidate function [with T = std::__1::array<int, 100> &]
                [[nodiscard]] constexpr auto operator()(T&& t) const
                                             ^
../../../include/cjdb/detail/range/size.hpp:73:32: note: candidate function [with T = std::__1::array<int, 100> &]
                [[nodiscard]] constexpr auto operator()(T&& t) const
                                             ^
../../../include/cjdb/detail/range/size.hpp:79:8: note: candidate function [with T = std::__1::array<int, 100> &] has been explicitly deleted
                void operator()(T&&) const = delete;
                     ^

I'd like to be able to add an attribute to expressions inside requires-expressions to indicate that the compiler should divulge why said expression failed.

template<typename F, typename... Args>
concept invocable1 = requires(F f, Args&&... args) {
   std::invoke(std::forward<F>(f), std::forward<Args>(args)...); // first diagnostic
};

template<typename F, typename... Args>
concept invocable2 = requires(F f, Args&&... args) {
   [[clang::detailed_diagnostic]]
   std::invoke(std::forward<F>(f), std::forward<Args>(args)...); // second diagnostic
};

The reason for wanting an attribute is because there might be some concepts where divulging information is TMI or perhaps it'll lead to template dump-like issues, etc.