CaseyCarter created this revision. CaseyCarter added reviewers: mclow.lists, EricWF. Herald added subscribers: christof, modocache, mgorny.
Piece number two contains the header, a bunch of "add a new header" changes, and LIT config to grok tests that need concepts (Thanks to @EricWF's similar handling for coroutines which I copied shamelessly). No tests yet, but fear not - there are 10 pieces yet to come ;) https://reviews.llvm.org/D49120 Files: CMakeLists.txt include/CMakeLists.txt include/__config include/concepts include/module.modulemap test/libcxx/concepts/lit.local.cfg test/libcxx/concepts/version.pass.cpp test/libcxx/double_include.sh.cpp test/libcxx/min_max_macros.sh.cpp utils/libcxx/test/config.py
Index: utils/libcxx/test/config.py =================================================================== --- utils/libcxx/test/config.py +++ utils/libcxx/test/config.py @@ -153,6 +153,7 @@ self.configure_coverage() self.configure_modules() self.configure_coroutines() + self.configure_concepts() self.configure_substitutions() self.configure_features() @@ -1017,6 +1018,22 @@ if intMacroValue(macros['__cpp_coroutines']) >= 201703: self.config.available_features.add('fcoroutines-ts') + def configure_concepts(self): + # If the compiler supports concepts, add the 'concepts' feature. + # If it requires the '-fconcepts' flag to do so, additionally add the + # 'fconcepts' feature. + macros = self._dump_macros_verbose() + if '__cpp_concepts' in macros and intMacroValue(macros['__cpp_concepts']) >= 201507: + self.config.available_features.add('concepts') + elif self.cxx.hasCompileFlag('-fconcepts'): + macros = self._dump_macros_verbose(flags=['-fconcepts']) + if '__cpp_concepts' not in macros: + self.lit_config.warning('-fconcepts is supported but ' + '__cpp_concepts is not defined') + if intMacroValue(macros['__cpp_concepts']) >= 201507: + self.config.available_features.add('concepts') + self.config.available_features.add('fconcepts') + def configure_modules(self): modules_flags = ['-fmodules'] if platform.system() != 'Darwin': Index: test/libcxx/min_max_macros.sh.cpp =================================================================== --- test/libcxx/min_max_macros.sh.cpp +++ test/libcxx/min_max_macros.sh.cpp @@ -64,6 +64,8 @@ TEST_MACROS(); #include <complex.h> TEST_MACROS(); +#include <concepts> +TEST_MACROS(); #include <condition_variable> TEST_MACROS(); #include <csetjmp> Index: test/libcxx/double_include.sh.cpp =================================================================== --- test/libcxx/double_include.sh.cpp +++ test/libcxx/double_include.sh.cpp @@ -44,6 +44,9 @@ #include <compare> #include <complex> #include <complex.h> +#ifndef _LIBCPP_HAS_NO_CONCEPTS +#include <concepts> +#endif #include <condition_variable> #include <csetjmp> #include <csignal> Index: test/libcxx/concepts/version.pass.cpp =================================================================== --- /dev/null +++ test/libcxx/concepts/version.pass.cpp @@ -0,0 +1,19 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// + +// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17 + +#include <concepts> + +#ifndef _LIBCPP_VERSION +#error _LIBCPP_VERSION not defined +#endif + +int main() {} Index: test/libcxx/concepts/lit.local.cfg =================================================================== --- /dev/null +++ test/libcxx/concepts/lit.local.cfg @@ -0,0 +1,9 @@ +# If the compiler doesn't support concepts, mark all of the tests under +# this directory as unsupported. +if 'concepts' not in config.available_features: + config.unsupported = True +elif 'fconcepts' in config.available_features: + # The compiler supports concepts only with the flag - require it. + import copy + config.test_format.cxx = copy.deepcopy(config.test_format.cxx) + config.test_format.cxx.compile_flags += ['-fconcepts'] Index: include/module.modulemap =================================================================== --- include/module.modulemap +++ include/module.modulemap @@ -251,6 +251,10 @@ header "complex" export * } + module concepts { + header "concepts" + export * + } module condition_variable { header "condition_variable" export * Index: include/concepts =================================================================== --- /dev/null +++ include/concepts @@ -0,0 +1,417 @@ +// -*- C++ -*- +//===-------------------------- concepts ----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP_CONCEPTS +#define _LIBCPP_CONCEPTS + +/* + concepts synopsis + +// C++20 + +namespace std +{ + + // [concepts.lang], language-related concepts + // [concept.same], concept Same + template<class T, class U> + concept Same = see below; + + // [concept.derivedfrom], concept DerivedFrom + template<class Derived, class Base> + concept DerivedFrom = see below; + + // [concept.convertibleto], concept ConvertibleTo + template<class From, class To> + concept ConvertibleTo = see below; + + // [concept.commonref], concept CommonReference + template<class T, class U> + concept CommonReference = see below; + + // [concept.common], concept Common + template<class T, class U> + concept Common = see below; + + // [concepts.integral], integral concepts + template<class T> + concept Integral = see below; + template<class T> + concept SignedIntegral = see below; + template<class T> + concept UnsignedIntegral = see below; + + // [concept.assignable], concept Assignable + template<class LHS, class RHS> + concept Assignable = see below; + + // [concept.swappable], concept Swappable + template<class T> + concept Swappable = see below; + template<class T, class U> + concept SwappableWith = see below; + + // [concept.destructible], concept Destructible + template<class T> + concept Destructible = see below; + + // [cooncept.constructible], concept Constructible + template<class T, class... Args> + concept Constructible = see below; + + // [concept.defaultconstructible], concept DefaultConstructible + template<class T> + concept DefaultConstructible = see below; + + // [concept.moveconstructible], concept MoveConstructible + template<class T> + concept MoveConstructible = see below; + + // [concept.copyconstructible], concept CopyConstructible + template<class T> + concept CopyConstructible = see below; + + // [concepts.compare], comparison concepts + // [concept.boolean], concept Boolean + template<class B> + concept Boolean = see below; + + // [concept.equalitycomparable], concept EqualityComparable + template<class T> + concept EqualityComparable = see below; + template<class T, class U> + concept EqualityComparableWith = see below; + + // [concept.stricttotallyordered], concept StrictTotallyOrdered + template<class T> + concept StrictTotallyOrdered = see below; + template<class T, class U> + concept StrictTotallyOrderedWith = see below; + + // [concepts.object], object concepts + template<class T> + concept Movable = see below; + template<class T> + concept Copyable = see below; + template<class T> + concept Semiregular = see below; + template<class T> + concept Regular = see below; + + // [concepts.callable], callable concepts + // [concept.invocable], concept Invocable + template<class F, class... Args> + concept Invocable = see below; + + // [concept.regularinvocable], concept RegularInvocable + template<class F, class... Args> + concept RegularInvocable = see below; + + // [concept.predicate], concept Predicate + template<class F, class... Args> + concept Predicate = see below; + + // [concept.relation], concept Relation + template<class R, class T, class U> + concept Relation = see below; + + // [concept.strictweakorder], concept StrictWeakOrder + template<class R, class T, class U> + concept StrictWeakOrder = see below; + +} + +*/ + +#include <__config> +#include <type_traits> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#ifdef _LIBCPP_HAS_NO_CONCEPTS +# if defined(_LIBCPP_WARNING) + _LIBCPP_WARNING("<concepts> cannot be used with this compiler") +# else +# warning <concepts> cannot be used with this compiler +# endif +#endif + +#if !defined(_LIBCPP_HAS_NO_CONCEPTS) && _LIBCPP_STD_VER > 17 +#define __cpp_lib_concepts 201806L + +#if __cpp_concepts < 201707L +#define _LIBCPP_CONCEPT_DECL concept bool +#else +#define _LIBCPP_CONCEPT_DECL concept +#endif // __cpp_concepts < 201707L + +_LIBCPP_BEGIN_NAMESPACE_STD + +#ifdef _LIBCPP_HAS_IS_SAME_AS +template <class _Tp, class _Up> +_LIBCPP_CONCEPT_DECL __same_impl = __is_same_as(_Tp, _Up); +#else +template <class, class> +_LIBCPP_INLINE_VAR _LIBCPP_CONSTEXPR bool __same_impl_ = false; +template <class _Tp> +_LIBCPP_INLINE_VAR _LIBCPP_CONSTEXPR bool __same_impl_<_Tp, _Tp> = true; +template <class _Tp, class _Up> +_LIBCPP_CONCEPT_DECL __same_impl = __same_impl_<_Tp, _Up>; +#endif // _LIBCPP_HAS_IS_SAME_AS + +template <class _Tp, class _Up> +_LIBCPP_CONCEPT_DECL Same = __same_impl<_Tp, _Up> && __same_impl<_Up, _Tp>; + +template <class _Derived, class _Base> +_LIBCPP_CONCEPT_DECL DerivedFrom = +#ifdef _LIBCPP_HAS_IS_BASE_OF + __is_base_of(_Base, _Derived) && +#else + is_base_of_v<_Base, _Derived> && +#endif // _LIBCPP_HAS_IS_BASE_OF + is_convertible_v<const volatile _Derived*, const volatile _Base*>; + +template <class _From, class _To> +_LIBCPP_CONCEPT_DECL ConvertibleTo = +#if __has_feature(is_convertible_to) && !defined(_LIBCPP_USE_IS_CONVERTIBLE_FALLBACK) + __is_convertible_to(_From, _To) && +#else + is_convertible_v<_From, _To> && +#endif +#if 0 // FIXME: File LWG issue + requires(_From (&_Fn)()) { static_cast<_To>(_Fn()); }; +#else + requires(add_rvalue_reference_t<_From> (&__fn)()) { + static_cast<_To>(__fn()); + }; +#endif + +template <class _Tp, class _Up> +_LIBCPP_CONCEPT_DECL CommonReference = + requires { + typename common_reference_t<_Tp, _Up>; + typename common_reference_t<_Up, _Tp>; + } && + Same<common_reference_t<_Tp, _Up>, common_reference_t<_Up, _Tp>> && + ConvertibleTo<_Tp, common_reference_t<_Tp, _Up>> && + ConvertibleTo<_Up, common_reference_t<_Tp, _Up>>; + +template <class _Tp, class _Up> +_LIBCPP_CONCEPT_DECL Common = + requires { + typename common_type_t<_Tp, _Up>; + typename common_type_t<_Up, _Tp>; + } && + Same<common_type_t<_Tp, _Up>, common_type_t<_Up, _Tp>> && + ConvertibleTo<_Tp, common_type_t<_Tp, _Up>> && + ConvertibleTo<_Up, common_type_t<_Tp, _Up>> && + CommonReference< + add_lvalue_reference_t<const _Tp>, + add_lvalue_reference_t<const _Up>> && + CommonReference< + add_lvalue_reference_t<common_type_t<_Tp, _Up>>, + common_reference_t< + add_lvalue_reference_t<const _Tp>, + add_lvalue_reference_t<const _Up>>>; + +template <class _Tp> +_LIBCPP_CONCEPT_DECL Integral = is_integral_v<_Tp>; + +template <class _Tp> +_LIBCPP_CONCEPT_DECL __integral_has_negatives = _Tp(-1) < _Tp(0); + +template <class _Tp> +_LIBCPP_CONCEPT_DECL SignedIntegral = Integral<_Tp> && __integral_has_negatives<_Tp>; + +template <class _Tp> +_LIBCPP_CONCEPT_DECL UnsignedIntegral = Integral<_Tp> && !__integral_has_negatives<_Tp>; + +template <class _Lhs, class _Rhs> +_LIBCPP_CONCEPT_DECL Assignable = + is_lvalue_reference_v<_Lhs> && + CommonReference< + const remove_reference_t<_Lhs>&, + const remove_reference_t<_Rhs>&> && + requires(_Lhs __left, _Rhs&& __right) { + __left = static_cast<_Rhs&&>(__right); + requires Same<_Lhs, decltype(__left = static_cast<_Rhs&&>(__right))>; + }; + +template <class _Tp> +_LIBCPP_CONCEPT_DECL Swappable = is_swappable_v<_Tp>; + +template <class _Tp, class _Up> +_LIBCPP_CONCEPT_DECL SwappableWith = + is_swappable_with_v<_Tp, _Tp> && is_swappable_with_v<_Up, _Up> && + CommonReference<const remove_reference_t<_Tp>&, const remove_reference_t<_Up>&> && + is_swappable_with_v<_Tp, _Up> && is_swappable_with_v<_Up, _Tp>; + +template <class _Tp> +_LIBCPP_CONCEPT_DECL Destructible = is_nothrow_destructible_v<_Tp>; + +template <class _Tp, class... _Args> +_LIBCPP_CONCEPT_DECL Constructible = + Destructible<_Tp> && is_constructible_v<_Tp, _Args...>; + +template <class _Tp> +_LIBCPP_CONCEPT_DECL DefaultConstructible = Constructible<_Tp>; + +template <class _Tp> +_LIBCPP_CONCEPT_DECL MoveConstructible = + Constructible<_Tp, _Tp> && ConvertibleTo<_Tp, _Tp>; + +template <class _Tp> +_LIBCPP_CONCEPT_DECL CopyConstructible = + MoveConstructible<_Tp> && + Constructible<_Tp, _Tp&> && ConvertibleTo<_Tp&, _Tp> && + Constructible<_Tp, const _Tp&> && ConvertibleTo<const _Tp&, _Tp> && + Constructible<_Tp, const _Tp> && ConvertibleTo<const _Tp, _Tp>; + +template <class _Tp> +_LIBCPP_CONCEPT_DECL Movable = + is_object_v<_Tp> && + MoveConstructible<_Tp> && + Assignable<_Tp&, _Tp> && + Swappable<_Tp>; + +template <class _Tp> +_LIBCPP_CONCEPT_DECL Boolean = + Movable<remove_cvref_t<_Tp>> && + requires(const remove_reference_t<_Tp>& __t1, + const remove_reference_t<_Tp>& __t2, const bool __b) { + requires ConvertibleTo<const remove_reference_t<_Tp>&, bool>; + !__t1; requires ConvertibleTo<decltype(!__t1), bool>; + __t1 && __t2; requires Same<decltype(__t1 && __t2), bool>; + __t1 && __b; requires Same<decltype(__t1 && __b), bool>; + __b && __t2; requires Same<decltype( __b && __t2), bool>; + __t1 || __t2; requires Same<decltype(__t1 || __t2), bool>; + __t1 || __b; requires Same<decltype(__t1 || __b), bool>; + __b || __t2; requires Same<decltype( __b || __t2), bool>; + __t1 == __t2; requires ConvertibleTo<decltype(__t1 == __t2), bool>; + __t1 == __b; requires ConvertibleTo<decltype(__t1 == __b), bool>; + __b == __t2; requires ConvertibleTo<decltype( __b == __t2), bool>; + __t1 != __t2; requires ConvertibleTo<decltype(__t1 != __t2), bool>; + __t1 != __b; requires ConvertibleTo<decltype(__t1 != __b), bool>; + __b != __t2; requires ConvertibleTo<decltype( __b != __t2), bool>; + }; + +template <class _Tp, class _Up> +_LIBCPP_CONCEPT_DECL __weakly_equality_comparable = + requires(const remove_reference_t<_Tp>& __t, + const remove_reference_t<_Up>& __u) { + __t == __u; requires Boolean<decltype(__t == __u)>; + __t != __u; requires Boolean<decltype(__t != __u)>; + __u == __t; requires Boolean<decltype(__u == __t)>; + __u != __t; requires Boolean<decltype(__u != __t)>; + }; + +template <class _Tp> +_LIBCPP_CONCEPT_DECL EqualityComparable = __weakly_equality_comparable<_Tp, _Tp>; + +template <class _Tp, class _Up> +_LIBCPP_CONCEPT_DECL EqualityComparableWith = + EqualityComparable<_Tp> && + EqualityComparable<_Up> && + CommonReference< + const remove_reference_t<_Tp>&, + const remove_reference_t<_Up>&> && + EqualityComparable< + common_reference_t< + const remove_reference_t<_Tp>&, + const remove_reference_t<_Up>&>> && + __weakly_equality_comparable<_Tp, _Up>; + +template <class _Tp, class _Up> +_LIBCPP_CONCEPT_DECL __totally_ordered = + requires(const remove_reference_t<_Tp>& __t, + const remove_reference_t<_Up>& __u) { + __t < __u; requires Boolean<decltype(__t < __u)>; + __t > __u; requires Boolean<decltype(__t > __u)>; + __t <= __u; requires Boolean<decltype(__t <= __u)>; + __t >= __u; requires Boolean<decltype(__t >= __u)>; + }; + +template <class _Tp> +_LIBCPP_CONCEPT_DECL StrictTotallyOrdered = + EqualityComparable<_Tp> && __totally_ordered<_Tp, _Tp>; + +template <class _Tp, class _Up> +_LIBCPP_CONCEPT_DECL StrictTotallyOrderedWith = + StrictTotallyOrdered<_Tp> && + StrictTotallyOrdered<_Up> && + CommonReference< + const remove_reference_t<_Tp>&, + const remove_reference_t<_Up>&> && + StrictTotallyOrdered< + common_reference_t< + const remove_reference_t<_Tp>&, + const remove_reference_t<_Up>&>> && + EqualityComparableWith<_Tp, _Up> && + __totally_ordered<_Tp, _Up> && + __totally_ordered<_Up, _Tp>; + +template <class _Tp> +_LIBCPP_CONCEPT_DECL Copyable = + CopyConstructible<_Tp> && + Movable<_Tp> && + Assignable<_Tp&, const _Tp&>; + +template <class _Tp> +_LIBCPP_CONCEPT_DECL Semiregular = Copyable<_Tp> && DefaultConstructible<_Tp>; + +template <class _Tp> +_LIBCPP_CONCEPT_DECL Regular = Semiregular<_Tp> && EqualityComparable<_Tp>; + +template <class _Fn, class... _Args> +_LIBCPP_CONCEPT_DECL Invocable = requires(_Fn&& __fn, _Args&&... __args) { + __invoke_constexpr(static_cast<_Fn&&>(__fn), static_cast<_Args&&>(__args)...); +}; + +template <class _Fn, class... _Args> +_LIBCPP_CONCEPT_DECL RegularInvocable = Invocable<_Fn, _Args...>; + +template <class _Fn, class... _Args> +_LIBCPP_CONCEPT_DECL Predicate = RegularInvocable<_Fn, _Args...> && + Boolean<invoke_result_t<_Fn, _Args...>>; + +template <class _Fn, class _Tp, class _Up> +_LIBCPP_CONCEPT_DECL Relation = + Predicate<_Fn, _Tp, _Tp> && + Predicate<_Fn, _Up, _Up> && + CommonReference< + const remove_reference_t<_Tp>&, + const remove_reference_t<_Up>&> && + Predicate<_Fn, + common_reference_t< + const remove_reference_t<_Tp>&, + const remove_reference_t<_Up>&>, + common_reference_t< + const remove_reference_t<_Tp>&, + const remove_reference_t<_Up>&>> && + Predicate<_Fn, _Tp, _Up> && + Predicate<_Fn, _Up, _Tp>; + +template <class _Fn, class _Tp, class _Up> +_LIBCPP_CONCEPT_DECL StrictWeakOrder = Relation<_Fn, _Tp, _Up>; + +_LIBCPP_END_NAMESPACE_STD + +#undef _LIBCPP_CONCEPT_DECL + +#endif // !defined(_LIBCPP_HAS_NO_CONCEPTS) && _LIBCPP_STD_VER > 17 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP_CONCEPTS Index: include/__config =================================================================== --- include/__config +++ include/__config @@ -494,6 +494,10 @@ #define _LIBCPP_HAS_IS_FINAL #endif +#if defined(__GNUC__) && _GNUC_VER >= 600 +#define _LIBCPP_HAS_IS_SAME_AS +#endif + #if defined(__GNUC__) && _GNUC_VER >= 403 #define _LIBCPP_HAS_IS_BASE_OF #endif @@ -1203,6 +1207,18 @@ #define _LIBCPP_HAS_NO_COROUTINES #endif +// Note that there is no feature test macro for Concepts in the current C++20 +// working draft. Some of the concepts working papers - but notably neither the +// TS nor the final proposal which was partially merged into the WD - defined +// __cpp_concepts to 201507L. This is the value that GCC currently defines when +// support for the concepts TS is enabled with -fconcepts. We therefore use +// __cpp_concepts to detect support, and speculate that C++20-compliant +// compilers will define __cpp_concepts to at least 201707 - the date of the +// Toronto WG21 meeting that incorporated Concepts into the WD. +#if !defined(__cpp_concepts) || __cpp_concepts < 201507L +#define _LIBCPP_HAS_NO_CONCEPTS +#endif + // FIXME: Correct this macro when either (A) a feature test macro for the // spaceship operator is provided, or (B) a compiler provides a complete // implementation. Index: include/CMakeLists.txt =================================================================== --- include/CMakeLists.txt +++ include/CMakeLists.txt @@ -41,6 +41,7 @@ compare complex complex.h + concepts condition_variable csetjmp csignal Index: CMakeLists.txt =================================================================== --- CMakeLists.txt +++ CMakeLists.txt @@ -507,6 +507,8 @@ if (LIBCXX_CONFIGURE_IDE) # This simply allows IDE to process <experimental/coroutine> add_compile_flags_if_supported(-fcoroutines-ts) + # This (presumably) allows IDE to process <concepts> + add_compile_flags_if_supported(-fconcepts) endif() # Let the library headers know they are currently being used to build the
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits