Index: CMakeLists.txt =================================================================== --- CMakeLists.txt +++ CMakeLists.txt @@ -507,6 +507,8 @@ if (LIBCXX_CONFIGURE_IDE) # This simply allows IDE to process add_compile_flags_if_supported(-fcoroutines-ts) + # This (presumably) allows IDE to process + add_compile_flags_if_supported(-fconcepts) endif() # Let the library headers know they are currently being used to build the Index: include/CMakeLists.txt =================================================================== --- include/CMakeLists.txt +++ include/CMakeLists.txt @@ -41,6 +41,7 @@ compare complex complex.h + concepts condition_variable csetjmp csignal 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/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 + concept Same = see below; + + // [concept.derivedfrom], concept DerivedFrom + template + concept DerivedFrom = see below; + + // [concept.convertibleto], concept ConvertibleTo + template + concept ConvertibleTo = see below; + + // [concept.commonref], concept CommonReference + template + concept CommonReference = see below; + + // [concept.common], concept Common + template + concept Common = see below; + + // [concepts.integral], integral concepts + template + concept Integral = see below; + template + concept SignedIntegral = see below; + template + concept UnsignedIntegral = see below; + + // [concept.assignable], concept Assignable + template + concept Assignable = see below; + + // [concept.swappable], concept Swappable + template + concept Swappable = see below; + template + concept SwappableWith = see below; + + // [concept.destructible], concept Destructible + template + concept Destructible = see below; + + // [cooncept.constructible], concept Constructible + template + concept Constructible = see below; + + // [concept.defaultconstructible], concept DefaultConstructible + template + concept DefaultConstructible = see below; + + // [concept.moveconstructible], concept MoveConstructible + template + concept MoveConstructible = see below; + + // [concept.copyconstructible], concept CopyConstructible + template + concept CopyConstructible = see below; + + // [concepts.compare], comparison concepts + // [concept.boolean], concept Boolean + template + concept Boolean = see below; + + // [concept.equalitycomparable], concept EqualityComparable + template + concept EqualityComparable = see below; + template + concept EqualityComparableWith = see below; + + // [concept.stricttotallyordered], concept StrictTotallyOrdered + template + concept StrictTotallyOrdered = see below; + template + concept StrictTotallyOrderedWith = see below; + + // [concepts.object], object concepts + template + concept Movable = see below; + template + concept Copyable = see below; + template + concept Semiregular = see below; + template + concept Regular = see below; + + // [concepts.callable], callable concepts + // [concept.invocable], concept Invocable + template + concept Invocable = see below; + + // [concept.regularinvocable], concept RegularInvocable + template + concept RegularInvocable = see below; + + // [concept.predicate], concept Predicate + template + concept Predicate = see below; + + // [concept.relation], concept Relation + template + concept Relation = see below; + + // [concept.strictweakorder], concept StrictWeakOrder + template + concept StrictWeakOrder = see below; + +} + +*/ + +#include <__config> +#include + +#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(" cannot be used with this compiler") +# else +# warning 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 +_LIBCPP_CONCEPT_DECL __same_impl = __is_same_as(_Tp, _Up); +#else +template +_LIBCPP_INLINE_VAR _LIBCPP_CONSTEXPR bool __same_impl_ = false; +template +_LIBCPP_INLINE_VAR _LIBCPP_CONSTEXPR bool __same_impl_<_Tp, _Tp> = true; +template +_LIBCPP_CONCEPT_DECL __same_impl = __same_impl_<_Tp, _Up>; +#endif // _LIBCPP_HAS_IS_SAME_AS + +template +_LIBCPP_CONCEPT_DECL Same = __same_impl<_Tp, _Up> && __same_impl<_Up, _Tp>; + +template +_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; + +template +_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 +_LIBCPP_CONCEPT_DECL CommonReference = + requires { + typename common_reference_t<_Tp, _Up>; + typename common_reference_t<_Up, _Tp>; + } && + Same, common_reference_t<_Up, _Tp>> && + ConvertibleTo<_Tp, common_reference_t<_Tp, _Up>> && + ConvertibleTo<_Up, common_reference_t<_Tp, _Up>>; + +template +_LIBCPP_CONCEPT_DECL Common = + requires { + typename common_type_t<_Tp, _Up>; + typename common_type_t<_Up, _Tp>; + } && + Same, common_type_t<_Up, _Tp>> && + ConvertibleTo<_Tp, common_type_t<_Tp, _Up>> && + ConvertibleTo<_Up, common_type_t<_Tp, _Up>> && + CommonReference< + add_lvalue_reference_t, + add_lvalue_reference_t> && + CommonReference< + add_lvalue_reference_t>, + common_reference_t< + add_lvalue_reference_t, + add_lvalue_reference_t>>; + +template +_LIBCPP_CONCEPT_DECL Integral = is_integral_v<_Tp>; + +template +_LIBCPP_CONCEPT_DECL __integral_has_negatives = _Tp(-1) < _Tp(0); + +template +_LIBCPP_CONCEPT_DECL SignedIntegral = Integral<_Tp> && __integral_has_negatives<_Tp>; + +template +_LIBCPP_CONCEPT_DECL UnsignedIntegral = Integral<_Tp> && !__integral_has_negatives<_Tp>; + +template +_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 +_LIBCPP_CONCEPT_DECL Swappable = is_swappable_v<_Tp>; + +template +_LIBCPP_CONCEPT_DECL SwappableWith = + is_swappable_with_v<_Tp, _Tp> && is_swappable_with_v<_Up, _Up> && + CommonReference&, const remove_reference_t<_Up>&> && + is_swappable_with_v<_Tp, _Up> && is_swappable_with_v<_Up, _Tp>; + +template +_LIBCPP_CONCEPT_DECL Destructible = is_nothrow_destructible_v<_Tp>; + +template +_LIBCPP_CONCEPT_DECL Constructible = + Destructible<_Tp> && is_constructible_v<_Tp, _Args...>; + +template +_LIBCPP_CONCEPT_DECL DefaultConstructible = Constructible<_Tp>; + +template +_LIBCPP_CONCEPT_DECL MoveConstructible = + Constructible<_Tp, _Tp> && ConvertibleTo<_Tp, _Tp>; + +template +_LIBCPP_CONCEPT_DECL CopyConstructible = + MoveConstructible<_Tp> && + Constructible<_Tp, _Tp&> && ConvertibleTo<_Tp&, _Tp> && + Constructible<_Tp, const _Tp&> && ConvertibleTo && + Constructible<_Tp, const _Tp> && ConvertibleTo; + +template +_LIBCPP_CONCEPT_DECL Movable = + is_object_v<_Tp> && + MoveConstructible<_Tp> && + Assignable<_Tp&, _Tp> && + Swappable<_Tp>; + +template +_LIBCPP_CONCEPT_DECL Boolean = + Movable> && + requires(const remove_reference_t<_Tp>& __t1, + const remove_reference_t<_Tp>& __t2, const bool __b) { + requires ConvertibleTo&, bool>; + !__t1; requires ConvertibleTo; + __t1 && __t2; requires Same; + __t1 && __b; requires Same; + __b && __t2; requires Same; + __t1 || __t2; requires Same; + __t1 || __b; requires Same; + __b || __t2; requires Same; + __t1 == __t2; requires ConvertibleTo; + __t1 == __b; requires ConvertibleTo; + __b == __t2; requires ConvertibleTo; + __t1 != __t2; requires ConvertibleTo; + __t1 != __b; requires ConvertibleTo; + __b != __t2; requires ConvertibleTo; + }; + +template +_LIBCPP_CONCEPT_DECL __weakly_equality_comparable = + requires(const remove_reference_t<_Tp>& __t, + const remove_reference_t<_Up>& __u) { + __t == __u; requires Boolean; + __t != __u; requires Boolean; + __u == __t; requires Boolean; + __u != __t; requires Boolean; + }; + +template +_LIBCPP_CONCEPT_DECL EqualityComparable = __weakly_equality_comparable<_Tp, _Tp>; + +template +_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 +_LIBCPP_CONCEPT_DECL __totally_ordered = + requires(const remove_reference_t<_Tp>& __t, + const remove_reference_t<_Up>& __u) { + __t < __u; requires Boolean; + __t > __u; requires Boolean __u)>; + __t <= __u; requires Boolean; + __t >= __u; requires Boolean= __u)>; + }; + +template +_LIBCPP_CONCEPT_DECL StrictTotallyOrdered = + EqualityComparable<_Tp> && __totally_ordered<_Tp, _Tp>; + +template +_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 +_LIBCPP_CONCEPT_DECL Copyable = + CopyConstructible<_Tp> && + Movable<_Tp> && + Assignable<_Tp&, const _Tp&>; + +template +_LIBCPP_CONCEPT_DECL Semiregular = Copyable<_Tp> && DefaultConstructible<_Tp>; + +template +_LIBCPP_CONCEPT_DECL Regular = Semiregular<_Tp> && EqualityComparable<_Tp>; + +template +_LIBCPP_CONCEPT_DECL Invocable = requires(_Fn&& __fn, _Args&&... __args) { + _VSTD::__invoke_constexpr(static_cast<_Fn&&>(__fn), static_cast<_Args&&>(__args)...); +}; + +template +_LIBCPP_CONCEPT_DECL RegularInvocable = Invocable<_Fn, _Args...>; + +template +_LIBCPP_CONCEPT_DECL Predicate = RegularInvocable<_Fn, _Args...> && + Boolean>; + +template +_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 +_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/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: 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: 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 + +#ifndef _LIBCPP_VERSION +#error _LIBCPP_VERSION not defined +#endif + +int main() {} Index: test/libcxx/double_include.sh.cpp =================================================================== --- test/libcxx/double_include.sh.cpp +++ test/libcxx/double_include.sh.cpp @@ -44,6 +44,9 @@ #include #include #include +#ifndef _LIBCPP_HAS_NO_CONCEPTS +#include +#endif #include #include #include 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 TEST_MACROS(); +#include +TEST_MACROS(); #include TEST_MACROS(); #include 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':