@@ -3751,6 +3751,9 @@ diagnose_trait_expr (tree expr, tree args)
case CPTK_IS_FINAL:
inform (loc, " %qT is not a final class", t1);
break;
+ case CPTK_IS_FUNCTION:
+ inform (loc, " %qT is not a function", t1);
+ break;
case CPTK_IS_LAYOUT_COMPATIBLE:
inform (loc, " %qT is not layout compatible with %qT", t1, t2);
break;
@@ -70,6 +70,7 @@ DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2)
DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
+DEFTRAIT_EXPR (IS_FUNCTION, "__is_function", 1)
DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
@@ -12178,6 +12178,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
case CPTK_IS_FINAL:
return CLASS_TYPE_P (type1) && CLASSTYPE_FINAL (type1);
+ case CPTK_IS_FUNCTION:
+ return type_code1 == FUNCTION_TYPE;
+
case CPTK_IS_LAYOUT_COMPATIBLE:
return layout_compatible_type_p (type1, type2);
@@ -12405,6 +12408,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
case CPTK_IS_CLASS:
case CPTK_IS_CONST:
case CPTK_IS_ENUM:
+ case CPTK_IS_FUNCTION:
case CPTK_IS_MEMBER_FUNCTION_POINTER:
case CPTK_IS_MEMBER_OBJECT_POINTER:
case CPTK_IS_MEMBER_POINTER:
@@ -89,6 +89,9 @@
#if !__has_builtin (__is_final)
# error "__has_builtin (__is_final) failed"
#endif
+#if !__has_builtin (__is_function)
+# error "__has_builtin (__is_function) failed"
+#endif
#if !__has_builtin (__is_layout_compatible)
# error "__has_builtin (__is_layout_compatible) failed"
#endif
new file mode 100644
@@ -0,0 +1,58 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+#define SA_TEST_CATEGORY(TRAIT, TYPE, EXPECT) \
+ SA(TRAIT(TYPE) == EXPECT); \
+ SA(TRAIT(const TYPE) == EXPECT); \
+ SA(TRAIT(volatile TYPE) == EXPECT); \
+ SA(TRAIT(const volatile TYPE) == EXPECT)
+
+struct A
+{ void fn(); };
+
+template<typename>
+struct AHolder { };
+
+template<class T, class U>
+struct AHolder<U T::*>
+{ using type = U; };
+
+// Positive tests.
+SA(__is_function(int (int)));
+SA(__is_function(ClassType (ClassType)));
+SA(__is_function(float (int, float, int[], int&)));
+SA(__is_function(int (int, ...)));
+SA(__is_function(bool (ClassType) const));
+SA(__is_function(AHolder<decltype(&A::fn)>::type));
+
+void fn();
+SA(__is_function(decltype(fn)));
+
+// Negative tests.
+SA_TEST_CATEGORY(__is_function, int, false);
+SA_TEST_CATEGORY(__is_function, int*, false);
+SA_TEST_CATEGORY(__is_function, int&, false);
+SA_TEST_CATEGORY(__is_function, void, false);
+SA_TEST_CATEGORY(__is_function, void*, false);
+SA_TEST_CATEGORY(__is_function, void**, false);
+SA_TEST_CATEGORY(__is_function, std::nullptr_t, false);
+
+SA_TEST_CATEGORY(__is_function, AbstractClass, false);
+SA(!__is_function(int(&)(int)));
+SA(!__is_function(int(*)(int)));
+
+SA_TEST_CATEGORY(__is_function, A, false);
+SA_TEST_CATEGORY(__is_function, decltype(&A::fn), false);
+
+struct FnCallOverload
+{ void operator()(); };
+SA_TEST_CATEGORY(__is_function, FnCallOverload, false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_function, ClassType, false);
+SA_TEST_CATEGORY(__is_function, IncompleteClass, false);
+SA_TEST_CATEGORY(__is_function, IncompleteUnion, false);