c++: Implement C++26 P3176R1 - The Oxford variadic comma

While we are already in stage3, I wonder if implementing this small paper
wouldn't be useful even for GCC 15, so that we have in the GCC world one
extra year of deprecation of variadic ellipsis without preceding comma.

The paper just deprecates something, I'd hope most of the C++ code in the
wild when it uses variadic functions at all uses the comma before the
ellipsis.

2024-11-30  Jakub Jelinek  <jakub@redhat.com>

gcc/c-family/
	* c.opt (Wdeprecated-variadic-comma-omission): New option.
	* c.opt.urls: Regenerate.
	* c-opts.cc (c_common_post_options): Default to
	-Wdeprecated-variadic-comma-omission for C++26 or -Wpedantic.
gcc/cp/
	* parser.cc: Implement C++26 P3176R1 - The Oxford variadic comma.
	(cp_parser_parameter_declaration_clause): Emit
	-Wdeprecated-variadic-comma-omission warnings.
gcc/
	* doc/invoke.texi (-Wdeprecated-variadic-comma-omission): Document.
gcc/testsuite/
	* g++.dg/cpp26/variadic-comma1.C: New test.
	* g++.dg/cpp26/variadic-comma2.C: New test.
	* g++.dg/cpp26/variadic-comma3.C: New test.
	* g++.dg/cpp26/variadic-comma4.C: New test.
	* g++.dg/cpp26/variadic-comma5.C: New test.
	* g++.dg/cpp1z/fold10.C: Expect a warning for C++26.
	* g++.dg/ext/attrib33.C: Likewise.
	* g++.dg/cpp1y/lambda-generic-variadic19.C: Likewise.
	* g++.dg/cpp2a/lambda-generic10.C: Likewise.
	* g++.dg/cpp0x/lambda/lambda-const3.C: Likewise.
	* g++.dg/cpp0x/variadic164.C: Likewise.
	* g++.dg/cpp0x/variadic17.C: Likewise.
	* g++.dg/cpp0x/udlit-args-neg.C: Likewise.
	* g++.dg/cpp0x/variadic28.C: Likewise.
	* g++.dg/cpp0x/gen-attrs-33.C: Likewise.
	* g++.dg/cpp23/explicit-obj-diagnostics3.C: Likewise.
	* g++.old-deja/g++.law/operators15.C: Likewise.
	* g++.old-deja/g++.mike/p811.C: Likewise.
	* g++.old-deja/g++.mike/p12306.C (printf): Add , before ... .
	* g++.dg/analyzer/fd-bind-pr107783.C (bind): Likewise.
	* g++.dg/cpp0x/vt-65790.C (printf): Likewise.
libstdc++-v3/
	* include/std/functional (_Bind_check_arity): Add , before ... .
	* include/bits/refwrap.h (_Mem_fn_traits, _Weak_result_type_impl):
	Likewise.
	* include/tr1/type_traits (is_function): Likewise.
This commit is contained in:
Jakub Jelinek 2024-11-30 01:49:21 +01:00 committed by Jakub Jelinek
parent 20dcb7926b
commit cc67d95dc1
29 changed files with 147 additions and 41 deletions

View file

@ -1061,6 +1061,11 @@ c_common_post_options (const char **pfilename)
warn_array_compare,
warn_array_compare || deprecated_in (cxx20));
/* -Wdeprecated-variadic-comma-omission is enabled by default in C++26. */
SET_OPTION_IF_UNSET (&global_options, &global_options_set,
warn_deprecated_variadic_comma_omission,
deprecated_in (cxx26));
/* -Wtemplate-id-cdtor is enabled by default in C++20. */
SET_OPTION_IF_UNSET (&global_options, &global_options_set,
warn_template_id_cdtor,

View file

@ -672,6 +672,10 @@ Wdeprecated-non-prototype
C ObjC Var(warn_deprecated_non_prototype) Init(-1) Warning
Warn about calls with arguments to functions declared without parameters.
Wdeprecated-variadic-comma-omission
C++ ObjC++ Var(warn_deprecated_variadic_comma_omission) Warning
Warn about deprecated omission of comma before ... in varargs function declaration.
Wdesignated-init
C ObjC Var(warn_designated_init) Init(1) Warning
Warn about positional initialization of structs requiring designated initializers.

View file

@ -310,6 +310,9 @@ UrlSuffix(gcc/C_002b_002b-Dialect-Options.html#index-Wdeprecated-literal-operato
Wdeprecated-non-prototype
UrlSuffix(gcc/Warning-Options.html#index-Wdeprecated-non-prototype)
Wdeprecated-variadic-comma-omission
UrlSuffix(gcc/C_002b_002b-Dialect-Options.html#index-Wdeprecated-variadic-comma-omission)
Wdesignated-init
UrlSuffix(gcc/Warning-Options.html#index-Wdesignated-init)

View file

@ -25770,6 +25770,16 @@ cp_parser_parameter_declaration_clause (cp_parser* parser,
omitted. */
else if (token->type == CPP_ELLIPSIS)
{
/* Deprecated by P3176R1 in C++26. */
if (warn_deprecated_variadic_comma_omission)
{
gcc_rich_location richloc (token->location);
richloc.add_fixit_insert_before (", ");
warning_at (&richloc, OPT_Wdeprecated_variadic_comma_omission,
"omission of %<,%> before varargs %<...%> is "
"deprecated in C++26");
}
/* Consume the `...' token. */
cp_lexer_consume_token (parser->lexer);
/* And remember that we saw it. */

View file

@ -4069,6 +4069,22 @@ string operator "" _i18n(const char*, std::size_t); // deprecated
string operator ""_i18n(const char*, std::size_t); // preferred
@end smallexample
@opindex Wdeprecated-variadic-comma-omission
@opindex Wno-deprecated-variadic-comma-omission
@item -Wdeprecated-variadic-comma-omission @r{(C++ and Objective-C++ only)}
Warn that omitting a comma before the varargs @code{...} at the end of
a function parameter list is deprecated. This warning is enabled by
default in C++26, or with explicit @option{-Wdeprecated}.
@smallexample
void f1(int...); // deprecated
void f1(int, ...); // preferred
template <typename ...T>
void f2(T...); // ok
template <typename ...T>
void f3(T......); // deprecated
@end smallexample
@opindex Welaborated-enum-base
@opindex Wno-elaborated-enum-base
@item -Wno-elaborated-enum-base
@ -10348,8 +10364,9 @@ In C++, explicitly specifying @option{-Wdeprecated} also enables
warnings about some features that are deprecated in later language
standards, specifically @option{-Wcomma-subscript},
@option{-Wvolatile}, @option{-Wdeprecated-enum-float-conversion},
@option{-Wdeprecated-enum-enum-conversion}, and
@option{-Wdeprecated-literal-operator}.
@option{-Wdeprecated-enum-enum-conversion},
@option{-Wdeprecated-literal-operator}, and
@option{-Wdeprecated-variadic-comma-omission}.
@opindex Wno-deprecated-declarations
@opindex Wdeprecated-declarations

View file

@ -7,5 +7,5 @@ struct _Bind {
_Bind(_Bind &);
};
template <typename _Func, typename _BoundArgs>
_Bind bind(_Func, _BoundArgs &&...);
_Bind bind(_Func, _BoundArgs &&, ...);
void test01() { bind(minus(), _2, _1); }

View file

@ -5,7 +5,7 @@
template <int N>
struct T
{
void foo [[gnu::format (printf,2,3)]] (char const * ...);
void foo [[gnu::format (printf,2,3)]] (char const * ...); // { dg-warning "omission of ',' before varargs '...' is deprecated" "" { target c++26 } }
};
template struct T<3>;

View file

@ -7,7 +7,7 @@ struct FF
{
template < class F, class ... Ts >
void
operator () (F & ...)
operator () (F & ...) // { dg-warning "omission of ',' before varargs '...' is deprecated" "" { target c++26 } }
{
const int n = sizeof ... (Ts) + 1;
void *mutexes[n];

View file

@ -27,6 +27,7 @@ operator ""_Foo(const char16_t *); // { dg-error "1:.Foo operator\"\"_Foo\\(cons
Foo
operator ""_Foo(char...); // { dg-error "1:.Foo operator\"\"_Foo\\(char, \\.\\.\\.\\). has invalid argument list" }
// { dg-warning "omission of ',' before varargs '...' is deprecated" "" { target c++26 } .-1 }
Foo
operator ""_Foo(unsigned long long int, char); // { dg-error "1:.Foo operator\"\"_Foo\\(long long unsigned int, char\\). has invalid argument list" }

View file

@ -8,5 +8,5 @@ template <typename Tuple, typename... Tuples, int... ElementIndices,
typename =
typename tuple<slice_result<ElementIndices, Tuples...>,
slice_result<ElementIndices, Tuples...>...>::type> // { dg-error "parameter pack" }
void zip_with(Tuple...);
void zip_with(Tuple...); // { dg-warning "omission of ',' before varargs '...' is deprecated" "" { target c++26 } }
decltype(zip_with(0)) d; // { dg-error "no match" }

View file

@ -2,7 +2,7 @@
template<typename R, typename... ArgTypes>
struct make_function_type
{
typedef R type(const ArgTypes&......);
typedef R type(const ArgTypes&......); // { dg-warning "omission of ',' before varargs '...' is deprecated" "" { target c++26 } }
};
template<typename T, typename U>
@ -16,6 +16,6 @@ struct is_same<T, T> {
};
int a0[is_same<make_function_type<int>::type, int(...)>::value? 1 : -1];
int a1[is_same<make_function_type<int, float>::type, int(const float&...)>::value? 1 : -1];
int a1[is_same<make_function_type<int, float>::type, int(const float&...)>::value? 1 : -1]; // { dg-warning "omission of ',' before varargs '...' is deprecated" "" { target c++26 } }
int a2[is_same<make_function_type<int, float>::type, int(const float&,...)>::value? 1 : -1];
int a3[is_same<make_function_type<int, float, double>::type, int(const float&, double const&...)>::value? 1 : -1];
int a3[is_same<make_function_type<int, float, double>::type, int(const float&, double const&...)>::value? 1 : -1]; // { dg-warning "omission of ',' before varargs '...' is deprecated" "" { target c++26 } }

View file

@ -3,7 +3,7 @@ template<typename Signature>
struct function_traits;
template<typename R, typename... ArgTypes>
struct function_traits<R(ArgTypes......)> {
struct function_traits<R(ArgTypes......)> { // { dg-warning "omission of ',' before varargs '...' is deprecated" "" { target c++26 } }
typedef R result_type;
};
@ -17,9 +17,9 @@ struct same_type<T, T> {
static const bool value = true;
};
int a0[same_type<function_traits<int(double, char...)>::result_type, int>::value? 1 : -1];
int a0[same_type<function_traits<int(double, char...)>::result_type, int>::value? 1 : -1]; // { dg-warning "omission of ',' before varargs '...' is deprecated" "" { target c++26 } }
int a1[same_type<function_traits<int(double, char,...)>::result_type, int>::value? 1 : -1];
int a2[same_type<function_traits<int(char,...)>::result_type, int>::value? 1 : -1];
int a3[same_type<function_traits<int(...)>::result_type, int>::value? 1 : -1];
int a4[same_type<function_traits<int(double x, char...)>::result_type, int>::value? 1 : -1];
int a5[same_type<function_traits<int(double, char y...)>::result_type, int>::value? 1 : -1];
int a4[same_type<function_traits<int(double x, char...)>::result_type, int>::value? 1 : -1]; // { dg-warning "omission of ',' before varargs '...' is deprecated" "" { target c++26 } }
int a5[same_type<function_traits<int(double, char y...)>::result_type, int>::value? 1 : -1]; // { dg-warning "omission of ',' before varargs '...' is deprecated" "" { target c++26 } }

View file

@ -1,7 +1,7 @@
// PR c++/65790
// { dg-do compile { target c++11 } }
extern "C" int printf(const char* ...);
extern "C" int printf(const char*, ...);
namespace std
{

View file

@ -1,4 +1,4 @@
// PR c++/86728
// { dg-do compile { target c++14 } }
auto c = [](auto x ...) { };
auto c = [](auto x ...) { }; // { dg-warning "omission of ',' before varargs '...' is deprecated" "" { target c++26 } }

View file

@ -4,7 +4,7 @@
template <int...> struct seq {};
template <bool> struct S {
template <typename Args>
constexpr static void call(Args&&...) {}
constexpr static void call(Args&&...) {} // { dg-warning "omission of ',' before varargs '...' is deprecated" "" { target c++26 } }
};
template <int ...Idx,typename ...Args>

View file

@ -24,7 +24,7 @@ void S::f12(this S s = {}) {} // { dg-error "an explicit object parameter may no
struct S0 {
template<typename Selves>
void f(this Selves...) {}
void f(this Selves...) {} // { dg-warning "omission of ',' before varargs '...' is deprecated" "" { target c++26 } }
template<typename Selves>
void g(this Selves... selves) {} // { dg-error "an explicit object parameter cannot be a function parameter pack" }
@ -37,7 +37,7 @@ struct S0 {
void k(this Selves...) {} // { dg-error "an explicit object parameter cannot be a function parameter pack" }
template<typename Selves>
void fd(this Selves...);
void fd(this Selves...); // { dg-warning "omission of ',' before varargs '...' is deprecated" "" { target c++26 } }
template<typename Selves>
void gd(this Selves... selves); // { dg-error "an explicit object parameter cannot be a function parameter pack" }
@ -52,7 +52,7 @@ struct S0 {
struct S1 {
template<typename Selves>
void f(this Selves&...) {}
void f(this Selves&...) {} // { dg-warning "omission of ',' before varargs '...' is deprecated" "" { target c++26 } }
template<typename Selves>
void g(this Selves&... selves) {} // { dg-error "an explicit object parameter cannot be a function parameter pack" }
@ -65,7 +65,7 @@ struct S1 {
void k(this Selves&...) {} // { dg-error "an explicit object parameter cannot be a function parameter pack" }
template<typename Selves>
void fd(this Selves&...);
void fd(this Selves&...); // { dg-warning "omission of ',' before varargs '...' is deprecated" "" { target c++26 } }
template<typename Selves>
void gd(this Selves&... selves); // { dg-error "an explicit object parameter cannot be a function parameter pack" }
@ -80,7 +80,7 @@ struct S1 {
struct S2 {
template<typename Selves>
void f(this Selves&&...) {}
void f(this Selves&&...) {} // { dg-warning "omission of ',' before varargs '...' is deprecated" "" { target c++26 } }
template<typename Selves>
void g(this Selves&&... selves) {} // { dg-error "an explicit object parameter cannot be a function parameter pack" }
@ -93,7 +93,7 @@ struct S2 {
void k(this Selves&&...) {} // { dg-error "an explicit object parameter cannot be a function parameter pack" }
template<typename Selves>
void fd(this Selves&&...);
void fd(this Selves&&...); // { dg-warning "omission of ',' before varargs '...' is deprecated" "" { target c++26 } }
template<typename Selves>
void gd(this Selves&&... selves); // { dg-error "an explicit object parameter cannot be a function parameter pack" }
@ -108,7 +108,7 @@ struct S2 {
struct S3 {
template<typename Selves>
void f(this Selves const&...) {}
void f(this Selves const&...) {} // { dg-warning "omission of ',' before varargs '...' is deprecated" "" { target c++26 } }
template<typename Selves>
void g(this Selves const&... selves) {} // { dg-error "an explicit object parameter cannot be a function parameter pack" }
@ -121,7 +121,7 @@ struct S3 {
void k(this Selves const&...) {} // { dg-error "an explicit object parameter cannot be a function parameter pack" }
template<typename Selves>
void fd(this Selves const&...);
void fd(this Selves const&...); // { dg-warning "omission of ',' before varargs '...' is deprecated" "" { target c++26 } }
template<typename Selves>
void gd(this Selves const&... selves); // { dg-error "an explicit object parameter cannot be a function parameter pack" }
@ -136,7 +136,7 @@ struct S3 {
struct S4 {
template<typename Selves>
void f(this Selves const&&...) {}
void f(this Selves const&&...) {} // { dg-warning "omission of ',' before varargs '...' is deprecated" "" { target c++26 } }
template<typename Selves>
void g(this Selves const&&... selves) {} // { dg-error "an explicit object parameter cannot be a function parameter pack" }
@ -149,7 +149,7 @@ struct S4 {
void k(this Selves const&&...) {} // { dg-error "an explicit object parameter cannot be a function parameter pack" }
template<typename Selves>
void fd(this Selves const&&...);
void fd(this Selves const&&...); // { dg-warning "omission of ',' before varargs '...' is deprecated" "" { target c++26 } }
template<typename Selves>
void gd(this Selves const&&... selves); // { dg-error "an explicit object parameter cannot be a function parameter pack" }

View file

@ -0,0 +1,18 @@
// P3176R1 - The Oxford variadic comma
// { dg-do compile { target c++11 } }
void f1 (int...); // { dg-warning "omission of ',' before varargs '...' is deprecated in" "" { target c++26 } }
#if __cplusplus >= 202002L
void f2 (auto...);
void f3 (auto......); // { dg-warning "omission of ',' before varargs '...' is deprecated in" "" { target c++26 } }
#endif
template <typename ...T>
void f4 (T......); // { dg-warning "omission of ',' before varargs '...' is deprecated in" "" { target c++26 } }
template <typename ...T>
void f5 (T...);
template <typename ...T>
void f6 (T..., int...); // { dg-warning "omission of ',' before varargs '...' is deprecated in" "" { target c++26 } }
void
f7 (char...) // { dg-warning "omission of ',' before varargs '...' is deprecated in" "" { target c++26 } }
{
}

View file

@ -0,0 +1,19 @@
// P3176R1 - The Oxford variadic comma
// { dg-do compile { target c++11 } }
// { dg-additional-options "-Wdeprecated" }
void f1 (int...); // { dg-warning "omission of ',' before varargs '...' is deprecated in" }
#if __cplusplus >= 202002L
void f2 (auto...);
void f3 (auto......); // { dg-warning "omission of ',' before varargs '...' is deprecated in" "" { target c++20 } }
#endif
template <typename ...T>
void f4 (T......); // { dg-warning "omission of ',' before varargs '...' is deprecated in" }
template <typename ...T>
void f5 (T...);
template <typename ...T>
void f6 (T..., int...); // { dg-warning "omission of ',' before varargs '...' is deprecated in" }
void
f7 (char...) // { dg-warning "omission of ',' before varargs '...' is deprecated in" }
{
}

View file

@ -0,0 +1,5 @@
// P3176R1 - The Oxford variadic comma
// { dg-do compile { target c++11 } }
// { dg-additional-options "-Wno-deprecated-variadic-comma-omission" }
#include "variadic-comma1.C"

View file

@ -0,0 +1,5 @@
// P3176R1 - The Oxford variadic comma
// { dg-do compile { target c++11 } }
// { dg-additional-options "-Wno-deprecated" }
#include "variadic-comma1.C"

View file

@ -0,0 +1,19 @@
// P3176R1 - The Oxford variadic comma
// { dg-do compile { target c++11 } }
// { dg-additional-options "-Wdeprecated-variadic-comma-omission" }
void f1 (int...); // { dg-warning "omission of ',' before varargs '...' is deprecated in" }
#if __cplusplus >= 202002L
void f2 (auto...);
void f3 (auto......); // { dg-warning "omission of ',' before varargs '...' is deprecated in" "" { target c++20 } }
#endif
template <typename ...T>
void f4 (T......); // { dg-warning "omission of ',' before varargs '...' is deprecated in" }
template <typename ...T>
void f5 (T...);
template <typename ...T>
void f6 (T..., int...); // { dg-warning "omission of ',' before varargs '...' is deprecated in" }
void
f7 (char...) // { dg-warning "omission of ',' before varargs '...' is deprecated in" }
{
}

View file

@ -4,7 +4,7 @@
void sink(...);
template <int... args> void f()
{
sink ([] <int T> (int...) { return 1; }
sink ([] <int T> (int...) { return 1; } // { dg-warning "omission of ',' before varargs '...' is deprecated" "" { target c++26 } }
.operator()<args>(args...)...); // { dg-warning "-Wmissing-template-keyword" }
} // { dg-prune-output {expected '\)'} }

View file

@ -5,7 +5,7 @@
template <int N>
struct T
{
void foo (char const * ...) __attribute__ ((format (printf,2,3)));
void foo (char const * ...) __attribute__ ((format (printf,2,3))); // { dg-warning "omission of ',' before varargs '...' is deprecated" "" { target c++26 } }
};
template struct T<3>;

View file

@ -6,7 +6,7 @@
// Subject: bug report
// Date: Wed, 27 Jan 1993 16:37:30 -0500
extern "C" int printf(const char* ...);
extern "C" int printf(const char* ...); // { dg-warning "omission of ',' before varargs '...' is deprecated" "" { target c++26 } }
int delete_counter = -1;

View file

@ -4,7 +4,7 @@
void *ptr1, *ptr2;
int fail = 0;
extern "C" int printf(const char *...);
extern "C" int printf(const char *, ...);
class RWSlist { };

View file

@ -305,7 +305,7 @@ class ostream : public ios
ostream& seekp(streampos);
ostream& seekp(streamoff, _seek_dir);
streampos tellp();
ostream& form(const char *format ...);
ostream& form(const char *format ...); // { dg-warning "omission of ',' before varargs '...' is deprecated" "" { target c++26 } }
ostream& vform(const char *format, char* args);
};
@ -460,7 +460,7 @@ class iostream : public ios {
{ return ((ostream*)this)->write((char*)s, n); }
ostream& write(const void *s, int n)
{ return ((ostream*)this)->write((char*)s, n); }
ostream& form(const char *format ...);
ostream& form(const char *format ...); // { dg-warning "omission of ',' before varargs '...' is deprecated" "" { target c++26 } }
ostream& vform(const char *format, char* args)
{ return ((ostream*)this)->vform(format, args); }
ostream& seekp(streampos pos) { return ((ostream*)this)->seekp(pos); }

View file

@ -94,7 +94,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
using __vararg = false_type; \
}; \
template<typename _Res, typename _Class, typename... _ArgTypes> \
struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes... ...) _CV _REF> \
struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes..., ...) _CV _REF> \
: _Mem_fn_traits_base<_Res, _CV _Class, _ArgTypes...> \
{ \
using __vararg = true_type; \
@ -145,7 +145,8 @@ _GLIBCXX_MEM_FN_TRAITS(&& noexcept, false_type, true_type)
/// Retrieve the result type for a varargs function type.
template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
struct _Weak_result_type_impl<_Res(_ArgTypes......) _GLIBCXX_NOEXCEPT_QUAL>
struct _Weak_result_type_impl<_Res(_ArgTypes...,
...) _GLIBCXX_NOEXCEPT_QUAL>
{ typedef _Res result_type; };
/// Retrieve the result type for a function pointer.
@ -156,7 +157,7 @@ _GLIBCXX_MEM_FN_TRAITS(&& noexcept, false_type, true_type)
/// Retrieve the result type for a varargs function pointer.
template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
struct
_Weak_result_type_impl<_Res(*)(_ArgTypes......) _GLIBCXX_NOEXCEPT_QUAL>
_Weak_result_type_impl<_Res(*)(_ArgTypes..., ...) _GLIBCXX_NOEXCEPT_QUAL>
{ typedef _Res result_type; };
// Let _Weak_result_type_impl perform the real work.

View file

@ -841,7 +841,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
};
template<typename _Ret, typename... _Args, typename... _BoundArgs>
struct _Bind_check_arity<_Ret (*)(_Args......), _BoundArgs...>
struct _Bind_check_arity<_Ret (*)(_Args..., ...), _BoundArgs...>
{
static_assert(sizeof...(_BoundArgs) >= sizeof...(_Args),
"Wrong number of arguments for function");

View file

@ -235,25 +235,24 @@ namespace tr1
struct is_function<_Res(_ArgTypes...)>
: public true_type { };
template<typename _Res, typename... _ArgTypes>
struct is_function<_Res(_ArgTypes......)>
: public true_type { };
struct is_function<_Res(_ArgTypes..., ...)> : public true_type { };
template<typename _Res, typename... _ArgTypes>
struct is_function<_Res(_ArgTypes...) const>
: public true_type { };
template<typename _Res, typename... _ArgTypes>
struct is_function<_Res(_ArgTypes......) const>
struct is_function<_Res(_ArgTypes..., ...) const>
: public true_type { };
template<typename _Res, typename... _ArgTypes>
struct is_function<_Res(_ArgTypes...) volatile>
: public true_type { };
template<typename _Res, typename... _ArgTypes>
struct is_function<_Res(_ArgTypes......) volatile>
struct is_function<_Res(_ArgTypes..., ...) volatile>
: public true_type { };
template<typename _Res, typename... _ArgTypes>
struct is_function<_Res(_ArgTypes...) const volatile>
: public true_type { };
template<typename _Res, typename... _ArgTypes>
struct is_function<_Res(_ArgTypes......) const volatile>
struct is_function<_Res(_ArgTypes..., ...) const volatile>
: public true_type { };
// composite type traits [4.5.2].