static bool
builtin_function_validate_nargs (location_t loc, tree fndecl, int nargs,
- int required)
+ int required, bool complain)
{
if (nargs < required)
{
- error_at (loc, "too few arguments to function %qE", fndecl);
+ if (complain)
+ error_at (loc, "too few arguments to function %qE", fndecl);
return false;
}
else if (nargs > required)
{
- error_at (loc, "too many arguments to function %qE", fndecl);
+ if (complain)
+ error_at (loc, "too many arguments to function %qE", fndecl);
return false;
}
return true;
bool
check_builtin_function_arguments (location_t loc, vec<location_t> arg_loc,
- tree fndecl, tree orig_fndecl,
- int nargs, tree *args)
+ tree fndecl, tree orig_fndecl, int nargs,
+ tree *args, bool complain)
{
if (!fndecl_built_in_p (fndecl))
return true;
if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
return (!targetm.check_builtin_call
- || targetm.check_builtin_call (loc, arg_loc, fndecl,
- orig_fndecl, nargs, args));
+ || targetm.check_builtin_call (loc, arg_loc, fndecl, orig_fndecl,
+ nargs, args, complain));
if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_FRONTEND)
return true;
case BUILT_IN_ALLOCA_WITH_ALIGN_AND_MAX:
if (!tree_fits_uhwi_p (args[2]))
{
- error_at (ARG_LOCATION (2),
- "third argument to function %qE must be a constant integer",
- fndecl);
+ if (complain)
+ error_at (
+ ARG_LOCATION (2),
+ "third argument to function %qE must be a constant integer",
+ fndecl);
return false;
}
/* fall through */
/* Reject invalid alignments. */
if (align < BITS_PER_UNIT || maxalign < align)
{
- error_at (ARG_LOCATION (1),
- "second argument to function %qE must be a constant "
- "integer power of 2 between %qi and %qu bits",
- fndecl, BITS_PER_UNIT, maxalign);
+ if (complain)
+ error_at (ARG_LOCATION (1),
+ "second argument to function %qE must be a constant "
+ "integer power of 2 between %qi and %qu bits",
+ fndecl, BITS_PER_UNIT, maxalign);
return false;
}
return true;
}
case BUILT_IN_CONSTANT_P:
- return builtin_function_validate_nargs (loc, fndecl, nargs, 1);
+ return builtin_function_validate_nargs (loc, fndecl, nargs, 1, complain);
case BUILT_IN_ISFINITE:
case BUILT_IN_ISINF:
case BUILT_IN_ISNORMAL:
case BUILT_IN_ISSIGNALING:
case BUILT_IN_SIGNBIT:
- if (builtin_function_validate_nargs (loc, fndecl, nargs, 1))
+ if (builtin_function_validate_nargs (loc, fndecl, nargs, 1, complain))
{
if (TREE_CODE (TREE_TYPE (args[0])) != REAL_TYPE)
{
- error_at (ARG_LOCATION (0), "non-floating-point argument in "
- "call to function %qE", fndecl);
+ if (complain)
+ error_at (ARG_LOCATION (0),
+ "non-floating-point argument in "
+ "call to function %qE",
+ fndecl);
return false;
}
return true;
case BUILT_IN_ISLESSGREATER:
case BUILT_IN_ISUNORDERED:
case BUILT_IN_ISEQSIG:
- if (builtin_function_validate_nargs (loc, fndecl, nargs, 2))
+ if (builtin_function_validate_nargs (loc, fndecl, nargs, 2, complain))
{
enum tree_code code0, code1;
code0 = TREE_CODE (TREE_TYPE (args[0]));
|| ((code0 == INTEGER_TYPE || code0 == BITINT_TYPE)
&& code1 == REAL_TYPE)))
{
- error_at (loc, "non-floating-point arguments in call to "
- "function %qE", fndecl);
+ if (complain)
+ error_at (loc,
+ "non-floating-point arguments in call to "
+ "function %qE",
+ fndecl);
return false;
}
return true;
return false;
case BUILT_IN_FPCLASSIFY:
- if (builtin_function_validate_nargs (loc, fndecl, nargs, 6))
+ if (builtin_function_validate_nargs (loc, fndecl, nargs, 6, complain))
{
for (unsigned int i = 0; i < 5; i++)
if (TREE_CODE (args[i]) != INTEGER_CST)
{
- error_at (ARG_LOCATION (i), "non-const integer argument %u in "
- "call to function %qE", i + 1, fndecl);
+ if (complain)
+ error_at (ARG_LOCATION (i),
+ "non-const integer argument %u in "
+ "call to function %qE",
+ i + 1, fndecl);
return false;
}
if (TREE_CODE (TREE_TYPE (args[5])) != REAL_TYPE)
{
- error_at (ARG_LOCATION (5), "non-floating-point argument in "
- "call to function %qE", fndecl);
+ if (complain)
+ error_at (ARG_LOCATION (5),
+ "non-floating-point argument in "
+ "call to function %qE",
+ fndecl);
return false;
}
return true;
return false;
case BUILT_IN_ASSUME_ALIGNED:
- if (builtin_function_validate_nargs (loc, fndecl, nargs, 2 + (nargs > 2)))
+ if (builtin_function_validate_nargs (loc, fndecl, nargs, 2 + (nargs > 2),
+ complain))
{
if (nargs >= 3
&& TREE_CODE (TREE_TYPE (args[2])) != INTEGER_TYPE
&& TREE_CODE (TREE_TYPE (args[2])) != BITINT_TYPE)
{
- error_at (ARG_LOCATION (2), "non-integer argument 3 in call to "
- "function %qE", fndecl);
+ if (complain)
+ error_at (ARG_LOCATION (2),
+ "non-integer argument 3 in call to "
+ "function %qE",
+ fndecl);
return false;
}
return true;
case BUILT_IN_ADD_OVERFLOW:
case BUILT_IN_SUB_OVERFLOW:
case BUILT_IN_MUL_OVERFLOW:
- if (builtin_function_validate_nargs (loc, fndecl, nargs, 3))
+ if (builtin_function_validate_nargs (loc, fndecl, nargs, 3, complain))
{
unsigned i;
for (i = 0; i < 2; i++)
if (!INTEGRAL_TYPE_P (TREE_TYPE (args[i])))
{
- error_at (ARG_LOCATION (i), "argument %u in call to function "
- "%qE does not have integral type", i + 1, fndecl);
+ if (complain)
+ error_at (ARG_LOCATION (i),
+ "argument %u in call to function "
+ "%qE does not have integral type",
+ i + 1, fndecl);
return false;
}
if (TREE_CODE (TREE_TYPE (args[2])) != POINTER_TYPE
|| !INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (args[2]))))
{
- error_at (ARG_LOCATION (2), "argument 3 in call to function %qE "
- "does not have pointer to integral type", fndecl);
+ if (complain)
+ error_at (ARG_LOCATION (2),
+ "argument 3 in call to function %qE "
+ "does not have pointer to integral type",
+ fndecl);
return false;
}
else if (TREE_CODE (TREE_TYPE (TREE_TYPE (args[2]))) == ENUMERAL_TYPE)
{
- error_at (ARG_LOCATION (2), "argument 3 in call to function %qE "
- "has pointer to enumerated type", fndecl);
+ if (complain)
+ error_at (ARG_LOCATION (2),
+ "argument 3 in call to function %qE "
+ "has pointer to enumerated type",
+ fndecl);
return false;
}
else if (TREE_CODE (TREE_TYPE (TREE_TYPE (args[2]))) == BOOLEAN_TYPE)
{
- error_at (ARG_LOCATION (2), "argument 3 in call to function %qE "
- "has pointer to boolean type", fndecl);
+ if (complain)
+ error_at (ARG_LOCATION (2),
+ "argument 3 in call to function %qE "
+ "has pointer to boolean type",
+ fndecl);
return false;
}
else if (TYPE_READONLY (TREE_TYPE (TREE_TYPE (args[2]))))
{
- error_at (ARG_LOCATION (2), "argument %u in call to function %qE "
- "has pointer to %qs type (%qT)", 3, fndecl, "const",
- TREE_TYPE (args[2]));
+ if (complain)
+ error_at (ARG_LOCATION (2),
+ "argument %u in call to function %qE "
+ "has pointer to %qs type (%qT)",
+ 3, fndecl, "const", TREE_TYPE (args[2]));
return false;
}
else if (TYPE_ATOMIC (TREE_TYPE (TREE_TYPE (args[2]))))
{
- error_at (ARG_LOCATION (2), "argument %u in call to function %qE "
- "has pointer to %qs type (%qT)", 3, fndecl,
- "_Atomic", TREE_TYPE (args[2]));
+ if (complain)
+ error_at (ARG_LOCATION (2),
+ "argument %u in call to function %qE "
+ "has pointer to %qs type (%qT)",
+ 3, fndecl, "_Atomic", TREE_TYPE (args[2]));
return false;
}
return true;
case BUILT_IN_ADD_OVERFLOW_P:
case BUILT_IN_SUB_OVERFLOW_P:
case BUILT_IN_MUL_OVERFLOW_P:
- if (builtin_function_validate_nargs (loc, fndecl, nargs, 3))
+ if (builtin_function_validate_nargs (loc, fndecl, nargs, 3, complain))
{
unsigned i;
for (i = 0; i < 3; i++)
if (!INTEGRAL_TYPE_P (TREE_TYPE (args[i])))
{
- error_at (ARG_LOCATION (i), "argument %u in call to function "
- "%qE does not have integral type", i + 1, fndecl);
+ if (complain)
+ error_at (ARG_LOCATION (i),
+ "argument %u in call to function "
+ "%qE does not have integral type",
+ i + 1, fndecl);
return false;
}
if (TREE_CODE (TREE_TYPE (args[2])) == ENUMERAL_TYPE)
{
- error_at (ARG_LOCATION (2), "argument %u in call to function "
- "%qE has enumerated type", 3, fndecl);
+ if (complain)
+ error_at (ARG_LOCATION (2),
+ "argument %u in call to function "
+ "%qE has enumerated type",
+ 3, fndecl);
return false;
}
else if (TREE_CODE (TREE_TYPE (args[2])) == BOOLEAN_TYPE)
{
- error_at (ARG_LOCATION (2), "argument %u in call to function "
- "%qE has boolean type", 3, fndecl);
+ if (complain)
+ error_at (ARG_LOCATION (2),
+ "argument %u in call to function "
+ "%qE has boolean type",
+ 3, fndecl);
return false;
}
return true;
return false;
case BUILT_IN_CLEAR_PADDING:
- if (builtin_function_validate_nargs (loc, fndecl, nargs, 1))
+ if (builtin_function_validate_nargs (loc, fndecl, nargs, 1, complain))
{
if (!POINTER_TYPE_P (TREE_TYPE (args[0])))
{
- error_at (ARG_LOCATION (0), "argument %u in call to function "
- "%qE does not have pointer type", 1, fndecl);
+ if (complain)
+ error_at (ARG_LOCATION (0),
+ "argument %u in call to function "
+ "%qE does not have pointer type",
+ 1, fndecl);
return false;
}
else if (!COMPLETE_TYPE_P (TREE_TYPE (TREE_TYPE (args[0]))))
{
- error_at (ARG_LOCATION (0), "argument %u in call to function "
- "%qE points to incomplete type", 1, fndecl);
+ if (complain)
+ error_at (ARG_LOCATION (0),
+ "argument %u in call to function "
+ "%qE points to incomplete type",
+ 1, fndecl);
return false;
}
else if (TYPE_READONLY (TREE_TYPE (TREE_TYPE (args[0]))))
{
- error_at (ARG_LOCATION (0), "argument %u in call to function %qE "
- "has pointer to %qs type (%qT)", 1, fndecl, "const",
- TREE_TYPE (args[0]));
+ if (complain)
+ error_at (ARG_LOCATION (0),
+ "argument %u in call to function %qE "
+ "has pointer to %qs type (%qT)",
+ 1, fndecl, "const", TREE_TYPE (args[0]));
return false;
}
else if (TYPE_ATOMIC (TREE_TYPE (TREE_TYPE (args[0]))))
{
- error_at (ARG_LOCATION (0), "argument %u in call to function %qE "
- "has pointer to %qs type (%qT)", 1, fndecl,
- "_Atomic", TREE_TYPE (args[0]));
+ if (complain)
+ error_at (ARG_LOCATION (0),
+ "argument %u in call to function %qE "
+ "has pointer to %qs type (%qT)",
+ 1, fndecl, "_Atomic", TREE_TYPE (args[0]));
return false;
}
return true;
{
if (!INTEGRAL_TYPE_P (TREE_TYPE (args[1])))
{
- error_at (ARG_LOCATION (1), "argument %u in call to function "
- "%qE does not have integral type", 2, fndecl);
+ if (complain)
+ error_at (ARG_LOCATION (1),
+ "argument %u in call to function "
+ "%qE does not have integral type",
+ 2, fndecl);
return false;
}
if ((TYPE_PRECISION (TREE_TYPE (args[1]))
== TYPE_PRECISION (integer_type_node)
&& TYPE_UNSIGNED (TREE_TYPE (args[1]))))
{
- error_at (ARG_LOCATION (1), "argument %u in call to function "
- "%qE does not have %<int%> type", 2, fndecl);
+ if (complain)
+ error_at (ARG_LOCATION (1),
+ "argument %u in call to function "
+ "%qE does not have %<int%> type",
+ 2, fndecl);
return false;
}
}
- else if (!builtin_function_validate_nargs (loc, fndecl, nargs, 1))
+ else if (!builtin_function_validate_nargs (loc, fndecl, nargs, 1,
+ complain))
return false;
if (!INTEGRAL_TYPE_P (TREE_TYPE (args[0])))
{
- error_at (ARG_LOCATION (0), "argument %u in call to function "
- "%qE does not have integral type", 1, fndecl);
+ if (complain)
+ error_at (ARG_LOCATION (0),
+ "argument %u in call to function "
+ "%qE does not have integral type",
+ 1, fndecl);
return false;
}
if (TREE_CODE (TREE_TYPE (args[0])) == ENUMERAL_TYPE)
{
- error_at (ARG_LOCATION (0), "argument %u in call to function "
- "%qE has enumerated type", 1, fndecl);
+ if (complain)
+ error_at (ARG_LOCATION (0),
+ "argument %u in call to function "
+ "%qE has enumerated type",
+ 1, fndecl);
return false;
}
if (TREE_CODE (TREE_TYPE (args[0])) == BOOLEAN_TYPE)
{
- error_at (ARG_LOCATION (0), "argument %u in call to function "
- "%qE has boolean type", 1, fndecl);
+ if (complain)
+ error_at (ARG_LOCATION (0),
+ "argument %u in call to function "
+ "%qE has boolean type",
+ 1, fndecl);
return false;
}
if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FFSG
{
if (TYPE_UNSIGNED (TREE_TYPE (args[0])))
{
- error_at (ARG_LOCATION (0), "argument 1 in call to function "
- "%qE has unsigned type", fndecl);
+ if (complain)
+ error_at (ARG_LOCATION (0),
+ "argument 1 in call to function "
+ "%qE has unsigned type",
+ fndecl);
return false;
}
}
else if (!TYPE_UNSIGNED (TREE_TYPE (args[0])))
{
- error_at (ARG_LOCATION (0), "argument 1 in call to function "
- "%qE has signed type", fndecl);
+ if (complain)
+ error_at (ARG_LOCATION (0),
+ "argument 1 in call to function "
+ "%qE has signed type",
+ fndecl);
return false;
}
return true;
the size is too large; 0 if the argument type is a pointer or the
size if it is integral. */
static enum built_in_function
-speculation_safe_value_resolve_call (tree function, vec<tree, va_gc> *params)
+speculation_safe_value_resolve_call (tree function, vec<tree, va_gc> *params,
+ bool complain)
{
/* Type of the argument. */
tree type;
if (vec_safe_is_empty (params))
{
- error ("too few arguments to function %qE", function);
+ if (complain)
+ error ("too few arguments to function %qE", function);
return BUILT_IN_NONE;
}
incompatible:
/* Issue the diagnostic only if the argument is valid, otherwise
it would be redundant at best and could be misleading. */
- if (type != error_mark_node)
+ if (type != error_mark_node && complain)
error ("operand type %qT is incompatible with argument %d of %qE",
type, 1, function);
argument, if present, must be type compatible with the first. */
static bool
speculation_safe_value_resolve_params (location_t loc, tree orig_function,
- vec<tree, va_gc> *params)
+ vec<tree, va_gc> *params, bool complain)
{
tree val;
if (params->length () == 0)
{
- error_at (loc, "too few arguments to function %qE", orig_function);
+ if (complain)
+ error_at (loc, "too few arguments to function %qE", orig_function);
return false;
}
else if (params->length () > 2)
{
- error_at (loc, "too many arguments to function %qE", orig_function);
+ if (complain)
+ error_at (loc, "too many arguments to function %qE", orig_function);
return false;
}
if (!(TREE_CODE (TREE_TYPE (val)) == POINTER_TYPE
|| TREE_CODE (TREE_TYPE (val)) == INTEGER_TYPE))
{
- error_at (loc,
- "expecting argument of type pointer or of type integer "
- "for argument 1");
+ if (complain)
+ error_at (loc, "expecting argument of type pointer or of type integer "
+ "for argument 1");
return false;
}
(*params)[0] = val;
if (!(TREE_TYPE (val) == TREE_TYPE (val2)
|| useless_type_conversion_p (TREE_TYPE (val), TREE_TYPE (val2))))
{
- error_at (loc, "both arguments must be compatible");
+ if (complain)
+ error_at (loc, "both arguments must be compatible");
return false;
}
(*params)[1] = val2;
static int
sync_resolve_size (tree function, vec<tree, va_gc> *params, bool fetch,
- bool orig_format)
+ bool orig_format, bool complain)
{
/* Type of the argument. */
tree argtype;
if (vec_safe_is_empty (params))
{
- error ("too few arguments to function %qE", function);
+ if (complain)
+ error ("too few arguments to function %qE", function);
return 0;
}
incompatible:
/* Issue the diagnostic only if the argument is valid, otherwise
it would be redundant at best and could be misleading. */
- if (argtype != error_mark_node)
+ if (argtype != error_mark_node && complain)
error ("operand type %qT is incompatible with argument %d of %qE",
argtype, 1, function);
return 0;
static bool
sync_resolve_params (location_t loc, tree orig_function, tree function,
- vec<tree, va_gc> *params, bool orig_format)
+ vec<tree, va_gc> *params, bool orig_format, bool complain)
{
function_args_iterator iter;
tree ptype;
++parmnum;
if (params->length () <= parmnum)
{
- error_at (loc, "too few arguments to function %qE", orig_function);
+ if (complain)
+ error_at (loc, "too few arguments to function %qE", orig_function);
return false;
}
/* __atomic routines are not variadic. */
if (!orig_format && params->length () != parmnum + 1)
{
- error_at (loc, "too many arguments to function %qE", orig_function);
+ if (complain)
+ error_at (loc, "too many arguments to function %qE", orig_function);
return false;
}
static int
get_atomic_generic_size (location_t loc, tree function,
- vec<tree, va_gc> *params)
+ vec<tree, va_gc> *params, bool complain)
{
unsigned int n_param;
unsigned int n_model;
if (vec_safe_length (params) != n_param)
{
- error_at (loc, "incorrect number of arguments to function %qE", function);
+ if (complain)
+ error_at (loc, "incorrect number of arguments to function %qE",
+ function);
return 0;
}
}
if (TREE_CODE (type_0) != POINTER_TYPE || VOID_TYPE_P (TREE_TYPE (type_0)))
{
- error_at (loc, "argument 1 of %qE must be a non-void pointer type",
- function);
+ if (complain)
+ error_at (loc, "argument 1 of %qE must be a non-void pointer type",
+ function);
return 0;
}
if (!COMPLETE_TYPE_P (TREE_TYPE (type_0)))
{
- error_at (loc, "argument 1 of %qE must be a pointer to a complete type",
- function);
+ if (complain)
+ error_at (loc, "argument 1 of %qE must be a pointer to a complete type",
+ function);
return 0;
}
/* Types must be compile time constant sizes. */
if (!tree_fits_uhwi_p ((TYPE_SIZE_UNIT (TREE_TYPE (type_0)))))
{
- error_at (loc,
- "argument 1 of %qE must be a pointer to a constant size type",
- function);
+ if (complain)
+ error_at (loc,
+ "argument 1 of %qE must be a pointer to a constant size type",
+ function);
return 0;
}
/* Zero size objects are not allowed. */
if (size_0 == 0)
{
- error_at (loc,
- "argument 1 of %qE must be a pointer to a nonzero size object",
- function);
+ if (complain)
+ error_at (
+ loc, "argument 1 of %qE must be a pointer to a nonzero size object",
+ function);
return 0;
}
}
if (!POINTER_TYPE_P (type))
{
- error_at (loc, "argument %d of %qE must be a pointer type", x + 1,
- function);
+ if (complain)
+ error_at (loc, "argument %d of %qE must be a pointer type", x + 1,
+ function);
return 0;
}
else if (TYPE_SIZE_UNIT (TREE_TYPE (type))
&& TREE_CODE ((TYPE_SIZE_UNIT (TREE_TYPE (type))))
!= INTEGER_CST)
{
- error_at (loc, "argument %d of %qE must be a pointer to a constant "
- "size type", x + 1, function);
+ if (complain)
+ error_at (loc,
+ "argument %d of %qE must be a pointer to a constant "
+ "size type",
+ x + 1, function);
return 0;
}
else if (FUNCTION_POINTER_TYPE_P (type))
{
- error_at (loc, "argument %d of %qE must not be a pointer to a "
- "function", x + 1, function);
+ if (complain)
+ error_at (loc,
+ "argument %d of %qE must not be a pointer to a "
+ "function",
+ x + 1, function);
return 0;
}
tree type_size = TYPE_SIZE_UNIT (TREE_TYPE (type));
size = type_size ? tree_to_uhwi (type_size) : 0;
if (size != size_0)
{
- error_at (loc, "size mismatch in argument %d of %qE", x + 1,
- function);
+ if (complain)
+ error_at (loc, "size mismatch in argument %d of %qE", x + 1,
+ function);
return 0;
}
{
if (c_dialect_cxx ())
{
- error_at (loc, "argument %d of %qE must not be a pointer to "
- "a %<const%> type", x + 1, function);
+ if (complain)
+ error_at (loc,
+ "argument %d of %qE must not be a pointer to "
+ "a %<const%> type",
+ x + 1, function);
return 0;
}
else
{
if (c_dialect_cxx ())
{
- error_at (loc, "argument %d of %qE must not be a pointer to "
- "a %<volatile%> type", x + 1, function);
+ if (complain)
+ error_at (loc,
+ "argument %d of %qE must not be a pointer to "
+ "a %<volatile%> type",
+ x + 1, function);
return 0;
}
else
tree p = (*params)[x];
if (!INTEGRAL_TYPE_P (TREE_TYPE (p)))
{
- error_at (loc, "non-integer memory model argument %d of %qE", x + 1,
- function);
+ if (complain)
+ error_at (loc, "non-integer memory model argument %d of %qE", x + 1,
+ function);
return 0;
}
p = fold_for_warn (p);
bits will be checked later during expansion in target specific
way. */
if (memmodel_base (TREE_INT_CST_LOW (p)) >= MEMMODEL_LAST)
- warning_at (loc, OPT_Winvalid_memory_model,
- "invalid memory model argument %d of %qE", x + 1,
- function);
+ {
+ if (complain)
+ warning_at (loc, OPT_Winvalid_memory_model,
+ "invalid memory model argument %d of %qE", x + 1,
+ function);
+ else
+ return 0;
+ }
}
}
NEW_RETURN is set to the return value the result is copied into. */
static bool
resolve_overloaded_atomic_exchange (location_t loc, tree function,
- vec<tree, va_gc> *params, tree *new_return)
+ vec<tree, va_gc> *params, tree *new_return,
+ bool complain)
{
tree p0, p1, p2, p3;
tree I_type, I_type_ptr;
- int n = get_atomic_generic_size (loc, function, params);
+ int n = get_atomic_generic_size (loc, function, params, complain);
/* Size of 0 is an error condition. */
if (n == 0)
return false;
}
-
/* This will process an __atomic_compare_exchange function call, determine
whether it needs to be mapped to the _N variation, or turned into a lib call.
LOC is the location of the builtin call.
static bool
resolve_overloaded_atomic_compare_exchange (location_t loc, tree function,
vec<tree, va_gc> *params,
- tree *new_return)
+ tree *new_return, bool complain)
{
tree p0, p1, p2;
tree I_type, I_type_ptr;
- int n = get_atomic_generic_size (loc, function, params);
+ int n = get_atomic_generic_size (loc, function, params, complain);
/* Size of 0 is an error condition. */
if (n == 0)
return false;
}
-
/* This will process an __atomic_load function call, determine whether it
needs to be mapped to the _N variation, or turned into a library call.
LOC is the location of the builtin call.
static bool
resolve_overloaded_atomic_load (location_t loc, tree function,
- vec<tree, va_gc> *params, tree *new_return)
+ vec<tree, va_gc> *params, tree *new_return,
+ bool complain)
{
tree p0, p1, p2;
tree I_type, I_type_ptr;
- int n = get_atomic_generic_size (loc, function, params);
+ int n = get_atomic_generic_size (loc, function, params, complain);
/* Size of 0 is an error condition. */
if (n == 0)
return false;
}
-
/* This will process an __atomic_store function call, determine whether it
needs to be mapped to the _N variation, or turned into a library call.
LOC is the location of the builtin call.
static bool
resolve_overloaded_atomic_store (location_t loc, tree function,
- vec<tree, va_gc> *params, tree *new_return)
+ vec<tree, va_gc> *params, tree *new_return,
+ bool complain)
{
tree p0, p1;
tree I_type, I_type_ptr;
- int n = get_atomic_generic_size (loc, function, params);
+ int n = get_atomic_generic_size (loc, function, params, complain);
/* Size of 0 is an error condition. */
if (n == 0)
return false;
}
-
/* Emit __atomic*fetch* on _BitInt which doesn't have a size of
1, 2, 4, 8 or 16 bytes using __atomic_compare_exchange loop.
ORIG_CODE is the DECL_FUNCTION_CODE of ORIG_FUNCTION and
tree
resolve_overloaded_builtin (location_t loc, tree function,
- vec<tree, va_gc> *params)
+ vec<tree, va_gc> *params, bool complain)
{
/* Is function one of the _FETCH_OP_ or _OP_FETCH_ built-ins?
Those are not valid to call with a pointer to _Bool (or C++ bool)
break;
case BUILT_IN_MD:
if (targetm.resolve_overloaded_builtin)
- return targetm.resolve_overloaded_builtin (loc, function, params);
+ return targetm.resolve_overloaded_builtin (loc, function, params,
+ complain);
else
return NULL_TREE;
default:
{
tree new_function, first_param, result;
enum built_in_function fncode
- = speculation_safe_value_resolve_call (function, params);
+ = speculation_safe_value_resolve_call (function, params, complain);
if (fncode == BUILT_IN_NONE)
return error_mark_node;
first_param = (*params)[0];
- if (!speculation_safe_value_resolve_params (loc, function, params))
+ if (!speculation_safe_value_resolve_params (loc, function, params,
+ complain))
return error_mark_node;
if (targetm.have_speculation_safe_value (true))
against incorrect speculative execution. Simply return the
first parameter to the builtin. */
if (!targetm.have_speculation_safe_value (false))
- /* The user has invoked __builtin_speculation_safe_value
- even though __HAVE_SPECULATION_SAFE_VALUE is not
- defined: emit a warning. */
- warning_at (input_location, 0,
- "this target does not define a speculation barrier; "
- "your program will still execute correctly, "
- "but incorrect speculation may not be "
- "restricted");
+ {
+ if (complain)
+ /* The user has invoked __builtin_speculation_safe_value
+ even though __HAVE_SPECULATION_SAFE_VALUE is not
+ defined: emit a warning. */
+ warning_at (
+ input_location, 0,
+ "this target does not define a speculation barrier; "
+ "your program will still execute correctly, "
+ "but incorrect speculation may not be "
+ "restricted");
+ else
+ return error_mark_node;
+ }
/* If the optional second argument is present, handle any side
effects now. */
case BUILT_IN_ATOMIC_EXCHANGE:
{
if (resolve_overloaded_atomic_exchange (loc, function, params,
- &new_return))
+ &new_return, complain))
return new_return;
/* Change to the _N variant. */
orig_code = BUILT_IN_ATOMIC_EXCHANGE_N;
case BUILT_IN_ATOMIC_COMPARE_EXCHANGE:
{
- if (resolve_overloaded_atomic_compare_exchange (loc, function,
- params,
- &new_return))
+ if (resolve_overloaded_atomic_compare_exchange (
+ loc, function, params, &new_return, complain))
return new_return;
/* Change to the _N variant. */
orig_code = BUILT_IN_ATOMIC_COMPARE_EXCHANGE_N;
case BUILT_IN_ATOMIC_LOAD:
{
if (resolve_overloaded_atomic_load (loc, function, params,
- &new_return))
+ &new_return, complain))
return new_return;
/* Change to the _N variant. */
orig_code = BUILT_IN_ATOMIC_LOAD_N;
case BUILT_IN_ATOMIC_STORE:
{
if (resolve_overloaded_atomic_store (loc, function, params,
- &new_return))
+ &new_return, complain))
return new_return;
/* Change to the _N variant. */
orig_code = BUILT_IN_ATOMIC_STORE_N;
&& orig_code != BUILT_IN_SYNC_LOCK_TEST_AND_SET_N
&& orig_code != BUILT_IN_SYNC_LOCK_RELEASE_N);
- int n = sync_resolve_size (function, params, fetch_op, orig_format);
+ int n = sync_resolve_size (function, params, fetch_op, orig_format,
+ complain);
tree new_function, first_param, result;
enum built_in_function fncode;
return error_mark_node;
if (n == -1)
- return atomic_bitint_fetch_using_cas_loop (loc, orig_code,
- function, params);
+ {
+ /* complain is related to SFINAE context.
+ _BitInt is not defined in C++, hence can't enter this clause
+ with complain unset. Even if at the abstraction level
+ this complain is unset that still makes sense (whether
+ this function should report an error or not if anything is
+ wrong).
+ Since can't test avoiding an error when this value is false not
+ writing the code and instead asserting value is not set. */
+ gcc_assert (complain);
+ return atomic_bitint_fetch_using_cas_loop (loc, orig_code, function,
+ params);
+ }
fncode = (enum built_in_function)((int)orig_code + exact_log2 (n) + 1);
new_function = builtin_decl_explicit (fncode);
if (!sync_resolve_params (loc, function, new_function, params,
- orig_format))
+ orig_format, complain))
return error_mark_node;
first_param = (*params)[0];
void *, tree,
unsigned HOST_WIDE_INT,
opt_code);
-extern bool check_builtin_function_arguments (location_t, vec<location_t>,
- tree, tree, int, tree *);
+extern bool check_builtin_function_arguments (location_t, vec<location_t>, tree,
+ tree, int, tree *, bool = true);
extern void check_function_format (const_tree, tree, int, tree *,
vec<location_t> *,
bool (*comp_types) (tree, tree));
vec<tree, va_gc> *, vec<tree, va_gc> *,
tree = NULL_TREE);
-extern tree resolve_overloaded_builtin (location_t, tree, vec<tree, va_gc> *);
+extern tree resolve_overloaded_builtin (location_t, tree, vec<tree, va_gc> *,
+ bool = true);
extern tree finish_label_address_expr (tree, location_t);
/* Implement TARGET_RESOLVE_OVERLOADED_BUILTIN. */
static tree
aarch64_resolve_overloaded_builtin (location_t location,
- tree fndecl, void *uncast_arglist)
+ tree fndecl, void *uncast_arglist, bool)
{
vec<tree, va_gc> empty = {};
vec<tree, va_gc> *arglist = (uncast_arglist
/* Implement TARGET_CHECK_BUILTIN_CALL. */
static bool
aarch64_check_builtin_call (location_t loc, vec<location_t> arg_loc,
- tree fndecl, tree orig_fndecl,
- unsigned int nargs, tree *args)
+ tree fndecl, tree orig_fndecl, unsigned int nargs,
+ tree *args, bool)
{
unsigned int code = DECL_MD_FUNCTION_CODE (fndecl);
unsigned int subcode = code >> AARCH64_BUILTIN_SHIFT;
/* Implement TARGET_CHECK_BUILTIN_CALL. */
bool
-arm_check_builtin_call (location_t loc, vec<location_t> arg_loc,
- tree fndecl, tree orig_fndecl,
- unsigned int nargs, tree *args)
+arm_check_builtin_call (location_t loc, vec<location_t> arg_loc, tree fndecl,
+ tree orig_fndecl, unsigned int nargs, tree *args, bool)
{
unsigned int code = DECL_MD_FUNCTION_CODE (fndecl);
unsigned int subcode = code >> ARM_BUILTIN_SHIFT;
/* Implement TARGET_RESOLVE_OVERLOADED_BUILTIN. */
tree
arm_resolve_overloaded_builtin (location_t loc, tree fndecl,
- void *uncast_arglist)
+ void *uncast_arglist, bool)
{
enum resolver_ident resolver = arm_describe_resolver (fndecl);
if (resolver == arm_cde_resolver)
extern int use_return_insn (int, rtx);
extern bool use_simple_return_p (void);
extern enum reg_class arm_regno_class (int);
-extern bool arm_check_builtin_call (location_t , vec<location_t> , tree,
- tree, unsigned int, tree *);
+extern bool arm_check_builtin_call (location_t, vec<location_t>, tree, tree,
+ unsigned int, tree *, bool);
extern void arm_load_pic_register (unsigned long, rtx);
extern int arm_volatile_func (void);
extern void arm_expand_prologue (void);
/* Implement `TARGET_RESOLVE_OVERLOADED_PLUGIN'. */
static tree
-avr_resolve_overloaded_builtin (location_t loc, tree fndecl, void *vargs)
+avr_resolve_overloaded_builtin (location_t loc, tree fndecl, void *vargs, bool)
{
tree type0, type1, fold = NULL_TREE;
avr_builtin_id id = AVR_BUILTIN_COUNT;
/* Implement TARGET_CHECK_BUILTIN_CALL. */
static bool
riscv_check_builtin_call (location_t loc, vec<location_t> arg_loc, tree fndecl,
- tree, unsigned int nargs, tree *args)
+ tree, unsigned int nargs, tree *args, bool)
{
unsigned int code = DECL_MD_FUNCTION_CODE (fndecl);
unsigned int subcode = code >> RISCV_BUILTIN_SHIFT;
/* Implement TARGET_RESOLVE_OVERLOADED_BUILTIN. */
static tree
riscv_resolve_overloaded_builtin (location_t loc, tree fndecl,
- void *uncast_arglist)
+ void *uncast_arglist, bool)
{
vec<tree, va_gc> empty = {};
vec<tree, va_gc> *arglist = (vec<tree, va_gc> *) uncast_arglist;
tree
altivec_resolve_overloaded_builtin (location_t loc, tree fndecl,
- void *passed_arglist)
+ void *passed_arglist, bool)
{
rs6000_gen_builtins fcode
= (rs6000_gen_builtins) DECL_MD_FUNCTION_CODE (fndecl);
unsigned int);
extern unsigned int darwin_rs6000_special_round_type_align (tree, unsigned int,
unsigned int);
-extern tree altivec_resolve_overloaded_builtin (location_t, tree, void *);
+extern tree altivec_resolve_overloaded_builtin (location_t, tree, void *,
+ bool = true);
extern rtx rs6000_libcall_value (machine_mode);
extern rtx rs6000_va_arg (tree, tree);
extern int function_ok_for_sibcall (tree);
/* Return a tree expression for a call to the overloaded builtin
function OB_FNDECL at LOC with arguments PASSED_ARGLIST. */
tree
-s390_resolve_overloaded_builtin (location_t loc,
- tree ob_fndecl,
- void *passed_arglist)
+s390_resolve_overloaded_builtin (location_t loc, tree ob_fndecl,
+ void *passed_arglist, bool)
{
vec<tree, va_gc> *arglist = static_cast<vec<tree, va_gc> *> (passed_arglist);
unsigned int in_args_num = vec_safe_length (arglist);
argarray[i] = maybe_constant_value (argarray[i]);
if (!check_builtin_function_arguments (EXPR_LOCATION (fn), vNULL, fndecl,
- orig_fndecl, nargs, argarray))
+ orig_fndecl, nargs, argarray,
+ complain & tf_error))
return error_mark_node;
else if (fndecl_built_in_p (fndecl, BUILT_IN_CLEAR_PADDING))
{
if (TREE_CODE (fn) == FUNCTION_DECL
&& (DECL_BUILT_IN_CLASS (fn) == BUILT_IN_NORMAL
|| DECL_BUILT_IN_CLASS (fn) == BUILT_IN_MD))
- result = resolve_overloaded_builtin (input_location, fn, *args);
+ result = resolve_overloaded_builtin (input_location, fn, *args,
+ complain & tf_error);
if (!result)
{
built-in function.
@end deftypefn
-@deftypefn {Target Hook} tree TARGET_RESOLVE_OVERLOADED_BUILTIN (location_t @var{loc}, tree @var{fndecl}, void *@var{arglist})
+@deftypefn {Target Hook} tree TARGET_RESOLVE_OVERLOADED_BUILTIN (location_t @var{loc}, tree @var{fndecl}, void *@var{arglist}, bool @var{complain})
Select a replacement for a machine specific built-in function that
was set up by @samp{TARGET_INIT_BUILTINS}. This is done
@emph{before} regular type checking, and so allows the target to
complete expression that implements the operation, usually
another @code{CALL_EXPR}.
@var{arglist} really has type @samp{VEC(tree,gc)*}
+@var{complain} is a boolean indicating whether invalid operations
+should emit errors. This is set to @code{false} when the C++ templating
+context expects that errors should not be emitted (i.e. SFINAE).
@end deftypefn
-@deftypefn {Target Hook} bool TARGET_CHECK_BUILTIN_CALL (location_t @var{loc}, vec<location_t> @var{arg_loc}, tree @var{fndecl}, tree @var{orig_fndecl}, unsigned int @var{nargs}, tree *@var{args})
+@deftypefn {Target Hook} bool TARGET_CHECK_BUILTIN_CALL (location_t @var{loc}, vec<location_t> @var{arg_loc}, tree @var{fndecl}, tree @var{orig_fndecl}, unsigned int @var{nargs}, tree *@var{args}, bool @var{complain})
Perform semantic checking on a call to a machine-specific built-in
function after its arguments have been constrained to the function
signature. Return true if the call is valid, otherwise report an error
step is now to built-in function @var{fndecl}. @var{loc} is the
location of the call and @var{args} is an array of function arguments,
of which there are @var{nargs}. @var{arg_loc} specifies the location
-of each argument.
+of each argument. @var{complain} is a boolean indicating whether invalid
+arguments should emitm errors. This is set to @code{false} when the C++
+templating context expects that errors should not be emitted (i.e. SFINAE).
@end deftypefn
@deftypefn {Target Hook} tree TARGET_FOLD_BUILTIN (tree @var{fndecl}, int @var{n_args}, tree *@var{argp}, bool @var{ignore})
arguments passed to the built-in function. The result is a\n\
complete expression that implements the operation, usually\n\
another @code{CALL_EXPR}.\n\
-@var{arglist} really has type @samp{VEC(tree,gc)*}",
- tree, (location_t loc, tree fndecl, void *arglist), NULL)
+@var{arglist} really has type @samp{VEC(tree,gc)*}\n\
+@var{complain} is a boolean indicating whether invalid operations\n\
+should emit errors. This is set to @code{false} when the C++ templating\n\
+context expects that errors should not be emitted (i.e. SFINAE).",
+ tree, (location_t loc, tree fndecl, void *arglist, bool complain), NULL)
DEFHOOK
(check_builtin_call,
step is now to built-in function @var{fndecl}. @var{loc} is the\n\
location of the call and @var{args} is an array of function arguments,\n\
of which there are @var{nargs}. @var{arg_loc} specifies the location\n\
-of each argument.",
+of each argument. @var{complain} is a boolean indicating whether invalid\n\
+arguments should emitm errors. This is set to @code{false} when the C++\n\
+templating context expects that errors should not be emitted (i.e. SFINAE).",
bool, (location_t loc, vec<location_t> arg_loc, tree fndecl,
- tree orig_fndecl, unsigned int nargs, tree *args),
+ tree orig_fndecl, unsigned int nargs, tree *args, bool complain),
NULL)
/* Fold a target-specific builtin to a tree valid for both GIMPLE
--- /dev/null
+#include <type_traits>
+
+class X{};
+/* Want a zero-sized type in order to trigger one of the error messages.
+ Don't want the error message about creating a zero sized type.
+ However, *do* want to see any pedantic error messages coming from the rest
+ of the testcase. */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpedantic"
+class Zero {
+ unsigned int trailing[0];
+};
+#pragma GCC diagnostic pop
+class Large { public: int arr[10]; };
+class Incomplete;
+
+/* We have to use std::remove_pointer_t<T> for a few of the cases below to
+ handle using `int *` as the type.
+ In turn the problem is:
+ 1) __atomic_load_n (int *, int) is valid, so when having `int *` as the
+ type to operate on does not create something invalid (which is the
+ point of the NONPOINTER_PARAMS entry).
+ 2) __atomic_store_n (int *, int *, int) is not correct w.r.t. types
+ according to the GCC manual (and indeed ends up casting the pointer VAL
+ into an integer before storing it into the location.
+ However this is a known behaviour (PR 69404) so we're just working
+ around that for the moment.
+ 3) __atomic_load, __atomic_store, __atomic_exchange, __atomic_exchange_n,
+ __atomic_compare_exchange, and __atomic_compare_exchange_n, and all the
+ __atomic_fetch_<op> functions are using std::remove_pointer_t for
+ essentially the same behaviour of discarding the types as
+ __atomic_store_n. */
+
+#define ATOMIC_SFINAES \
+ SFINAE_TYPE_CHECK (load_n, (std::declval<T *> (), int ()), \
+ (std::declval<std::remove_pointer_t<T>> (), int ())) \
+ SFINAE_TYPE_CHECK (load, \
+ (std::declval<T *> (), std::declval<T *> (), int ()), \
+ (std::declval<std::remove_pointer_t<T>> (), \
+ std::declval<T *> (), int ())) \
+ SFINAE_TYPE_CHECK (store_n, \
+ (std::declval<T *> (), std::declval<T> (), int ()), \
+ (std::declval<std::remove_pointer_t<T>> (), \
+ std::declval<T> (), int ())) \
+ SFINAE_TYPE_CHECK (store, \
+ (std::declval<T *> (), std::declval<T *> (), int ()), \
+ (std::declval<std::remove_pointer_t<T>> (), \
+ std::declval<T *> (), int ())) \
+ SFINAE_TYPE_CHECK (exchange_n, \
+ (std::declval<T *> (), std::declval<T> (), int ()), \
+ (std::declval<std::remove_pointer_t<T>> (), \
+ std::declval<T> (), int ())) \
+ SFINAE_TYPE_CHECK (exchange, \
+ (std::declval<T *> (), std::declval<T *> (), \
+ std::declval<T *> (), int ()), \
+ (std::declval<std::remove_pointer_t<T>> (), \
+ std::declval<T *> (), std::declval<T *> (), int ())) \
+ SFINAE_TYPE_CHECK (compare_exchange_n, \
+ (std::declval<T *> (), std::declval<T *> (), \
+ std::declval<T> (), bool (), int (), int ()), \
+ (std::declval<std::remove_pointer_t<T>> (), \
+ std::declval<T *> (), std::declval<T> (), bool (), \
+ int (), int ())) \
+ SFINAE_TYPE_CHECK (compare_exchange, \
+ (std::declval<T *> (), std::declval<T *> (), \
+ std::declval<T *> (), bool (), int (), int ()), \
+ (std::declval<std::remove_pointer_t<T>> (), \
+ std::declval<T *> (), std::declval<T *> (), bool (), \
+ int (), int ())) \
+ SFINAE_TYPE_CHECK (add_fetch, \
+ (std::declval<T *> (), std::declval<T> (), int ()), \
+ (std::declval<std::remove_pointer_t<T>> (), \
+ std::declval<T> (), int ())) \
+ SFINAE_TYPE_CHECK (fetch_add, \
+ (std::declval<T *> (), std::declval<T> (), int ()), \
+ (std::declval<std::remove_pointer_t<T>> (), \
+ std::declval<T> (), int ())) \
+ SFINAE_TYPE_CHECK (sub_fetch, \
+ (std::declval<T *> (), std::declval<T> (), int ()), \
+ (std::declval<std::remove_pointer_t<T>> (), \
+ std::declval<T> (), int ())) \
+ SFINAE_TYPE_CHECK (fetch_sub, \
+ (std::declval<T *> (), std::declval<T> (), int ()), \
+ (std::declval<std::remove_pointer_t<T>> (), \
+ std::declval<T> (), int ())) \
+ SFINAE_TYPE_CHECK (and_fetch, \
+ (std::declval<T *> (), std::declval<T> (), int ()), \
+ (std::declval<std::remove_pointer_t<T>> (), \
+ std::declval<T> (), int ())) \
+ SFINAE_TYPE_CHECK (fetch_and, \
+ (std::declval<T *> (), std::declval<T> (), int ()), \
+ (std::declval<std::remove_pointer_t<T>> (), \
+ std::declval<T> (), int ())) \
+ SFINAE_TYPE_CHECK (xor_fetch, \
+ (std::declval<T *> (), std::declval<T> (), int ()), \
+ (std::declval<std::remove_pointer_t<T>> (), \
+ std::declval<T> (), int ())) \
+ SFINAE_TYPE_CHECK (fetch_xor, \
+ (std::declval<T *> (), std::declval<T> (), int ()), \
+ (std::declval<std::remove_pointer_t<T>> (), \
+ std::declval<T> (), int ())) \
+ SFINAE_TYPE_CHECK (or_fetch, \
+ (std::declval<T *> (), std::declval<T> (), int ()), \
+ (std::declval<std::remove_pointer_t<T>> (), \
+ std::declval<T> (), int ())) \
+ SFINAE_TYPE_CHECK (fetch_or, \
+ (std::declval<T *> (), std::declval<T> (), int ()), \
+ (std::declval<std::remove_pointer_t<T>> (), \
+ std::declval<T> (), int ())) \
+ SFINAE_TYPE_CHECK (nand_fetch, \
+ (std::declval<T *> (), std::declval<T> (), int ()), \
+ (std::declval<std::remove_pointer_t<T>> (), \
+ std::declval<T> (), int ())) \
+ SFINAE_TYPE_CHECK (fetch_nand, \
+ (std::declval<T *> (), std::declval<T> (), int ()), \
+ (std::declval<std::remove_pointer_t<T>> (), \
+ std::declval<T> (), int ()))
+
+ATOMIC_SFINAES
+
+#define FETCH_OP_ASSERTS(NAME) \
+ MAKE_ATOMIC_ASSERT(NAME, int *, true) \
+ MAKE_ATOMIC_ASSERT(NAME, float, false) \
+ MAKE_ATOMIC_ASSERT(NAME, int, true) \
+ MAKE_ATOMIC_ASSERT(NAME, bool, false) \
+ MAKE_ATOMIC_ASSERT(NAME, X, false) \
+ MAKE_ATOMIC_ASSERT(NAME, Zero, false) \
+ MAKE_ATOMIC_ASSERT(NAME, Large, false) \
+ MAKE_ATOMIC_ASSERT(NAME, Incomplete, false) \
+ MAKE_ATOMIC_ASSERT(NAME, long, true)
+
+#define ATOMIC_FETCH_ASSERTS \
+ FETCH_OP_ASSERTS(add_fetch) \
+ FETCH_OP_ASSERTS(fetch_add) \
+ FETCH_OP_ASSERTS(sub_fetch) \
+ FETCH_OP_ASSERTS(fetch_sub) \
+ FETCH_OP_ASSERTS(and_fetch) \
+ FETCH_OP_ASSERTS(fetch_and) \
+ FETCH_OP_ASSERTS(xor_fetch) \
+ FETCH_OP_ASSERTS(fetch_xor) \
+ FETCH_OP_ASSERTS(or_fetch) \
+ FETCH_OP_ASSERTS(fetch_or) \
+ FETCH_OP_ASSERTS(nand_fetch) \
+ FETCH_OP_ASSERTS(fetch_nand)
+
+#define ATOMIC_GENERIC_ASSERTS(NAME) \
+ MAKE_ATOMIC_ASSERT(NAME##_n, int *, true) \
+ MAKE_ATOMIC_ASSERT(NAME##_n, int, true) \
+ MAKE_ATOMIC_ASSERT(NAME##_n, bool, true) \
+ MAKE_ATOMIC_ASSERT(NAME##_n, X, false) \
+ MAKE_ATOMIC_ASSERT(NAME##_n, Zero, false) \
+ MAKE_ATOMIC_ASSERT(NAME##_n, Large, false) \
+ MAKE_ATOMIC_ASSERT(NAME##_n, Incomplete, false) \
+ MAKE_ATOMIC_ASSERT(NAME##_n, long, true) \
+ MAKE_ATOMIC_ASSERT(NAME##_n, float, false) \
+ MAKE_ATOMIC_ASSERT(NAME, int *, true) \
+ MAKE_ATOMIC_ASSERT(NAME, int, true) \
+ MAKE_ATOMIC_ASSERT(NAME, bool, true) \
+ MAKE_ATOMIC_ASSERT(NAME, X, true) \
+ MAKE_ATOMIC_ASSERT(NAME, Zero, false) \
+ MAKE_ATOMIC_ASSERT(NAME, Large, true) \
+ MAKE_ATOMIC_ASSERT(NAME, Incomplete, false) \
+ MAKE_ATOMIC_ASSERT(NAME, float, true) \
+ MAKE_ATOMIC_ASSERT(NAME, long, true)
+
+
+#define ATOMIC_ASSERTS \
+ ATOMIC_FETCH_ASSERTS \
+ ATOMIC_GENERIC_ASSERTS(load) \
+ ATOMIC_GENERIC_ASSERTS(store) \
+ ATOMIC_GENERIC_ASSERTS(exchange) \
+ ATOMIC_GENERIC_ASSERTS(compare_exchange)
+
+int main() {
+ ATOMIC_ASSERTS
+ return 0;
+}
--- /dev/null
+/* Check that overloaded builtins can be used in templates with SFINAE. */
+// { dg-do compile { target c++17 } }
+
+/* builtin-atomic-overloads{1,2,3,4,5}.C are focussed on checking various
+ properties of all the different atomic builtins.
+ builtin-atomic-overloads6.C is focussed on checking all error conditions in
+ the code ignoring which builtin we trigger them with. */
+
+/* Checks performed here:
+ Correctly specified -- as long as the type is something that these builtins
+ can work on. */
+#define SFINAE_TYPE_CHECK(NAME, PARAMS, NONPOINTER_PARAMS) \
+ template <typename T, typename = void> \
+ struct is_##NAME##_available : std::false_type {}; \
+ template <typename T> \
+ struct is_##NAME##_available<T, \
+ std::void_t<decltype(__atomic_##NAME PARAMS) >> \
+ : std::true_type {};
+
+/* Success according to type argument. */
+#define MAKE_ATOMIC_ASSERT(NAME, TYPE, SUCCESS) \
+ static_assert(is_##NAME##_available<TYPE>::value == SUCCESS);
+
+#include "builtin-atomic-overloads.def"
--- /dev/null
+/* Check that overloaded builtins can be used in templates with SFINAE. */
+// { dg-do compile { target c++17 } }
+
+/* Checks performed here:
+ Parameters without a pointer where it should be. */
+#define SFINAE_TYPE_CHECK(NAME, PARAMS, NONPOINTER_PARAMS) \
+ template <typename T, typename = void> \
+ struct is_##NAME##_available : std::false_type {}; \
+ template <typename T> \
+ struct is_##NAME##_available<T, \
+ std::void_t<decltype(__atomic_##NAME NONPOINTER_PARAMS) >> \
+ : std::true_type {};
+
+/* Everything fails with pointer to non-pointer mismatch. */
+#define MAKE_ATOMIC_ASSERT(NAME, TYPE, SUCCESS) \
+ static_assert(is_##NAME##_available<TYPE>::value == false);
+
+#include "builtin-atomic-overloads.def"
--- /dev/null
+/* Check that overloaded builtins can be used in templates with SFINAE. */
+// { dg-do compile { target c++17 } }
+
+/* Checks performed here:
+ Too many arguments (all atomic builtins take less than 7 arguments). */
+#define SFINAE_TYPE_CHECK(NAME, PARAMS, NONPOINTER_PARAMS) \
+ template <typename T, typename = void> \
+ struct is_##NAME##_available : std::false_type {}; \
+ template <typename T> \
+ struct is_##NAME##_available<T, \
+ std::void_t<decltype(__atomic_##NAME \
+ (int(), int(), int(), int(), int(), int(), std::declval<T>())) >> \
+ : std::true_type {};
+
+/* Everything fails with too many arguments. */
+#define MAKE_ATOMIC_ASSERT(NAME, TYPE, SUCCESS) \
+ static_assert(is_##NAME##_available<TYPE>::value == false);
+
+#include "builtin-atomic-overloads.def"
--- /dev/null
+/* Check that overloaded builtins can be used in templates with SFINAE. */
+// { dg-do compile { target c++17 } }
+
+/* Checks performed here:
+ Too few arguments (all atomic functions require more than one argument). */
+#define SFINAE_TYPE_CHECK(NAME, PARAMS, NONPOINTER_PARAMS) \
+ template <typename T, typename = void> \
+ struct is_##NAME##_available : std::false_type {}; \
+ template <typename T> \
+ struct is_##NAME##_available<T, \
+ std::void_t<decltype(__atomic_##NAME (std::declval<T>())) >> \
+ : std::true_type {};
+
+
+/* Everything fails with too few arguments. */
+#define MAKE_ATOMIC_ASSERT(NAME, TYPE, SUCCESS) \
+ static_assert(is_##NAME##_available<TYPE>::value == false);
+
+#include "builtin-atomic-overloads.def"
--- /dev/null
+/* Check that overloaded builtins still error when not in SFINAE context. */
+// { dg-do compile { target c++17 } }
+#include <type_traits>
+
+/* Should error here due to the fully specified (and invalid) builtin calls. */
+#define SFINAE_TYPE_CHECK(NAME, PARAMS, NONPOINTER_PARAMS) \
+ template <typename T, typename = void> \
+ struct is_##NAME##_available : std::false_type {}; \
+ template <typename T> \
+ struct is_##NAME##_available<T, \
+ std::void_t<decltype(__atomic_##NAME (int())) >> \
+ : std::true_type {}; \
+ template <typename T> \
+ struct is_##NAME##_available<T, \
+ std::void_t<decltype(__atomic_##NAME (int(), int())) >> \
+ : std::true_type {}; \
+ template <typename T> \
+ struct is_##NAME##_available<T, \
+ std::void_t<decltype(__atomic_##NAME (int(), int(), int())) >> \
+ : std::true_type {}; \
+ template <typename T> \
+ struct is_##NAME##_available<T, \
+ std::void_t<decltype(__atomic_##NAME (int(), int(), int(), int())) >> \
+ : std::true_type {}; \
+ template <typename T> \
+ struct is_##NAME##_available<T, \
+ std::void_t<decltype(__atomic_##NAME (int(), int(), int(), int(), int())) >> \
+ : std::true_type {}; \
+ template <typename T> \
+ struct is_##NAME##_available<T, \
+ std::void_t<decltype(__atomic_##NAME (int(), int(), int(), int(), int(), int())) >> \
+ : std::true_type {}; \
+ template <typename T> \
+ struct is_##NAME##_available<T, \
+ std::void_t<decltype(__atomic_##NAME (X(), int())) >> \
+ : std::true_type {}; \
+ template <typename T> \
+ struct is_##NAME##_available<T, \
+ std::void_t<decltype(__atomic_##NAME (Incomplete(), int())) >> \
+ : std::true_type {}; \
+ template <typename T> \
+ struct is_##NAME##_available<T, \
+ std::void_t<decltype(__atomic_##NAME (int(), int(), int(), int(), \
+ int(), int(), int())) >> \
+ : std::true_type {}; \
+ template <typename T> \
+ struct is_##NAME##_available<T, \
+ std::void_t<decltype(__atomic_##NAME (std::declval<int*>(), int(), int(), int(), \
+ int(), int(), int())) >> \
+ : std::true_type {}; \
+ template <typename T> \
+ struct is_##NAME##_available<T, \
+ std::void_t<decltype(__atomic_##NAME ()) >> \
+ : std::true_type {};
+
+/* All the errors that are emitted. We don't check that the errors directly
+ correspond to the relevant scenarios because validation that the correct
+ errors are generated for the relevant problems is done in other tests.
+
+ This test is checking that all the error types below are still emitted
+ when the problem occurs in templates for fully specified calls.
+
+ NOTE: We are missing some of the errors that could be emitted because the
+ above doesn't generate all invalid calls.
+ Things that could be added:
+ - pointer to incomplete type
+ - pointer to type of non-constant size
+ - pointer to type of zero size
+ - arguments after the first one:
+ - not pointers
+ - pointers to non-constant sized type
+ - pointers to function
+ - pointer to type of different size to the first one.
+ - pointer to const type
+ - pointer to volatile type
+ - memory model argument is not an integral type
+ - all errors around bitint
+ */
+
+/* { dg-error "argument 1 of '__atomic_compare_exchange' must be a non-void pointer type" "" { target *-*-* } 31 } */
+/* { dg-error "argument 1 of '__atomic_exchange' must be a non-void pointer type" "" { target *-*-* } 23 } */
+/* { dg-error "argument 1 of '__atomic_load' must be a non-void pointer type" "" { target *-*-* } 19 } */
+/* { dg-error "argument 1 of '__atomic_store' must be a non-void pointer type" "" { target *-*-* } 19 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_compare_exchange'" "" { target *-*-* } 11 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_compare_exchange'" "" { target *-*-* } 15 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_compare_exchange'" "" { target *-*-* } 19 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_compare_exchange'" "" { target *-*-* } 23 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_compare_exchange'" "" { target *-*-* } 27 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_compare_exchange'" "" { target *-*-* } 35 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_compare_exchange'" "" { target *-*-* } 39 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_compare_exchange'" "" { target *-*-* } 43 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_compare_exchange'" "" { target *-*-* } 48 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_compare_exchange'" "" { target *-*-* } 53 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_exchange'" "" { target *-*-* } 11 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_exchange'" "" { target *-*-* } 15 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_exchange'" "" { target *-*-* } 19 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_exchange'" "" { target *-*-* } 27 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_exchange'" "" { target *-*-* } 31 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_exchange'" "" { target *-*-* } 35 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_exchange'" "" { target *-*-* } 39 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_exchange'" "" { target *-*-* } 43 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_exchange'" "" { target *-*-* } 48 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_exchange'" "" { target *-*-* } 53 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_load'" "" { target *-*-* } 11 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_load'" "" { target *-*-* } 15 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_load'" "" { target *-*-* } 23 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_load'" "" { target *-*-* } 27 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_load'" "" { target *-*-* } 31 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_load'" "" { target *-*-* } 35 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_load'" "" { target *-*-* } 39 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_load'" "" { target *-*-* } 43 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_load'" "" { target *-*-* } 48 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_load'" "" { target *-*-* } 53 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_store'" "" { target *-*-* } 11 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_store'" "" { target *-*-* } 15 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_store'" "" { target *-*-* } 23 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_store'" "" { target *-*-* } 27 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_store'" "" { target *-*-* } 31 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_store'" "" { target *-*-* } 35 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_store'" "" { target *-*-* } 39 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_store'" "" { target *-*-* } 43 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_store'" "" { target *-*-* } 48 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_store'" "" { target *-*-* } 53 } */
+/* { dg-error "operand type 'Incomplete' is incompatible with argument 1 of '__atomic_add_fetch'" "" { target *-*-* } 39 } */
+/* { dg-error "operand type 'Incomplete' is incompatible with argument 1 of '__atomic_and_fetch'" "" { target *-*-* } 39 } */
+/* { dg-error "operand type 'Incomplete' is incompatible with argument 1 of '__atomic_compare_exchange_n'" "" { target *-*-* } 39 } */
+/* { dg-error "operand type 'Incomplete' is incompatible with argument 1 of '__atomic_exchange_n'" "" { target *-*-* } 39 } */
+/* { dg-error "operand type 'Incomplete' is incompatible with argument 1 of '__atomic_fetch_add'" "" { target *-*-* } 39 } */
+/* { dg-error "operand type 'Incomplete' is incompatible with argument 1 of '__atomic_fetch_and'" "" { target *-*-* } 39 } */
+/* { dg-error "operand type 'Incomplete' is incompatible with argument 1 of '__atomic_fetch_nand'" "" { target *-*-* } 39 } */
+/* { dg-error "operand type 'Incomplete' is incompatible with argument 1 of '__atomic_fetch_or'" "" { target *-*-* } 39 } */
+/* { dg-error "operand type 'Incomplete' is incompatible with argument 1 of '__atomic_fetch_sub'" "" { target *-*-* } 39 } */
+/* { dg-error "operand type 'Incomplete' is incompatible with argument 1 of '__atomic_fetch_xor'" "" { target *-*-* } 39 } */
+/* { dg-error "operand type 'Incomplete' is incompatible with argument 1 of '__atomic_load_n'" "" { target *-*-* } 39 } */
+/* { dg-error "operand type 'Incomplete' is incompatible with argument 1 of '__atomic_nand_fetch'" "" { target *-*-* } 39 } */
+/* { dg-error "operand type 'Incomplete' is incompatible with argument 1 of '__atomic_or_fetch'" "" { target *-*-* } 39 } */
+/* { dg-error "operand type 'Incomplete' is incompatible with argument 1 of '__atomic_store_n'" "" { target *-*-* } 39 } */
+/* { dg-error "operand type 'Incomplete' is incompatible with argument 1 of '__atomic_sub_fetch'" "" { target *-*-* } 39 } */
+/* { dg-error "operand type 'Incomplete' is incompatible with argument 1 of '__atomic_xor_fetch'" "" { target *-*-* } 39 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_add_fetch'" "" { target *-*-* } 11 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_add_fetch'" "" { target *-*-* } 15 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_add_fetch'" "" { target *-*-* } 19 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_add_fetch'" "" { target *-*-* } 23 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_add_fetch'" "" { target *-*-* } 27 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_add_fetch'" "" { target *-*-* } 31 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_add_fetch'" "" { target *-*-* } 43 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_and_fetch'" "" { target *-*-* } 11 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_and_fetch'" "" { target *-*-* } 15 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_and_fetch'" "" { target *-*-* } 19 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_and_fetch'" "" { target *-*-* } 23 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_and_fetch'" "" { target *-*-* } 27 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_and_fetch'" "" { target *-*-* } 31 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_and_fetch'" "" { target *-*-* } 43 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_compare_exchange_n'" "" { target *-*-* } 11 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_compare_exchange_n'" "" { target *-*-* } 15 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_compare_exchange_n'" "" { target *-*-* } 19 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_compare_exchange_n'" "" { target *-*-* } 23 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_compare_exchange_n'" "" { target *-*-* } 27 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_compare_exchange_n'" "" { target *-*-* } 31 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_compare_exchange_n'" "" { target *-*-* } 43 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_exchange_n'" "" { target *-*-* } 11 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_exchange_n'" "" { target *-*-* } 15 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_exchange_n'" "" { target *-*-* } 19 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_exchange_n'" "" { target *-*-* } 23 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_exchange_n'" "" { target *-*-* } 27 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_exchange_n'" "" { target *-*-* } 31 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_exchange_n'" "" { target *-*-* } 43 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_add'" "" { target *-*-* } 11 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_add'" "" { target *-*-* } 15 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_add'" "" { target *-*-* } 19 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_add'" "" { target *-*-* } 23 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_add'" "" { target *-*-* } 27 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_add'" "" { target *-*-* } 31 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_add'" "" { target *-*-* } 43 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_and'" "" { target *-*-* } 11 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_and'" "" { target *-*-* } 15 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_and'" "" { target *-*-* } 19 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_and'" "" { target *-*-* } 23 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_and'" "" { target *-*-* } 27 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_and'" "" { target *-*-* } 31 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_and'" "" { target *-*-* } 43 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_nand'" "" { target *-*-* } 11 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_nand'" "" { target *-*-* } 15 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_nand'" "" { target *-*-* } 19 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_nand'" "" { target *-*-* } 23 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_nand'" "" { target *-*-* } 27 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_nand'" "" { target *-*-* } 31 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_nand'" "" { target *-*-* } 43 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_or'" "" { target *-*-* } 11 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_or'" "" { target *-*-* } 15 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_or'" "" { target *-*-* } 19 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_or'" "" { target *-*-* } 23 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_or'" "" { target *-*-* } 27 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_or'" "" { target *-*-* } 31 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_or'" "" { target *-*-* } 43 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_sub'" "" { target *-*-* } 11 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_sub'" "" { target *-*-* } 15 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_sub'" "" { target *-*-* } 19 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_sub'" "" { target *-*-* } 23 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_sub'" "" { target *-*-* } 27 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_sub'" "" { target *-*-* } 31 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_sub'" "" { target *-*-* } 43 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_xor'" "" { target *-*-* } 11 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_xor'" "" { target *-*-* } 15 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_xor'" "" { target *-*-* } 19 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_xor'" "" { target *-*-* } 23 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_xor'" "" { target *-*-* } 27 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_xor'" "" { target *-*-* } 31 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_fetch_xor'" "" { target *-*-* } 43 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_load_n'" "" { target *-*-* } 11 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_load_n'" "" { target *-*-* } 15 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_load_n'" "" { target *-*-* } 19 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_load_n'" "" { target *-*-* } 23 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_load_n'" "" { target *-*-* } 27 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_load_n'" "" { target *-*-* } 31 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_load_n'" "" { target *-*-* } 43 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_nand_fetch'" "" { target *-*-* } 11 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_nand_fetch'" "" { target *-*-* } 15 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_nand_fetch'" "" { target *-*-* } 19 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_nand_fetch'" "" { target *-*-* } 23 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_nand_fetch'" "" { target *-*-* } 27 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_nand_fetch'" "" { target *-*-* } 31 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_nand_fetch'" "" { target *-*-* } 43 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_or_fetch'" "" { target *-*-* } 11 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_or_fetch'" "" { target *-*-* } 15 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_or_fetch'" "" { target *-*-* } 19 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_or_fetch'" "" { target *-*-* } 23 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_or_fetch'" "" { target *-*-* } 27 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_or_fetch'" "" { target *-*-* } 31 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_or_fetch'" "" { target *-*-* } 43 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_store_n'" "" { target *-*-* } 11 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_store_n'" "" { target *-*-* } 15 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_store_n'" "" { target *-*-* } 19 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_store_n'" "" { target *-*-* } 23 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_store_n'" "" { target *-*-* } 27 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_store_n'" "" { target *-*-* } 31 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_store_n'" "" { target *-*-* } 43 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_sub_fetch'" "" { target *-*-* } 11 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_sub_fetch'" "" { target *-*-* } 15 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_sub_fetch'" "" { target *-*-* } 19 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_sub_fetch'" "" { target *-*-* } 23 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_sub_fetch'" "" { target *-*-* } 27 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_sub_fetch'" "" { target *-*-* } 31 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_sub_fetch'" "" { target *-*-* } 43 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_xor_fetch'" "" { target *-*-* } 11 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_xor_fetch'" "" { target *-*-* } 15 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_xor_fetch'" "" { target *-*-* } 19 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_xor_fetch'" "" { target *-*-* } 23 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_xor_fetch'" "" { target *-*-* } 27 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_xor_fetch'" "" { target *-*-* } 31 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_xor_fetch'" "" { target *-*-* } 43 } */
+/* { dg-error "operand type 'X' is incompatible with argument 1 of '__atomic_add_fetch'" "" { target *-*-* } 35 } */
+/* { dg-error "operand type 'X' is incompatible with argument 1 of '__atomic_and_fetch'" "" { target *-*-* } 35 } */
+/* { dg-error "operand type 'X' is incompatible with argument 1 of '__atomic_compare_exchange_n'" "" { target *-*-* } 35 } */
+/* { dg-error "operand type 'X' is incompatible with argument 1 of '__atomic_exchange_n'" "" { target *-*-* } 35 } */
+/* { dg-error "operand type 'X' is incompatible with argument 1 of '__atomic_fetch_add'" "" { target *-*-* } 35 } */
+/* { dg-error "operand type 'X' is incompatible with argument 1 of '__atomic_fetch_and'" "" { target *-*-* } 35 } */
+/* { dg-error "operand type 'X' is incompatible with argument 1 of '__atomic_fetch_nand'" "" { target *-*-* } 35 } */
+/* { dg-error "operand type 'X' is incompatible with argument 1 of '__atomic_fetch_or'" "" { target *-*-* } 35 } */
+/* { dg-error "operand type 'X' is incompatible with argument 1 of '__atomic_fetch_sub'" "" { target *-*-* } 35 } */
+/* { dg-error "operand type 'X' is incompatible with argument 1 of '__atomic_fetch_xor'" "" { target *-*-* } 35 } */
+/* { dg-error "operand type 'X' is incompatible with argument 1 of '__atomic_load_n'" "" { target *-*-* } 35 } */
+/* { dg-error "operand type 'X' is incompatible with argument 1 of '__atomic_nand_fetch'" "" { target *-*-* } 35 } */
+/* { dg-error "operand type 'X' is incompatible with argument 1 of '__atomic_or_fetch'" "" { target *-*-* } 35 } */
+/* { dg-error "operand type 'X' is incompatible with argument 1 of '__atomic_store_n'" "" { target *-*-* } 35 } */
+/* { dg-error "operand type 'X' is incompatible with argument 1 of '__atomic_sub_fetch'" "" { target *-*-* } 35 } */
+/* { dg-error "operand type 'X' is incompatible with argument 1 of '__atomic_xor_fetch'" "" { target *-*-* } 35 } */
+/* { dg-error "too few arguments to function '__atomic_add_fetch'" "" { target *-*-* } 53 } */
+/* { dg-error "too few arguments to function '__atomic_and_fetch'" "" { target *-*-* } 53 } */
+/* { dg-error "too few arguments to function '__atomic_compare_exchange_n'" "" { target *-*-* } 53 } */
+/* { dg-error "too few arguments to function '__atomic_exchange_n'" "" { target *-*-* } 53 } */
+/* { dg-error "too few arguments to function '__atomic_fetch_add'" "" { target *-*-* } 53 } */
+/* { dg-error "too few arguments to function '__atomic_fetch_and'" "" { target *-*-* } 53 } */
+/* { dg-error "too few arguments to function '__atomic_fetch_nand'" "" { target *-*-* } 53 } */
+/* { dg-error "too few arguments to function '__atomic_fetch_or'" "" { target *-*-* } 53 } */
+/* { dg-error "too few arguments to function '__atomic_fetch_sub'" "" { target *-*-* } 53 } */
+/* { dg-error "too few arguments to function '__atomic_fetch_xor'" "" { target *-*-* } 53 } */
+/* { dg-error "too few arguments to function '__atomic_load_n'" "" { target *-*-* } 53 } */
+/* { dg-error "too few arguments to function '__atomic_nand_fetch'" "" { target *-*-* } 53 } */
+/* { dg-error "too few arguments to function '__atomic_or_fetch'" "" { target *-*-* } 53 } */
+/* { dg-error "too few arguments to function '__atomic_store_n'" "" { target *-*-* } 53 } */
+/* { dg-error "too few arguments to function '__atomic_sub_fetch'" "" { target *-*-* } 53 } */
+/* { dg-error "too few arguments to function '__atomic_xor_fetch'" "" { target *-*-* } 53 } */
+/* { dg-error "too many arguments to function '__atomic_add_fetch'" "" { target *-*-* } 48 } */
+/* { dg-error "too many arguments to function '__atomic_and_fetch'" "" { target *-*-* } 48 } */
+/* { dg-error "too many arguments to function '__atomic_compare_exchange_n'" "" { target *-*-* } 48 } */
+/* { dg-error "too many arguments to function '__atomic_exchange_n'" "" { target *-*-* } 48 } */
+/* { dg-error "too many arguments to function '__atomic_fetch_add'" "" { target *-*-* } 48 } */
+/* { dg-error "too many arguments to function '__atomic_fetch_and'" "" { target *-*-* } 48 } */
+/* { dg-error "too many arguments to function '__atomic_fetch_nand'" "" { target *-*-* } 48 } */
+/* { dg-error "too many arguments to function '__atomic_fetch_or'" "" { target *-*-* } 48 } */
+/* { dg-error "too many arguments to function '__atomic_fetch_sub'" "" { target *-*-* } 48 } */
+/* { dg-error "too many arguments to function '__atomic_fetch_xor'" "" { target *-*-* } 48 } */
+/* { dg-error "too many arguments to function '__atomic_load_n'" "" { target *-*-* } 48 } */
+/* { dg-error "too many arguments to function '__atomic_nand_fetch'" "" { target *-*-* } 48 } */
+/* { dg-error "too many arguments to function '__atomic_or_fetch'" "" { target *-*-* } 48 } */
+/* { dg-error "too many arguments to function '__atomic_store_n'" "" { target *-*-* } 48 } */
+/* { dg-error "too many arguments to function '__atomic_sub_fetch'" "" { target *-*-* } 48 } */
+/* { dg-error "too many arguments to function '__atomic_xor_fetch'" "" { target *-*-* } 48 } */
+
+
+/* { dg-error "template argument 1 is invalid" "" { target *-*-* } 11 } */
+/* { dg-error "template argument 1 is invalid" "" { target *-*-* } 15 } */
+/* { dg-error "template argument 1 is invalid" "" { target *-*-* } 19 } */
+/* { dg-error "template argument 1 is invalid" "" { target *-*-* } 23 } */
+/* { dg-error "template argument 1 is invalid" "" { target *-*-* } 27 } */
+/* { dg-error "template argument 1 is invalid" "" { target *-*-* } 31 } */
+/* { dg-error "template argument 1 is invalid" "" { target *-*-* } 35 } */
+/* { dg-error "template argument 1 is invalid" "" { target *-*-* } 39 } */
+/* { dg-error "template argument 1 is invalid" "" { target *-*-* } 43 } */
+/* { dg-error "template argument 1 is invalid" "" { target *-*-* } 48 } */
+/* { dg-error "template argument 1 is invalid" "" { target *-*-* } 53 } */
+/* { dg-error "template argument 2 is invalid" "" { target *-*-* } 11 } */
+/* { dg-error "template argument 2 is invalid" "" { target *-*-* } 15 } */
+/* { dg-error "template argument 2 is invalid" "" { target *-*-* } 19 } */
+/* { dg-error "template argument 2 is invalid" "" { target *-*-* } 23 } */
+/* { dg-error "template argument 2 is invalid" "" { target *-*-* } 27 } */
+/* { dg-error "template argument 2 is invalid" "" { target *-*-* } 31 } */
+/* { dg-error "template argument 2 is invalid" "" { target *-*-* } 35 } */
+/* { dg-error "template argument 2 is invalid" "" { target *-*-* } 39 } */
+/* { dg-error "template argument 2 is invalid" "" { target *-*-* } 44 } */
+/* { dg-error "template argument 2 is invalid" "" { target *-*-* } 49 } */
+/* { dg-error "template argument 2 is invalid" "" { target *-*-* } 53 } */
+
+/* Just avoid generating anything for the assertions (not what we're testing
+ here). */
+#define MAKE_ATOMIC_ASSERT(NAME, TYPE, SUCCESS)
+
+#include "builtin-atomic-overloads.def"
--- /dev/null
+/* Various atomic builtin errors are still emitted when in a fully specified
+ builtin in a template. */
+// { dg-do compile { target c++17 } }
+// { dg-additional-options "-Wno-pedantic" }
+#include <type_traits>
+#ifdef __ARM_FEATURE_SVE
+#include <arm_sve.h>
+#endif
+
+/*
+ Covering all if clauses, *not* all possible errors.
+ E.g. load, store, exchange, compare_exchange all go through
+ get_atomic_generic_size. I ensure I test all if clauses in that function
+ but do not ensure each clause is hit when using each of the different
+ builtins.
+
+ This is the stuff that is not handled by
+ builtin-atomic-overloads{1,2,3,4,5}.C */
+
+class X{};
+/* Want a zero-sized type in order to trigger one of the error messages.
+ Don't want the error message about creating a zero sized type.
+ However, *do* want to see any pedantic error messages coming from the rest
+ of the testcase. */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpedantic"
+class Zero {
+ unsigned int trailing[0];
+};
+#pragma GCC diagnostic pop
+class Large { public: int arr[10]; };
+class Incomplete;
+/* If there are other non-constant size types that I can use in a template
+ would appreciate hearing about it (especially if they work on all targets).
+ AFAIK VLA's are the other canonical example and have not managed to trigger
+ the same error with those due to scoping limitations. */
+#ifdef __ARM_FEATURE_SVE
+ typedef __SVUint32_t NonConstant;
+#else
+class NonConstant { };
+#endif
+typedef __UINT64_TYPE__ uint64_t;
+typedef __UINT32_TYPE__ uint32_t;
+// typedef _BitInt(12) Bitint;
+
+
+#define INCORRECT_NUMBER_ARGUMENTS(X) \
+ X(load, (int(), int(), int(), int()), 0)
+
+#define NONPOINTER_FIRST_ARG(X) \
+ X(load, (int(), int(), int()), 1)
+#define INCOMPLETE_FIRST_ARG(X) \
+ X(load, (Incomplete(), int(), int()), 2)
+/* This won't trigger relevant fail when not using nonconstant sized type. */
+#define NONCONST_SIZE_FIRST_ARG(X) \
+ X(load, (std::declval<NonConstant*>(), std::declval<NonConstant*>(), int()), 3)
+#define ZEROSIZE_FIRST_ARG(X) \
+ X(load, (std::declval<Zero*>(), std::declval<Zero*>(), int()), 4)
+
+// Errors triggered by a bad type in the first position not yet triggered by
+// builtin-atomic-overloads5.C.
+// These are already checked to *not* give an error in the SFINAE context by
+// builtin-atomic-overloads1.C.
+#define FIRST_ARGS_BADTYPE(X) \
+ ZEROSIZE_FIRST_ARG(X) \
+ NONCONST_SIZE_FIRST_ARG(X) \
+ INCOMPLETE_FIRST_ARG(X) \
+ NONPOINTER_FIRST_ARG(X)
+
+#define NONPOINTER_OTHER_ARG(X) \
+ X(load, (std::declval<int*>(), int(), int()), 5)
+/* This won't trigger relevant fail when not using nonconstant sized type. */
+#define NONCONST_SIZE_OTHER_ARG(X) \
+ X(load, (std::declval<int*>(), std::declval<NonConstant*>(), int()), 6)
+#define FUNCTIONPTR_OTHER_ARG(X) \
+ X(load, (std::declval<int*>(), std::declval<int(*)()>(), int()), 7)
+#define SIZE_MISMATCH(X) \
+ X(load, (std::declval<uint32_t*>(), std::declval<uint64_t*>(), int()), 8)
+#define OUTPUT_CONST(X) \
+ X(load, (std::declval<int*>(), std::declval<const int*>(), int()), 9)
+#define SECOND_VOLATILE(X) \
+ X(load, (std::declval<int*>(), std::declval<volatile int*>(), int()), 10)
+
+#define OTHER_ARG_BADTYPE(X) \
+ NONPOINTER_OTHER_ARG(X) \
+ SECOND_VOLATILE(X) \
+ OUTPUT_CONST(X) \
+ SIZE_MISMATCH(X) \
+ FUNCTIONPTR_OTHER_ARG(X) \
+ NONCONST_SIZE_OTHER_ARG(X)
+
+#define MEMMODEL_BADTYPE(X) \
+ X(load, (std::declval<int*>(), std::declval<int*>(), float()), 11)
+#define MEMMODEL_TOOLARGE(X) \
+ X(load, (std::declval<int*>(), std::declval<int*>(), 100), 12)
+
+#define MEMMODEL_BAD(X) \
+ MEMMODEL_BADTYPE(X) \
+ MEMMODEL_TOOLARGE(X)
+
+#define GET_ATOMIC_GENERIC_ERRS(X) \
+ INCORRECT_NUMBER_ARGUMENTS(X) \
+ FIRST_ARGS_BADTYPE(X) \
+ OTHER_ARG_BADTYPE(X) \
+ MEMMODEL_BAD(X)
+
+#define SYNC_SIZE_TOOFEW(X) \
+ X(load_n, (), 0)
+#define SYNC_SIZE_INCOMPATIBLE(X) \
+ X(load_n, (int(), int()), 1)
+#define SYNC_SIZE_ERRS(X) \
+ SYNC_SIZE_TOOFEW(X) \
+ SYNC_SIZE_INCOMPATIBLE(X)
+
+#define SYNC_PARM_TOOFEW(X) \
+ X(load_n, (std::declval<int*>()), 2)
+#define SYNC_PARM_TOOMANY(X) \
+ X(load_n, (std::declval<int*>(), int(), int()), 3)
+#define SYNC_PARM_ERRS(X) \
+ SYNC_PARM_TOOFEW(X) \
+ SYNC_PARM_TOOMANY(X)
+
+/*
+ No Bitint in C++. Hence can't check for this error.
+#define BITINT_FETCHCAS_TOOFEW(X) \
+ X(add_fetch, (std::declval<Bitint*>(), std::declval<Bitint>()))
+#define BITINT_FETCHCAS_TOOMANY(X) \
+ X(add_fetch, (std::declval<Bitint*>(), std::declval<Bitint>(), int(), int()))
+#define BITINT_FETCHCAS_ERRS(X) \
+ BITINT_FETCHCAS_TOOFEW(X) \
+ BITINT_FETCHCAS_TOOMANY(X)
+*/
+#define BITINT_FETCHCAS_ERRS(X)
+
+#define ALL_ERRS(X) \
+ GET_ATOMIC_GENERIC_ERRS(X) \
+ SYNC_SIZE_ERRS(X) \
+ SYNC_PARM_ERRS(X) \
+ BITINT_FETCHCAS_ERRS(X)
+
+#define SFINAE_TYPE_CHECK(NAME, PARAMS, COUNTER) \
+ template <typename T, typename = void> \
+ struct is_##NAME##_available_##COUNTER : std::false_type {}; \
+ template <typename T> \
+ struct is_##NAME##_available_##COUNTER<T, \
+ std::void_t<decltype(__atomic_##NAME PARAMS) >> \
+ : std::true_type {}; \
+
+ALL_ERRS(SFINAE_TYPE_CHECK)
+
+/* { dg-error "too few arguments to function '__atomic_load_n'" "" { target *-*-* } 108 } */
+/* { dg-error "operand type 'int' is incompatible with argument 1 of '__atomic_load_n'" "" { target *-*-* } 110 } */
+/* { dg-error "too few arguments to function '__atomic_load_n'" "" { target *-*-* } 116 } */
+/* { dg-error "too many arguments to function '__atomic_load_n'" "" { target *-*-* } 118 } */
+/* { dg-error "template argument 1 is invalid" "" { target *-*-* } 146 } */
+/* { dg-error "template argument 2 is invalid" "" { target *-*-* } 146 } */
+/* { dg-error "incorrect number of arguments to function '__atomic_load'" "" { target *-*-* } 48 } */
+/* { dg-error "argument 1 of '__atomic_load' must be a non-void pointer type" "" { target *-*-* } 51 } */
+/* { dg-error "argument 1 of '__atomic_load' must be a non-void pointer type" "" { target *-*-* } 53 } */
+/* { dg-error "argument 1 of '__atomic_load' must be a pointer to a constant size type" "" { target aarch64_sve } 56 } */
+/* { dg-error "argument 1 of '__atomic_load' must be a pointer to a nonzero size object" "" { target *-*-* } 58 } */
+/* { dg-error "argument 2 of '__atomic_load' must be a pointer type" "" { target *-*-* } 71 } */
+/* { dg-error "argument 2 of '__atomic_load' must be a pointer to a constant size type" "" { target aarch64_sve } 74 } */
+/* { dg-error "size mismatch in argument 2 of '__atomic_load'" "" { target { ! aarch64_sve } } 74 } */
+/* { dg-error "argument 2 of '__atomic_load' must not be a pointer to a function" "" { target *-*-* } 76 } */
+/* { dg-error "size mismatch in argument 2 of '__atomic_load'" "" { target *-*-* } 78 } */
+/* { dg-error "argument 2 of '__atomic_load' must not be a pointer to a 'const' type" "" { target *-*-* } 80 } */
+/* { dg-error "argument 2 of '__atomic_load' must not be a pointer to a 'volatile' type" "" { target *-*-* } 82 } */
+/* { dg-error "non-integer memory model argument 3 of '__atomic_load'" "" { target *-*-* } 93 } */
+
+/* { dg-warning {invalid memory model argument 3 of '__atomic_load' \[-Winvalid-memory-model\]} "" { target *-*-* } 95 } */
--- /dev/null
+/* Various atomic builtin errors not emitted when in SFINAE context. */
+// { dg-do compile { target c++17 } }
+// { dg-additional-options "-Wno-pedantic" }
+#include <type_traits>
+#ifdef __ARM_FEATURE_SVE
+#include <arm_sve.h>
+#endif
+
+/*
+ Covering all if clauses, *not* all possible errors.
+ E.g. load, store, exchange, compare_exchange all go through
+ get_atomic_generic_size. I ensure I test all if clauses in that function
+ but do not ensure each clause is hit when using each of the different
+ builtins.
+
+ This is the stuff that is not handled by
+ builtin-atomic-overloads{1,2,3,4,5}.C */
+
+class X{};
+/* Want a zero-sized type in order to trigger one of the error messages.
+ Don't want the error message about creating a zero sized type.
+ However, *do* want to see any pedantic error messages coming from the rest
+ of the testcase (shouldn't be any, but would like to be alerted if there
+ are). */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpedantic"
+class Zero {
+ unsigned int trailing[0];
+};
+#pragma GCC diagnostic pop
+class Large { public: int arr[10]; };
+class Incomplete;
+/* If there are other non-constant size types that I can use in a template
+ would appreciate hearing about it (especially if they work on all targets).
+ AFAIK VLA's are the other canonical example and have not managed to trigger
+ the same error with those due to scoping limitations. */
+#ifdef __ARM_FEATURE_SVE
+ typedef __SVUint32_t NonConstant;
+#else
+class NonConstant { };
+#endif
+typedef __UINT64_TYPE__ uint64_t;
+typedef __UINT32_TYPE__ uint32_t;
+// typedef _BitInt(12) Bitint;
+
+
+#define INCORRECT_NUMBER_ARGUMENTS(X) \
+ X(load, (std::declval<T>(), int(), int(), int()), 0)
+
+#define NONPOINTER_FIRST_ARG(X) \
+ X(load, (std::declval<std::remove_pointer_t<T>>(), int(), int()), 1)
+#define INCOMPLETE_FIRST_ARG(X) \
+ X(load, (std::declval<Incomplete*>(), std::declval<T>(), int()), 2)
+/* This won't trigger relevant fail when not using nonconstant sized type. */
+#define NONCONST_SIZE_FIRST_ARG(X) \
+ X(load, (std::declval<NonConstant*>(), std::declval<T>(), int()), 3)
+#define ZEROSIZE_FIRST_ARG(X) \
+ X(load, (std::declval<Zero*>(), std::declval<T>(), int()), 4)
+
+// Errors triggered by a bad type in the first position not yet triggered by
+// builtin-atomic-overloads5.C.
+// these are already checked to *not* give an error in the SFINAE context by
+// builtin-atomic-overloads1.C.
+#define FIRST_ARGS_BADTYPE(X) \
+ ZEROSIZE_FIRST_ARG(X) \
+ NONCONST_SIZE_FIRST_ARG(X) \
+ INCOMPLETE_FIRST_ARG(X) \
+ NONPOINTER_FIRST_ARG(X)
+
+#define NONPOINTER_OTHER_ARG(X) \
+ X(load, (std::declval<T>(), int(), int()), 5)
+/* This won't trigger relevant fail when not using nonconstant sized type. */
+#define NONCONST_SIZE_OTHER_ARG(X) \
+ X(load, (std::declval<T>(), std::declval<NonConstant*>(), int()), 6)
+#define FUNCTIONPTR_OTHER_ARG(X) \
+ X(load, (std::declval<T>(), std::declval<int(*)()>(), int()), 7)
+#define SIZE_MISMATCH(X) \
+ X(load, (std::declval<T>(), std::declval<uint64_t*>(), int()), 8)
+#define OUTPUT_CONST(X) \
+ X(load, (std::declval<T>(), std::declval<const int*>(), int()), 9)
+#define SECOND_VOLATILE(X) \
+ X(load, (std::declval<T>(), std::declval<volatile int*>(), int()), 10)
+
+#define OTHER_ARG_BADTYPE(X) \
+ NONPOINTER_OTHER_ARG(X) \
+ SECOND_VOLATILE(X) \
+ OUTPUT_CONST(X) \
+ SIZE_MISMATCH(X) \
+ FUNCTIONPTR_OTHER_ARG(X) \
+ NONCONST_SIZE_OTHER_ARG(X)
+
+#define MEMMODEL_BADTYPE(X) \
+ X(load, (std::declval<T>(), std::declval<int*>(), float()), 11)
+#define MEMMODEL_TOOLARGE(X) \
+ X(load, (std::declval<T>(), std::declval<int*>(), 100), 12)
+
+#define MEMMODEL_BAD(X) \
+ MEMMODEL_BADTYPE(X) \
+
+#define GET_ATOMIC_GENERIC_ERRS(X) \
+ INCORRECT_NUMBER_ARGUMENTS(X) \
+ FIRST_ARGS_BADTYPE(X) \
+ OTHER_ARG_BADTYPE(X) \
+ MEMMODEL_BAD(X)
+
+/* Can't trigger this error in SFINAE context since in order to trigger error
+ need zero arguments, but that means type is fully specified.
+
+#define SYNC_SIZE_TOOFEW(X) \
+ X(load_n, (), 0)
+ */
+#define SYNC_SIZE_TOOFEW(X)
+#define SYNC_SIZE_INCOMPATIBLE(X) \
+ X(load_n, (int(), std::declval<T>()), 1)
+#define SYNC_SIZE_ERRS(X) \
+ SYNC_SIZE_TOOFEW(X) \
+ SYNC_SIZE_INCOMPATIBLE(X)
+
+#define SYNC_PARM_TOOFEW(X) \
+ X(load_n, (std::declval<T>()), 2)
+#define SYNC_PARM_TOOMANY(X) \
+ X(load_n, (std::declval<T>(), int(), int()), 3)
+#define SYNC_PARM_ERRS(X) \
+ SYNC_PARM_TOOFEW(X) \
+ SYNC_PARM_TOOMANY(X)
+
+/*
+ No Bitint in C++. Hence can't check for this error.
+#define BITINT_FETCHCAS_TOOFEW(X) \
+ X(add_fetch, (std::declval<Bitint*>(), std::declval<Bitint>()))
+#define BITINT_FETCHCAS_TOOMANY(X) \
+ X(add_fetch, (std::declval<Bitint*>(), std::declval<Bitint>(), int(), int()))
+#define BITINT_FETCHCAS_ERRS(X) \
+ BITINT_FETCHCAS_TOOFEW(X) \
+ BITINT_FETCHCAS_TOOMANY(X)
+*/
+#define BITINT_FETCHCAS_ERRS(X)
+
+#define ALL_ERRS(X) \
+ GET_ATOMIC_GENERIC_ERRS(X) \
+ SYNC_SIZE_ERRS(X) \
+ SYNC_PARM_ERRS(X) \
+ MEMMODEL_TOOLARGE(X) \
+ BITINT_FETCHCAS_ERRS(X)
+
+#define SFINAE_TYPE_CHECK(NAME, PARAMS, COUNTER) \
+ template <typename T, typename = void> \
+ struct is_##NAME##_available_##COUNTER : std::false_type {}; \
+ template <typename T> \
+ struct is_##NAME##_available_##COUNTER<T, \
+ std::void_t<decltype(__atomic_##NAME PARAMS) >> \
+ : std::true_type {}; \
+
+ALL_ERRS(SFINAE_TYPE_CHECK)
+
+#define ASSERT(NAME, PARAMS, COUNTER) \
+ static_assert(is_##NAME##_available_##COUNTER<int*>::value == false);
+
+#define ASSERT_TRUE(NAME, PARAMS, COUNTER) \
+ static_assert(is_##NAME##_available_##COUNTER<int*>::value == true);
+
+int foo() {
+ ALL_ERRS(ASSERT)
+ return 1;
+}
+
--- /dev/null
+/* Check that one can use integral template argument for memory model argument
+ * in atomic SFINAE. */
+// { dg-do compile { target c++17 } }
+
+#include <type_traits>
+
+template <typename T, int I, typename = void>
+struct is_available : std::false_type {};
+
+template <typename T, int I>
+struct is_available<T, I,
+ std::void_t<decltype(__atomic_load (std::declval<T *>(),
+ std::declval<T *>(), I)) >>
+ : std::true_type {};
+
+static_assert(is_available<int,1>::value == true);
+static_assert(is_available<int,10>::value == false);
--- /dev/null
+/* Testing various builtins don't complain about incorrect number of arguments. */
+// { dg-do compile { target c++17 } }
+#include <type_traits>
+
+/* Here checking the check_builtin_function_arguments function doesn't error
+ in an SFINAE context. Test each of the errors that are directly emitted
+ from check_builtin_function_arguments. */
+
+class BasicClass { };
+class Incomplete;
+enum En { En_A };
+
+/* Do not include tests against the *_overflow error message of storing to
+ atomic types since I don't know how to make a type that is both TYPE_ATOMIC
+ and INTEGRAL_TYPE_P in C++ (where _Atomic is not a keyword).
+ Similar for clear_padding error message on _Atomic integral types. */
+#define NARGS_CHECKS(X) \
+ X (clrsbg, (std::declval<T> ()), unsigned, 4) \
+ X (ffsg, (std::declval<T> ()), unsigned, 4) \
+ X (clzg, (std::declval<T> ()), int, 4) \
+ X (ctzg, (std::declval<T> ()), int, 4) \
+ X (parityg, (std::declval<T> ()), int, 4) \
+ X (popcountg, (std::declval<T> ()), int, 4) \
+ X (clzg, (std::declval<T> ()), bool, 3) \
+ X (ctzg, (std::declval<T> ()), bool, 3) \
+ X (clrsbg, (std::declval<T> ()), bool, 3) \
+ X (ffsg, (std::declval<T> ()), bool, 3) \
+ X (parityg, (std::declval<T> ()), bool, 3) \
+ X (popcountg, (std::declval<T> ()), bool, 3) \
+ X (clzg, (std::declval<T> ()), En, 2) \
+ X (ctzg, (std::declval<T> ()), En, 2) \
+ X (clrsbg, (std::declval<T> ()), En, 2) \
+ X (ffsg, (std::declval<T> ()), En, 2) \
+ X (parityg, (std::declval<T> ()), En, 2) \
+ X (popcountg, (std::declval<T> ()), En, 2) \
+ X (clzg, (std::declval<T> ()), float, 1) \
+ X (ctzg, (std::declval<T> ()), float, 1) \
+ X (clrsbg, (std::declval<T> ()), float, 1) \
+ X (ffsg, (std::declval<T> ()), float, 1) \
+ X (parityg, (std::declval<T> ()), float, 1) \
+ X (popcountg, (std::declval<T> ()), float, 1) \
+ X (clzg, (std::declval<T> (), std::declval<long> ()), int, 101) \
+ X (ctzg, (std::declval<T> (), std::declval<long> ()), int, 101) \
+ X (clzg, (std::declval<T> (), std::declval<T> ()), float, 100) \
+ X (ctzg, (std::declval<T> (), std::declval<T> ()), float, 100) \
+ X (clear_padding, (std::declval<T *> ()), const int, 3) \
+ X (clear_padding, (std::declval<T *> ()), Incomplete, 2) \
+ X (clear_padding, (std::declval<T> ()), int, 1) \
+ X (add_overflow_p, \
+ (std::declval<T> (), std::declval<T> (), std::declval<bool> ()), int, 3) \
+ X (sub_overflow_p, \
+ (std::declval<T> (), std::declval<T> (), std::declval<bool> ()), int, 3) \
+ X (mul_overflow_p, \
+ (std::declval<T> (), std::declval<T> (), std::declval<bool> ()), int, 3) \
+ X (add_overflow_p, \
+ (std::declval<T> (), std::declval<T> (), std::declval<En> ()), int, 2) \
+ X (sub_overflow_p, \
+ (std::declval<T> (), std::declval<T> (), std::declval<En> ()), int, 2) \
+ X (mul_overflow_p, \
+ (std::declval<T> (), std::declval<T> (), std::declval<En> ()), int, 2) \
+ X (add_overflow_p, \
+ (std::declval<T> (), std::declval<T> (), std::declval<T> ()), float, 1) \
+ X (sub_overflow_p, \
+ (std::declval<T> (), std::declval<T> (), std::declval<T> ()), float, 1) \
+ X (mul_overflow_p, \
+ (std::declval<T> (), std::declval<T> (), std::declval<T> ()), float, 1) \
+ X (mul_overflow, \
+ (std::declval<T> (), std::declval<T> (), std::declval<const int *> ()), \
+ int, 5) \
+ X (sub_overflow, \
+ (std::declval<T> (), std::declval<T> (), std::declval<const int *> ()), \
+ int, 5) \
+ X (add_overflow, \
+ (std::declval<T> (), std::declval<T> (), std::declval<const int *> ()), \
+ int, 5) \
+ X (mul_overflow, \
+ (std::declval<T> (), std::declval<T> (), std::declval<bool *> ()), int, \
+ 4) \
+ X (sub_overflow, \
+ (std::declval<T> (), std::declval<T> (), std::declval<bool *> ()), int, \
+ 4) \
+ X (add_overflow, \
+ (std::declval<T> (), std::declval<T> (), std::declval<bool *> ()), int, \
+ 4) \
+ X (mul_overflow, \
+ (std::declval<T> (), std::declval<T> (), std::declval<En *> ()), int, 3) \
+ X (sub_overflow, \
+ (std::declval<T> (), std::declval<T> (), std::declval<En *> ()), int, 3) \
+ X (add_overflow, \
+ (std::declval<T> (), std::declval<T> (), std::declval<En *> ()), int, 3) \
+ X (mul_overflow, \
+ (std::declval<T> (), std::declval<T> (), std::declval<T> ()), int, 2) \
+ X (sub_overflow, \
+ (std::declval<T> (), std::declval<T> (), std::declval<T> ()), int, 2) \
+ X (add_overflow, \
+ (std::declval<T> (), std::declval<T> (), std::declval<T> ()), int, 2) \
+ X (mul_overflow, \
+ (std::declval<T> (), std::declval<T> (), std::declval<T *> ()), float, 1) \
+ X (sub_overflow, \
+ (std::declval<T> (), std::declval<T> (), std::declval<T *> ()), float, 1) \
+ X (add_overflow, \
+ (std::declval<T> (), std::declval<T> (), std::declval<T *> ()), float, 1) \
+ X (assume_aligned, (std::declval<int *> (), int (), std::declval<T> ()), \
+ float, 1) \
+ X (fpclassify, \
+ (std::declval<T> (), int (), int (), int (), int (), std::declval<T> ()), \
+ int, 2) \
+ X (fpclassify, \
+ (std::declval<T> (), int (), int (), int (), int (), float ()), float, 1) \
+ X (isgreater, (std::declval<T> (), std::declval<T> ()), int, 1) \
+ X (isgreaterequal, (std::declval<T> (), std::declval<T> ()), int, 1) \
+ X (isless, (std::declval<T> (), std::declval<T> ()), int, 1) \
+ X (islessequal, (std::declval<T> (), std::declval<T> ()), int, 1) \
+ X (islessgreater, (std::declval<T> (), std::declval<T> ()), int, 1) \
+ X (isunordered, (std::declval<T> (), std::declval<T> ()), int, 1) \
+ X (iseqsig, (std::declval<T> (), std::declval<T> ()), int, 1) \
+ X (isinf_sign, (std::declval<T> ()), int, 1) \
+ X (isnan, (std::declval<T> ()), int, 1) \
+ X (isnormal, (std::declval<T> ()), int, 1) \
+ X (issignaling, (std::declval<T> ()), int, 1) \
+ X (signbit, (std::declval<T> ()), int, 1) \
+ X (isinf, (std::declval<T> ()), int, 1) \
+ X (isfinite, (std::declval<T> ()), int, 1) \
+ X (alloca_with_align, (int (), int (), std::declval<T> ()), BasicClass, 1) \
+ X (alloca_with_align_and_max, (std::declval<T> (), 1), int, 1)
+
+#define TEMPLATE_DEFS(NAME, PARAMS, TYPE, NUM) \
+ template <typename T, typename = void> \
+ struct is_##NAME##_available_##NUM : std::false_type \
+ { \
+ }; \
+ template <typename T> \
+ struct is_##NAME##_available_##NUM< \
+ T, std::void_t<decltype (__builtin_##NAME PARAMS)>> : std::true_type \
+ { \
+ };
+
+NARGS_CHECKS(TEMPLATE_DEFS)
+
+#define MAKE_ASSERT(NAME, PARAMS, TYPE, NUM) \
+ static_assert(is_##NAME##_available_##NUM<TYPE>::value == false);
+
+void foo() {
+ NARGS_CHECKS(MAKE_ASSERT)
+}
--- /dev/null
+#include <type_traits>
+
+/* Use std::remove_pointer_t<T> here in order to make `int *` fail when using
+ the INVALID_PARAMETERS block. Pointers of two different types are allowed
+ in __builtin_speculation_safe_value, it's one argument of a pointer and
+ another argument that is not a pointer that give errors. */
+#define SPECULATION_SFINAES \
+ SFINAE_TYPE_CHECK ((std::declval<T> (), std::declval<T> ()), \
+ (std::declval<T> ()), \
+ (std::declval<std::remove_pointer_t<T>> (), std::declval<T *> ()))
+
+SPECULATION_SFINAES
+
+class X{};
+class Large { public: int arr[10]; };
+class Incomplete;
+
+#define SPECULATION_ASSERTS \
+ MAKE_SPECULATION_ASSERT (int, true) \
+ MAKE_SPECULATION_ASSERT (float, false) \
+ MAKE_SPECULATION_ASSERT (X, false) \
+ MAKE_SPECULATION_ASSERT (Large, false) \
+ MAKE_SPECULATION_ASSERT (Incomplete, false) \
+ MAKE_SPECULATION_ASSERT (int *, true) \
+ MAKE_SPECULATION_ASSERT (long, true)
+
+int main() {
+ SPECULATION_ASSERTS
+ return 0;
+}
--- /dev/null
+/* Check that overloaded builtins can be used in templates with SFINAE. */
+// { dg-do compile { target c++17 } }
+
+/* Checks performed here:
+ Various types (some that work, some that don't). */
+#define SFINAE_TYPE_CHECK(PARAMS, SHORTENED_PARAMS, INVALID_PARAMS) \
+ template <typename T, typename = void> \
+ struct is_available : std::false_type {}; \
+ template <typename T> \
+ struct is_available<T, \
+ std::void_t<decltype(__builtin_speculation_safe_value PARAMS) >> \
+ : std::true_type {};
+
+/* Success according to type of argument. */
+#define MAKE_SPECULATION_ASSERT(TYPE, SUCCESS) \
+ static_assert(is_available<TYPE>::value == SUCCESS);
+
+#include "builtin-speculation-overloads.def"
--- /dev/null
+/* Check that overloaded builtins can be used in templates with SFINAE. */
+// { dg-do compile { target c++17 } }
+
+/* Checks performed here:
+ Invalid parameters with various types (mismatching pointer and non-pointer
+ types). */
+#define SFINAE_TYPE_CHECK(PARAMS, SHORTENED_PARAMS, INVALID_PARAMS) \
+ template <typename T, typename = void> \
+ struct is_available : std::false_type {}; \
+ template <typename T> \
+ struct is_available<T, \
+ std::void_t<decltype(__builtin_speculation_safe_value INVALID_PARAMS) >> \
+ : std::true_type {};
+
+/* Mismatching pointer/non-pointer typed parameters always fail. */
+#define MAKE_SPECULATION_ASSERT(TYPE, SUCCESS) \
+ static_assert(is_available<TYPE>::value == false);
+
+#include "builtin-speculation-overloads.def"
--- /dev/null
+/* Check that overloaded builtins can be used in templates with SFINAE. */
+// { dg-do compile { target c++17 } }
+
+/* Checks performed here:
+ Too many arguments (for any type three arguments should be invalid). */
+#define SFINAE_TYPE_CHECK(PARAMS, SHORTENED_PARAMS, INVALID_PARAMS) \
+ template <typename T, typename = void> \
+ struct is_available : std::false_type {}; \
+ template <typename T> \
+ struct is_available<T, \
+ std::void_t<decltype(__builtin_speculation_safe_value \
+ (int(), int(), std::declval<T>())) >> \
+ : std::true_type {};
+
+/* All types should fail with three arguments. */
+#define MAKE_SPECULATION_ASSERT(TYPE, SUCCESS) \
+ static_assert(is_available<TYPE>::value == false);
+
+#include "builtin-speculation-overloads.def"
+
--- /dev/null
+/* Check that overloaded builtins can be used in templates with SFINAE. */
+// { dg-do compile { target c++17 } }
+
+/* Checks performed here:
+ Optional parameter missing works same as with optional parameter specified. */
+#define SFINAE_TYPE_CHECK(PARAMS, SHORTENED_PARAMS, INVALID_PARAMS) \
+ template <typename T, typename = void> \
+ struct is_available : std::false_type {}; \
+ template <typename T> \
+ struct is_available<T, \
+ std::void_t<decltype(__builtin_speculation_safe_value SHORTENED_PARAMS) >> \
+ : std::true_type {};
+
+/* All types should fail with three arguments. */
+#define MAKE_SPECULATION_ASSERT(TYPE, SUCCESS) \
+ static_assert(is_available<TYPE>::value == SUCCESS);
+
+#include "builtin-speculation-overloads.def"
+
--- /dev/null
+/* Check that overloaded builtins still error when not in SFINAE context. */
+// { dg-do compile { target c++17 } }
+#include <type_traits>
+
+/* Checks performed here:
+ Fully specified and invalid function errors before SFINAE happens. */
+template <typename T, typename = void> struct is_available : std::false_type
+{
+};
+
+/* Should be error here because of the fully specified (and invalid) builtin
+ call. */
+/* { dg-error "template argument 2 is invalid" "" { target *-*-* } .+5 } */
+/* { dg-error "template argument 1 is invalid" "" { target *-*-* } .+4 } */
+/* { dg-error "too few arguments to function" "" { target *-*-* } .+3 } */
+template <typename T>
+struct is_available<
+ T, std::void_t<decltype (__builtin_speculation_safe_value ())>>
+ : std::true_type
+{
+};
+
+/* Should be error here because of the fully specified (and invalid) builtin
+ call. */
+/* { dg-error "template argument 2 is invalid" "" { target *-*-* } .+5 } */
+/* { dg-error "template argument 1 is invalid" "" { target *-*-* } .+4 } */
+/* { dg-error "operand type 'float' is incompatible" "" { target *-*-* } .+3 } */
+template <typename T>
+struct is_available<
+ T, std::void_t<decltype (__builtin_speculation_safe_value (float()))>>
+ : std::true_type
+{
+};
--- /dev/null
+/* Testing that we avoid error in SFINAE context when number of arguments are
+ invalid in a builtin template argument. */
+// { dg-do compile { target c++17 } }
+/* { dg-additional-options "-Wno-macro-redefined" { target { *-*-* } } } */
+#include <type_traits>
+
+/* Here checking the builtin_function_validate_nargs function doesn't error
+ in an SFINAE context. */
+
+template <typename T, typename = void> struct is_available : std::false_type
+{
+};
+
+/* Make one testcase for each of the functions in
+ check_builtin_function_arguments that uses builtin_function_validate_nargs.
+ */
+#define NARGS_CHECKS(X) \
+ X (constant_p, (std::declval<T> (), std::declval<T> ())) \
+ X (isfinite, (std::declval<T> (), std::declval<T> ())) \
+ X (isinf, (std::declval<T> (), std::declval<T> ())) \
+ X (isinf_sign, (std::declval<T> (), std::declval<T> ())) \
+ X (isnan, (std::declval<T> (), std::declval<T> ())) \
+ X (isnormal, (std::declval<T> (), std::declval<T> ())) \
+ X (issignaling, (std::declval<T> (), std::declval<T> ())) \
+ X (signbit, (std::declval<T> (), std::declval<T> ())) \
+ X (isgreater, (std::declval<T> ())) \
+ X (isgreaterequal, (std::declval<T> ())) \
+ X (isless, (std::declval<T> ())) \
+ X (islessequal, (std::declval<T> ())) \
+ X (islessgreater, (std::declval<T> ())) \
+ X (isunordered, (std::declval<T> ())) \
+ X (iseqsig, (std::declval<T> ())) \
+ X (fpclassify, (std::declval<T> ())) \
+ X (assume_aligned, (std::declval<T> ())) \
+ X (add_overflow, (std::declval<T> ())) \
+ X (sub_overflow, (std::declval<T> ())) \
+ X (mul_overflow, (std::declval<T> ())) \
+ X (add_overflow_p, (std::declval<T> ())) \
+ X (sub_overflow_p, (std::declval<T> ())) \
+ X (mul_overflow_p, (std::declval<T> ())) \
+ X (clear_padding, (std::declval<T> (), std::declval<T> ())) \
+ X (clzg, (std::declval<T> (), std::declval<T> (), std::declval<T> ())) \
+ X (ctzg, (std::declval<T> (), std::declval<T> (), std::declval<T> ())) \
+ X (clrsbg, (std::declval<T> (), std::declval<T> (), std::declval<T> ())) \
+ X (ffsg, (std::declval<T> (), std::declval<T> (), std::declval<T> ())) \
+ X (parityg, (std::declval<T> (), std::declval<T> (), std::declval<T> ())) \
+ X (popcountg, (std::declval<T> (), std::declval<T> (), std::declval<T> ()))
+
+#define TEMPLATE_DEFS(NAME, PARAMS) \
+ template <typename T, typename = void> \
+ struct is_##NAME##_available : std::false_type \
+ { \
+ }; \
+ template <typename T> \
+ struct is_##NAME##_available< \
+ T, std::void_t<decltype (__builtin_##NAME PARAMS)>> : std::true_type \
+ { \
+ };
+
+NARGS_CHECKS(TEMPLATE_DEFS)
+
+#define MAKE_ASSERT(NAME, PARAMS) \
+ static_assert(is_##NAME##_available<int>::value == false);
+
+void foo() {
+ NARGS_CHECKS(MAKE_ASSERT)
+}