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
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits