}
}
+/* Variables and functions to manage constexpr call expansion context.
+ These do not need to be marked for PCH or GC. */
+
+/* FIXME remember and print actual constant arguments. */
+static vec<tree> call_stack;
+static int call_stack_tick;
+static int last_cx_error_tick;
+
+/* Attempt to evaluate T which represents a call to __builtin_constexpr_diag.
+ The arguments should be an integer (0 for inform, 1 for warning, 2 for
+ error) optionally with 16 ored in if it should use caller's caller location
+ instead of caller's location and 2 messages which are either a pointer to
+ a STRING_CST or class with data () and size () member functions like
+ string_view or u8string_view. The first message is a tag, with "" passed
+ for no tag, data () should return const char *, the tag should only contain
+ alphanumeric letters or underscores. The second message is the diagnostic
+ message, data () can be either const char * or const char8_t *. size ()
+ should return the corresponding length of the strings in bytes as an
+ integer. */
+
+static tree
+cxx_eval_constexpr_diag (const constexpr_ctx *ctx, tree t, bool *non_constant_p,
+ bool *overflow_p, tree *jump_target)
+{
+ location_t loc = EXPR_LOCATION (t);
+ if (call_expr_nargs (t) != 3)
+ {
+ if (!ctx->quiet)
+ error_at (loc, "wrong number of arguments to %qs call",
+ "__builtin_constexpr_diag");
+ *non_constant_p = true;
+ return t;
+ }
+ tree args[3];
+ for (int i = 0; i < 3; ++i)
+ {
+ tree arg = CALL_EXPR_ARG (t, i);
+ arg = cxx_eval_constant_expression (ctx, arg,
+ (i == 0
+ || POINTER_TYPE_P (TREE_TYPE (arg)))
+ ? vc_prvalue : vc_glvalue,
+ non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
+ if (*non_constant_p)
+ return t;
+ args[i] = arg;
+ }
+ if (TREE_CODE (args[0]) != INTEGER_CST
+ || wi::to_widest (args[0]) < 0
+ || wi::to_widest (args[0]) > 18
+ || (wi::to_widest (args[0]) & 15) > 2)
+ {
+ if (!ctx->quiet)
+ error_at (loc, "first %qs call argument should be 0, 1, 2, 16, 17 or "
+ "18", "__builtin_constexpr_diag");
+ *non_constant_p = true;
+ return t;
+ }
+ const char *msgs[2] = {};
+ int lens[3] = {};
+ cexpr_str cstrs[2];
+ diagnostics::kind kind = diagnostics::kind::error;
+ for (int i = 1; i < 3; ++i)
+ {
+ tree arg = args[i];
+ if (POINTER_TYPE_P (TREE_TYPE (arg)))
+ {
+ tree str = arg;
+ STRIP_NOPS (str);
+ if (TREE_CODE (str) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (str, 0)) == STRING_CST)
+ {
+ str = TREE_OPERAND (str, 0);
+ tree eltype = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (str)));
+ if (eltype == char_type_node
+ || (i == 2 && eltype == char8_type_node))
+ arg = str;
+ }
+ }
+ cstrs[i - 1].message = arg;
+ if (!cstrs[i - 1].type_check (loc, i == 2))
+ {
+ *non_constant_p = true;
+ return t;
+ }
+ if (!cstrs[i - 1].extract (loc, msgs[i - 1], lens[i - 1], ctx,
+ non_constant_p, overflow_p, jump_target))
+ {
+ if (*jump_target)
+ return NULL_TREE;
+ *non_constant_p = true;
+ return t;
+ }
+ }
+ if (msgs[0])
+ {
+ for (int i = 0; i < lens[0]; ++i)
+ if (!ISALNUM (msgs[0][i]) && msgs[0][i] != '_')
+ {
+ if (!ctx->quiet)
+ error_at (loc, "%qs tag string contains %qc character other than"
+ " letters, digits or %<_%>",
+ "__builtin_constexpr_diag", msgs[0][i]);
+ *non_constant_p = true;
+ return t;
+ }
+ }
+ if (ctx->manifestly_const_eval == mce_unknown)
+ {
+ *non_constant_p = true;
+ return t;
+ }
+ int arg0 = tree_to_uhwi (args[0]);
+ if (arg0 & 16)
+ {
+ arg0 &= 15;
+ if (!call_stack.is_empty ())
+ {
+ tree call = call_stack.last ();
+ if (EXPR_HAS_LOCATION (call))
+ loc = EXPR_LOCATION (call);
+ }
+ }
+ if (arg0 == 0)
+ kind = diagnostics::kind::note;
+ else if (arg0 == 1)
+ kind = diagnostics::kind::warning;
+ if (lens[0])
+ {
+ const char *color = "error";
+ if (kind == diagnostics::kind::note)
+ color = "note";
+ else if (kind == diagnostics::kind::warning)
+ color = "warning";
+ emit_diagnostic (kind, loc, 0, "constexpr message: %.*s [%r%.*s%R]",
+ lens[1], msgs[1], color, lens[0], msgs[0]);
+ }
+ else
+ emit_diagnostic (kind, loc, 0, "constexpr message: %.*s",
+ lens[1], msgs[1]);
+ return void_node;
+}
+
/* Attempt to evaluate T which represents a call to a builtin function.
We assume here that all builtin functions evaluate to scalar types
represented by _CST nodes. */
fun, non_constant_p, overflow_p,
jump_target);
+ if (fndecl_built_in_p (fun, CP_BUILT_IN_CONSTEXPR_DIAG, BUILT_IN_FRONTEND))
+ return cxx_eval_constexpr_diag (ctx, t, non_constant_p, overflow_p,
+ jump_target);
+
int strops = 0;
int strret = 0;
if (fndecl_built_in_p (fun, BUILT_IN_NORMAL))
return binds;
}
-/* Variables and functions to manage constexpr call expansion context.
- These do not need to be marked for PCH or GC. */
-
-/* FIXME remember and print actual constant arguments. */
-static vec<tree> call_stack;
-static int call_stack_tick;
-static int last_cx_error_tick;
-
static int
push_cx_call_context (tree call)
{
&CALL_EXPR_ARG (*expr_p,
0));
break;
+ case CP_BUILT_IN_CONSTEXPR_DIAG:
+ *expr_p = void_node;
+ break;
default:
break;
}
CP_BUILT_IN_SOURCE_LOCATION,
CP_BUILT_IN_EH_PTR_ADJUST_REF,
CP_BUILT_IN_IS_STRING_LITERAL,
+ CP_BUILT_IN_CONSTEXPR_DIAG,
CP_BUILT_IN_LAST
};
class cexpr_str
{
public:
+ cexpr_str () : message (NULL_TREE) {}
cexpr_str (tree message) : message (message) {}
cexpr_str (const cexpr_str &) = delete;
~cexpr_str () { XDELETEVEC (buf); }
- bool type_check (location_t location);
- bool extract (location_t location, const char * & msg, int &len);
+ bool type_check (location_t location, bool allow_char8_t = false);
+ bool extract (location_t location, const char * &msg, int &len,
+ const constexpr_ctx * = NULL, bool * = NULL,
+ bool * = NULL, tree * = NULL);
bool extract (location_t location, tree &str);
tree message;
private:
BUILT_IN_FRONTEND, NULL, NULL_TREE);
set_call_expr_flags (decl, ECF_CONST | ECF_NOTHROW | ECF_LEAF);
+ tree void_vaintftype = build_varargs_function_type_list (void_type_node,
+ integer_type_node,
+ NULL_TREE);
+ decl = add_builtin_function ("__builtin_constexpr_diag",
+ void_vaintftype,
+ CP_BUILT_IN_CONSTEXPR_DIAG,
+ BUILT_IN_FRONTEND, NULL, NULL_TREE);
+ set_call_expr_flags (decl, ECF_NOTHROW | ECF_LEAF);
+
integer_two_node = build_int_cst (NULL_TREE, 2);
/* Guess at the initial static decls size. */
otherwise false. */
bool
-cexpr_str::type_check (location_t location)
+cexpr_str::type_check (location_t location, bool allow_char8_t /*=false*/)
{
tsubst_flags_t complain = tf_warning_or_error;
if (message_sz == error_mark_node || message_data == error_mark_node)
return false;
message_sz = build_converted_constant_expr (size_type_node, message_sz,
- complain);
+ complain);
if (message_sz == error_mark_node)
{
error_at (location, "constexpr string %<size()%> "
"%<std::size_t%>");
return false;
}
+
+ if (allow_char8_t
+ && POINTER_TYPE_P (TREE_TYPE (message_data))
+ && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (message_data)))
+ == char8_type_node)
+ && (TYPE_QUALS (TREE_TYPE (TREE_TYPE (message_data)))
+ == TYPE_QUAL_CONST))
+ return true;
+
message_data = build_converted_constant_expr (const_string_type_node,
- message_data, complain);
+ message_data, complain);
if (message_data == error_mark_node)
{
error_at (location, "constexpr string %<data()%> "
Returns true if successful, otherwise false. */
bool
-cexpr_str::extract (location_t location, const char * & msg, int &len)
+cexpr_str::extract (location_t location, const char * &msg, int &len,
+ const constexpr_ctx *ctx /* = NULL */,
+ bool *non_constant_p /* = NULL */,
+ bool *overflow_p /* = NULL */,
+ tree *jump_target /* = NULL */)
{
tsubst_flags_t complain = tf_warning_or_error;
msg = NULL;
if (message_sz && message_data)
{
- tree msz = cxx_constant_value (message_sz, NULL_TREE, complain);
+ tree msz;
+ if (ctx)
+ {
+ msz = cxx_eval_constant_expression (ctx, message_sz, vc_prvalue,
+ non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target || *non_constant_p)
+ return false;
+ }
+ else
+ msz = cxx_constant_value (message_sz, NULL_TREE, complain);
if (!tree_fits_uhwi_p (msz))
{
- error_at (location,
- "constexpr string %<size()%> "
- "must be a constant expression");
+ if (!ctx || !cxx_constexpr_quiet_p (ctx))
+ error_at (location,
+ "constexpr string %<size()%> "
+ "must be a constant expression");
return false;
}
else if ((unsigned HOST_WIDE_INT) (int) tree_to_uhwi (msz)
!= tree_to_uhwi (msz))
{
- error_at (location,
- "constexpr string message %<size()%> "
- "%qE too large", msz);
+ if (!ctx || !cxx_constexpr_quiet_p (ctx))
+ error_at (location,
+ "constexpr string message %<size()%> "
+ "%qE too large", msz);
return false;
}
len = tree_to_uhwi (msz);
- tree data = maybe_constant_value (message_data, NULL_TREE,
- mce_true);
- if (!reduced_constant_expression_p (data))
- data = NULL_TREE;
- if (len)
- {
- if (data)
- msg = c_getstr (data);
- if (msg == NULL)
- buf = XNEWVEC (char, len);
- for (int i = 0; i < len; ++i)
- {
- tree t = message_data;
- if (i)
- t = build2 (POINTER_PLUS_EXPR,
- TREE_TYPE (message_data), message_data,
- size_int (i));
- t = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (t)), t);
- tree t2 = cxx_constant_value (t, NULL_TREE, complain);
- if (!tree_fits_shwi_p (t2))
+ tree data;
+ if (ctx)
+ {
+ data = cxx_eval_constant_expression (ctx, message_data, vc_prvalue,
+ non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target || *non_constant_p)
+ return false;
+ STRIP_NOPS (data);
+ if (TREE_CODE (data) != ADDR_EXPR)
+ {
+ unhandled:
+ if (!cxx_constexpr_quiet_p (ctx))
+ error_at (location, "unhandled return from %<data()%>");
+ return false;
+ }
+ tree str = TREE_OPERAND (data, 0);
+ unsigned HOST_WIDE_INT off = 0;
+ if (TREE_CODE (str) == ARRAY_REF
+ && tree_fits_uhwi_p (TREE_OPERAND (str, 1)))
+ {
+ off = tree_to_uhwi (TREE_OPERAND (str, 1));
+ str = TREE_OPERAND (str, 0);
+ }
+ str = cxx_eval_constant_expression (ctx, str, vc_prvalue,
+ non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target || *non_constant_p)
+ return false;
+ if (TREE_CODE (str) == STRING_CST)
+ {
+ if (TREE_STRING_LENGTH (str) < len
+ || (unsigned) TREE_STRING_LENGTH (str) < off
+ || (unsigned) TREE_STRING_LENGTH (str) < off + len)
+ goto unhandled;
+ msg = TREE_STRING_POINTER (str) + off;
+ goto translate;
+ }
+ if (TREE_CODE (str) != CONSTRUCTOR
+ || TREE_CODE (TREE_TYPE (str)) != ARRAY_TYPE)
+ goto unhandled;
+ char *b;
+ if (len < 64)
+ b = XALLOCAVEC (char, len + 1);
+ else
+ {
+ buf = XNEWVEC (char, len + 1);
+ b = buf;
+ }
+ msg = b;
+ memset (b, 0, len + 1);
+ tree field, value;
+ unsigned k;
+ unsigned HOST_WIDE_INT l = 0;
+ FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (str), k, field, value)
+ if (!tree_fits_shwi_p (value))
+ goto unhandled;
+ else if (field == NULL_TREE)
+ {
+ if (integer_zerop (value))
+ break;
+ if (l >= off && l < off + len)
+ b[l - off] = tree_to_shwi (value);
+ ++l;
+ }
+ else if (TREE_CODE (field) == RANGE_EXPR)
+ {
+ tree lo = TREE_OPERAND (field, 0);
+ tree hi = TREE_OPERAND (field, 1);
+ if (!tree_fits_uhwi_p (lo) || !tree_fits_uhwi_p (hi))
+ goto unhandled;
+ if (integer_zerop (value))
+ break;
+ unsigned HOST_WIDE_INT m = tree_to_uhwi (hi);
+ for (l = tree_to_uhwi (lo); l <= m; ++l)
+ if (l >= off && l < off + len)
+ b[l - off] = tree_to_shwi (value);
+ }
+ else if (tree_fits_uhwi_p (field))
+ {
+ l = tree_to_uhwi (field);
+ if (integer_zerop (value))
+ break;
+ if (l >= off && l < off + len)
+ b[l - off] = tree_to_shwi (value);
+ l++;
+ }
+ b[len] = '\0';
+ }
+ else
+ {
+ data = maybe_constant_value (message_data, NULL_TREE, mce_true);
+ if (!reduced_constant_expression_p (data))
+ data = NULL_TREE;
+ if (len)
+ {
+ if (data)
+ msg = c_getstr (data);
+ if (msg == NULL)
+ buf = XNEWVEC (char, len);
+ for (int i = 0; i < len; ++i)
+ {
+ tree t = message_data;
+ if (i)
+ t = build2 (POINTER_PLUS_EXPR,
+ TREE_TYPE (message_data), message_data,
+ size_int (i));
+ t = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (t)), t);
+ tree t2 = cxx_constant_value (t, NULL_TREE, complain);
+ if (!tree_fits_shwi_p (t2))
+ {
+ error_at (location,
+ "constexpr string %<data()[%d]%> "
+ "must be a constant expression", i);
+ return false;
+ }
+ if (msg == NULL)
+ buf[i] = tree_to_shwi (t2);
+ /* If c_getstr worked, just verify the first and
+ last characters using constant evaluation. */
+ else if (len > 2 && i == 0)
+ i = len - 2;
+ }
+ if (msg == NULL)
+ msg = buf;
+ }
+ else if (!data)
+ {
+ /* We don't have any function to test whether some
+ expression is a core constant expression. So, instead
+ test whether (message.data (), 0) is a constant
+ expression. */
+ data = build2 (COMPOUND_EXPR, integer_type_node,
+ message_data, integer_zero_node);
+ tree t = cxx_constant_value (data, NULL_TREE, complain);
+ if (!integer_zerop (t))
{
error_at (location,
- "constexpr string %<data()[%d]%> "
- "must be a constant expression", i);
+ "constexpr string %<data()%> "
+ "must be a core constant expression");
return false;
}
- if (msg == NULL)
- buf[i] = tree_to_shwi (t2);
- /* If c_getstr worked, just verify the first and
- last characters using constant evaluation. */
- else if (len > 2 && i == 0)
- i = len - 2;
- }
- if (msg == NULL)
- msg = buf;
- }
- else if (!data)
- {
- /* We don't have any function to test whether some
- expression is a core constant expression. So, instead
- test whether (message.data (), 0) is a constant
- expression. */
- data = build2 (COMPOUND_EXPR, integer_type_node,
- message_data, integer_zero_node);
- tree t = cxx_constant_value (data, NULL_TREE, complain);
- if (!integer_zerop (t))
- {
- error_at (location,
- "constexpr string %<data()%> "
- "must be a core constant expression");
- return false;
}
}
+ }
+ else
+ {
+ tree eltype = TREE_TYPE (TREE_TYPE (message));
+ int sz = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (eltype));
+ msg = TREE_STRING_POINTER (message);
+ len = TREE_STRING_LENGTH (message) / sz - 1;
+ }
+translate:
+ if ((message_sz && message_data) || ctx)
+ {
/* Convert the string from execution charset to SOURCE_CHARSET. */
cpp_string istr, ostr;
istr.len = len;
istr.text = (const unsigned char *) msg;
+ enum cpp_ttype type = CPP_STRING;
+ if (message_sz && message_data)
+ {
+ if (POINTER_TYPE_P (TREE_TYPE (message_data))
+ && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (message_data)))
+ == char8_type_node))
+ type = CPP_UTF8STRING;
+ }
+ else if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (message)))
+ == char8_type_node)
+ type = CPP_UTF8STRING;
if (len == 0)
;
- else if (!cpp_translate_string (parse_in, &istr, &ostr, CPP_STRING,
+ else if (!cpp_translate_string (parse_in, &istr, &ostr, type,
true))
{
- error_at (location, "could not convert constexpr string from "
- "ordinary literal encoding to source character "
- "set");
+ if (type == CPP_UTF8STRING)
+ error_at (location, "could not convert constexpr string from "
+ "UTF-8 encoding to source character "
+ "set");
+ else
+ error_at (location, "could not convert constexpr string from "
+ "ordinary literal encoding to source character "
+ "set");
return false;
}
else
len = ostr.len;
}
}
- else
- {
- tree eltype = TREE_TYPE (TREE_TYPE (message));
- int sz = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (eltype));
- msg = TREE_STRING_POINTER (message);
- len = TREE_STRING_LENGTH (message) / sz - 1;
- }
return true;
}
case CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS:
case CP_BUILT_IN_EH_PTR_ADJUST_REF:
case CP_BUILT_IN_IS_STRING_LITERAL:
+ case CP_BUILT_IN_CONSTEXPR_DIAG:
return true;
default:
break;
--- /dev/null
+// { dg-do compile { target c++26 } }
+
+struct S {
+ char buf[16];
+ constexpr const char *data () const { return buf; }
+ constexpr decltype (sizeof 0) size () const { for (int i = 0; i < 16; ++i) if (!buf[i]) return i; return 0; }
+};
+struct T {
+ constexpr const char *data () const { return "bar"; }
+ constexpr decltype (sizeof 0) size () const { return 3; }
+};
+constexpr char str[] = "abcdefg";
+struct U {
+ constexpr const char *data () const { return &str[2]; }
+ constexpr decltype (sizeof 0) size () const { return 4; }
+};
+struct V {
+ constexpr const char *data () const { return &"abcdefghi"[3]; }
+ constexpr decltype (sizeof 0) size () const { return 5; }
+};
+struct W {
+ constexpr const char *data () const { return &"abcdefghi"[3] + 2; }
+ constexpr decltype (sizeof 0) size () const { return 3; }
+};
+
+consteval
+{
+ S s;
+ for (int i = 0; i < 10; ++i)
+ s.buf[i] = '0' + i;
+ s.buf[10] = '\0';
+ __builtin_constexpr_diag (0, "foo", "bar"); // { dg-message "constexpr message: bar \\\[foo\\\]" }
+ __builtin_constexpr_diag (1, "foo", "bar"); // { dg-warning "constexpr message: bar \\\[foo\\\]" }
+ __builtin_constexpr_diag (2, "foo", "bar"); // { dg-error "constexpr message: bar \\\[foo\\\]" }
+ __builtin_constexpr_diag (0, "bar_baz", "bar"); // { dg-message "constexpr message: bar \\\[bar_baz\\\]" }
+ __builtin_constexpr_diag (1, "bar_baz", "bar"); // { dg-warning "constexpr message: bar \\\[bar_baz\\\]" }
+ __builtin_constexpr_diag (2, "bar_baz", "bar"); // { dg-error "constexpr message: bar \\\[bar_baz\\\]" }
+ __builtin_constexpr_diag (0, "baz", s); // { dg-message "constexpr message: 0123456789 \\\[baz\\\]" }
+ __builtin_constexpr_diag (1, "baz", T {}); // { dg-warning "constexpr message: bar \\\[baz\\\]" }
+ __builtin_constexpr_diag (2, "baz", U {}); // { dg-error "constexpr message: cdef \\\[baz\\\]" }
+ __builtin_constexpr_diag (0, "baz", V {}); // { dg-message "constexpr message: defgh \\\[baz\\\]" }
+ __builtin_constexpr_diag (1, "baz", W {}); // { dg-warning "constexpr message: fgh \\\[baz\\\]" }
+ __builtin_constexpr_diag (0, "", "bar"); // { dg-message "constexpr message: bar" }
+ __builtin_constexpr_diag (1, "", "bar"); // { dg-warning "constexpr message: bar" }
+ __builtin_constexpr_diag (2, "", "bar"); // { dg-error "constexpr message: bar" }
+}
--- /dev/null
+// { dg-do compile { target c++26 } }
+
+#include <string_view>
+
+namespace std
+{
+#if __has_builtin(__builtin_constexpr_diag)
+ struct _S_constexpr_tag_str {
+ private:
+ string_view _M_str;
+ public:
+ template <class _Tp>
+ requires convertible_to<const _Tp&, string_view>
+ consteval _S_constexpr_tag_str(const _Tp& __s) : _M_str(__s) {}
+ friend constexpr void constexpr_print_str(_S_constexpr_tag_str __tag,
+ string_view) noexcept;
+ friend constexpr void constexpr_print_str(_S_constexpr_tag_str __tag,
+ u8string_view) noexcept;
+ friend constexpr void constexpr_warning_str(_S_constexpr_tag_str,
+ string_view) noexcept;
+ friend constexpr void constexpr_warning_str(_S_constexpr_tag_str,
+ u8string_view) noexcept;
+ friend constexpr void constexpr_error_str(_S_constexpr_tag_str,
+ string_view) noexcept;
+ friend constexpr void constexpr_error_str(_S_constexpr_tag_str,
+ u8string_view) noexcept;
+ };
+ constexpr void constexpr_print_str(string_view __msg) noexcept
+ { return __builtin_constexpr_diag(16, "", __msg); }
+ constexpr void constexpr_print_str(u8string_view __msg) noexcept
+ { return __builtin_constexpr_diag(16, "", __msg); }
+ constexpr void constexpr_print_str(_S_constexpr_tag_str __tag,
+ string_view __msg) noexcept
+ { return __builtin_constexpr_diag(16, __tag._M_str, __msg); }
+ constexpr void constexpr_print_str(_S_constexpr_tag_str __tag,
+ u8string_view __msg) noexcept
+ { return __builtin_constexpr_diag(16, __tag._M_str, __msg); }
+ constexpr void constexpr_warning_str(_S_constexpr_tag_str __tag,
+ string_view __msg) noexcept
+ { return __builtin_constexpr_diag(17, __tag._M_str, __msg); }
+ constexpr void constexpr_warning_str(_S_constexpr_tag_str __tag,
+ u8string_view __msg) noexcept
+ { return __builtin_constexpr_diag(17, __tag._M_str, __msg); }
+ constexpr void constexpr_error_str(_S_constexpr_tag_str __tag,
+ string_view __msg) noexcept
+ { return __builtin_constexpr_diag(18, __tag._M_str, __msg); }
+ constexpr void constexpr_error_str(_S_constexpr_tag_str __tag,
+ u8string_view __msg) noexcept
+ { return __builtin_constexpr_diag(18, __tag._M_str, __msg); }
+#endif
+}
+
+consteval
+{
+ std::constexpr_print_str("foo"); // { dg-message "constexpr message: foo" }
+ std::constexpr_print_str(u8"bar"); // { dg-message "constexpr message: bar" }
+ std::constexpr_print_str("uninitialized", "foo"); // { dg-message "constexpr message: foo \\\[uninitialized\\\]" }
+ std::constexpr_print_str("uninitialized", u8"bar"); // { dg-message "constexpr message: bar \\\[uninitialized\\\]" }
+ std::constexpr_warning_str("uninitialized", "foo"); // { dg-warning "constexpr message: foo \\\[uninitialized\\\]" }
+ std::constexpr_warning_str("uninitialized", u8"bar"); // { dg-warning "constexpr message: bar \\\[uninitialized\\\]" }
+ std::constexpr_error_str("uninitialized", "foo"); // { dg-error "constexpr message: foo \\\[uninitialized\\\]" }
+ std::constexpr_error_str("uninitialized", u8"bar"); // { dg-error "constexpr message: bar \\\[uninitialized\\\]" }
+}
--- /dev/null
+// { dg-do compile { target c++26 } }
+
+struct A {
+ constexpr const char *data () const { return "foo"; }
+};
+struct B {
+ constexpr decltype (sizeof 0) size () const { return 3; }
+};
+struct C {
+ constexpr const char *data () const { return "bar"; }
+ decltype (sizeof 0) size () const { return 3; }
+};
+struct D {
+ const char *data () const { return "bar"; }
+ constexpr decltype (sizeof 0) size () const { return 3; }
+};
+struct E {};
+struct F {
+ constexpr const char *data () const { return "bar"; }
+ constexpr decltype (sizeof 0) size () const { return 3; }
+};
+struct G {
+ constexpr const char8_t *data () const { return u8"bar"; }
+ constexpr decltype (sizeof 0) size () const { return 3; }
+};
+
+consteval { __builtin_constexpr_diag (0); } // { dg-error "wrong number of arguments to '__builtin_constexpr_diag' call" }
+consteval { __builtin_constexpr_diag (0, ""); } // { dg-error "wrong number of arguments to '__builtin_constexpr_diag' call" }
+consteval { __builtin_constexpr_diag (0, "", "", ""); } // { dg-error "wrong number of arguments to '__builtin_constexpr_diag' call" }
+consteval { __builtin_constexpr_diag (3, "", ""); } // { dg-error "first '__builtin_constexpr_diag' call argument should be 0, 1, 2, 16, 17 or 18" }
+consteval { __builtin_constexpr_diag (-42, "", ""); } // { dg-error "first '__builtin_constexpr_diag' call argument should be 0, 1, 2, 16, 17 or 18" }
+consteval { __builtin_constexpr_diag (1, "abcdABCD_0189", ""); }// { dg-warning "constexpr message: \\\[abcdABCD_0189\\\]" }
+consteval { __builtin_constexpr_diag (2, "%+-", ""); } // { dg-error "'__builtin_constexpr_diag' tag string contains '\\\%' character other than letters, digits or '_'" }
+consteval { __builtin_constexpr_diag (0, u8"foo", "bar"); } // { dg-error "request for member 'size' in" }
+// { dg-error "constexpr string must be a string literal or object with 'size' and 'data' members" "" { target *-*-* } .-1 }
+consteval { __builtin_constexpr_diag (1, u8"foo", "bar"); } // { dg-error "request for member 'size' in" }
+// { dg-error "constexpr string must be a string literal or object with 'size' and 'data' members" "" { target *-*-* } .-1 }
+consteval { __builtin_constexpr_diag (2, u8"foo", "bar"); } // { dg-error "request for member 'size' in" }
+// { dg-error "constexpr string must be a string literal or object with 'size' and 'data' members" "" { target *-*-* } .-1 }
+consteval { __builtin_constexpr_diag (0, "foo", u8"bar"); } // { dg-message "constexpr message: bar \\\[foo\\\]" }
+consteval { __builtin_constexpr_diag (1, "foo", u8"bar"); } // { dg-warning "constexpr message: bar \\\[foo\\\]" }
+consteval { __builtin_constexpr_diag (2, "foo", u8"bar"); } // { dg-error "constexpr message: bar \\\[foo\\\]" }
+consteval { __builtin_constexpr_diag (0, A {}, "foo"); } // { dg-error "'struct A' has no member named 'size'" }
+// { dg-error "constexpr string must be a string literal or object with 'size' and 'data' members" "" { target *-*-* } .-1 }
+consteval { __builtin_constexpr_diag (1, B {}, "foo"); } // { dg-error "'struct B' has no member named 'data'" }
+// { dg-error "constexpr string must be a string literal or object with 'size' and 'data' members" "" { target *-*-* } .-1 }
+consteval { __builtin_constexpr_diag (2, C {}, "foo"); } // { dg-error "call to non-'constexpr' function '\[^\n\r]* C::size\\\(\\\) const'" }
+consteval { __builtin_constexpr_diag (0, D {}, "foo"); } // { dg-error "call to non-'constexpr' function 'const char\\\* D::data\\\(\\\) const'" }
+consteval { __builtin_constexpr_diag (1, E {}, "foo"); } // { dg-error "'struct E' has no member named 'size'" }
+// { dg-error "constexpr string must be a string literal or object with 'size' and 'data' members" "" { target *-*-* } .-1 }
+consteval { __builtin_constexpr_diag (2, F {}, "foo"); } // { dg-error "constexpr message: foo \\\[bar\\\]" }
+consteval { __builtin_constexpr_diag (0, G {}, "foo"); } // { dg-error "conversion from 'const char8_t\\\*' to 'const char\\\*' in a converted constant expression" }
+// { dg-error "could not convert '<anonymous>.G::data\\\(\\\)' from 'const char8_t\\\*' to 'const char\\\*'" "" { target *-*-* } .-1 }
+// { dg-error "constexpr string 'data\\\(\\\)' must be implicitly convertible to 'const char\\\*'" "" { target *-*-* } .-2 }
+consteval { __builtin_constexpr_diag (0, "", A {}); } // { dg-error "'struct A' has no member named 'size'" }
+// { dg-error "constexpr string must be a string literal or object with 'size' and 'data' members" "" { target *-*-* } .-1 }
+consteval { __builtin_constexpr_diag (1, "", B {}); } // { dg-error "'struct B' has no member named 'data'" }
+// { dg-error "constexpr string must be a string literal or object with 'size' and 'data' members" "" { target *-*-* } .-1 }
+consteval { __builtin_constexpr_diag (2, "", C {}); } // { dg-error "call to non-'constexpr' function '\[^\n\r]* C::size\\\(\\\) const'" }
+consteval { __builtin_constexpr_diag (0, "", D {}); } // { dg-error "call to non-'constexpr' function 'const char\\\* D::data\\\(\\\) const'" }
+consteval { __builtin_constexpr_diag (1, "", E {}); } // { dg-error "'struct E' has no member named 'size'" }
+// { dg-error "constexpr string must be a string literal or object with 'size' and 'data' members" "" { target *-*-* } .-1 }
+consteval { __builtin_constexpr_diag (2, "", F {}); } // { dg-error "constexpr message: bar" }
+consteval { __builtin_constexpr_diag (0, "", G {}); } // { dg-message "constexpr message: bar" }
--- /dev/null
+// { dg-do compile { target c++26 } }
+// { dg-require-iconv "IBM1047" }
+// { dg-additional-options "-fexec-charset=IBM1047" }
+
+struct S {
+ char buf[16];
+ constexpr const char *data () const { return buf; }
+ constexpr decltype (sizeof 0) size () const { for (int i = 0; i < 16; ++i) if (!buf[i]) return i; return 0; }
+};
+struct T {
+ constexpr const char *data () const { return "bar"; }
+ constexpr decltype (sizeof 0) size () const { return 3; }
+};
+constexpr char str[] = "abcdefg";
+struct U {
+ constexpr const char *data () const { return &str[2]; }
+ constexpr decltype (sizeof 0) size () const { return 4; }
+};
+struct V {
+ constexpr const char *data () const { return &"abcdefghi"[3]; }
+ constexpr decltype (sizeof 0) size () const { return 5; }
+};
+struct W {
+ constexpr const char *data () const { return &"abcdefghi"[3] + 2; }
+ constexpr decltype (sizeof 0) size () const { return 3; }
+};
+
+consteval
+{
+ S s;
+ for (int i = 0; i < 10; ++i)
+ s.buf[i] = '0' + i;
+ s.buf[10] = '\0';
+ __builtin_constexpr_diag (0, "foo", "bar"); // { dg-message "constexpr message: bar \\\[foo\\\]" }
+ __builtin_constexpr_diag (1, "foo", "bar"); // { dg-warning "constexpr message: bar \\\[foo\\\]" }
+ __builtin_constexpr_diag (2, "foo", "bar"); // { dg-error "constexpr message: bar \\\[foo\\\]" }
+ __builtin_constexpr_diag (0, "bar_baz", "bar"); // { dg-message "constexpr message: bar \\\[bar_baz\\\]" }
+ __builtin_constexpr_diag (1, "bar_baz", "bar"); // { dg-warning "constexpr message: bar \\\[bar_baz\\\]" }
+ __builtin_constexpr_diag (2, "bar_baz", "bar"); // { dg-error "constexpr message: bar \\\[bar_baz\\\]" }
+ __builtin_constexpr_diag (0, "baz", s); // { dg-message "constexpr message: 0123456789 \\\[baz\\\]" }
+ __builtin_constexpr_diag (1, "baz", T {}); // { dg-warning "constexpr message: bar \\\[baz\\\]" }
+ __builtin_constexpr_diag (2, "baz", U {}); // { dg-error "constexpr message: cdef \\\[baz\\\]" }
+ __builtin_constexpr_diag (0, "baz", V {}); // { dg-message "constexpr message: defgh \\\[baz\\\]" }
+ __builtin_constexpr_diag (1, "baz", W {}); // { dg-warning "constexpr message: fgh \\\[baz\\\]" }
+ __builtin_constexpr_diag (0, "", "bar"); // { dg-message "constexpr message: bar" }
+ __builtin_constexpr_diag (1, "", "bar"); // { dg-warning "constexpr message: bar" }
+ __builtin_constexpr_diag (2, "", "bar"); // { dg-error "constexpr message: bar" }
+}
--- /dev/null
+// { dg-do compile { target c++26 } }
+// { dg-require-iconv "IBM1047" }
+// { dg-additional-options "-fexec-charset=IBM1047" }
+
+#include <string_view>
+
+namespace std
+{
+#if __has_builtin(__builtin_constexpr_diag)
+ struct _S_constexpr_tag_str {
+ private:
+ string_view _M_str;
+ public:
+ template <class _Tp>
+ requires convertible_to<const _Tp&, string_view>
+ consteval _S_constexpr_tag_str(const _Tp& __s) : _M_str(__s) {}
+ friend constexpr void constexpr_print_str(_S_constexpr_tag_str __tag,
+ string_view) noexcept;
+ friend constexpr void constexpr_print_str(_S_constexpr_tag_str __tag,
+ u8string_view) noexcept;
+ friend constexpr void constexpr_warning_str(_S_constexpr_tag_str,
+ string_view) noexcept;
+ friend constexpr void constexpr_warning_str(_S_constexpr_tag_str,
+ u8string_view) noexcept;
+ friend constexpr void constexpr_error_str(_S_constexpr_tag_str,
+ string_view) noexcept;
+ friend constexpr void constexpr_error_str(_S_constexpr_tag_str,
+ u8string_view) noexcept;
+ };
+ constexpr void constexpr_print_str(string_view __msg) noexcept
+ { return __builtin_constexpr_diag(16, "", __msg); }
+ constexpr void constexpr_print_str(u8string_view __msg) noexcept
+ { return __builtin_constexpr_diag(16, "", __msg); }
+ constexpr void constexpr_print_str(_S_constexpr_tag_str __tag,
+ string_view __msg) noexcept
+ { return __builtin_constexpr_diag(16, __tag._M_str, __msg); }
+ constexpr void constexpr_print_str(_S_constexpr_tag_str __tag,
+ u8string_view __msg) noexcept
+ { return __builtin_constexpr_diag(16, __tag._M_str, __msg); }
+ constexpr void constexpr_warning_str(_S_constexpr_tag_str __tag,
+ string_view __msg) noexcept
+ { return __builtin_constexpr_diag(17, __tag._M_str, __msg); }
+ constexpr void constexpr_warning_str(_S_constexpr_tag_str __tag,
+ u8string_view __msg) noexcept
+ { return __builtin_constexpr_diag(17, __tag._M_str, __msg); }
+ constexpr void constexpr_error_str(_S_constexpr_tag_str __tag,
+ string_view __msg) noexcept
+ { return __builtin_constexpr_diag(18, __tag._M_str, __msg); }
+ constexpr void constexpr_error_str(_S_constexpr_tag_str __tag,
+ u8string_view __msg) noexcept
+ { return __builtin_constexpr_diag(18, __tag._M_str, __msg); }
+#endif
+}
+
+consteval
+{
+ std::constexpr_print_str("foo"); // { dg-message "constexpr message: foo" }
+ std::constexpr_print_str(u8"bar"); // { dg-message "constexpr message: bar" }
+ std::constexpr_print_str("uninitialized", "foo"); // { dg-message "constexpr message: foo \\\[uninitialized\\\]" }
+ std::constexpr_print_str("uninitialized", u8"bar"); // { dg-message "constexpr message: bar \\\[uninitialized\\\]" }
+ std::constexpr_warning_str("uninitialized", "foo"); // { dg-warning "constexpr message: foo \\\[uninitialized\\\]" }
+ std::constexpr_warning_str("uninitialized", u8"bar"); // { dg-warning "constexpr message: bar \\\[uninitialized\\\]" }
+ std::constexpr_error_str("uninitialized", "foo"); // { dg-error "constexpr message: foo \\\[uninitialized\\\]" }
+ std::constexpr_error_str("uninitialized", u8"bar"); // { dg-error "constexpr message: bar \\\[uninitialized\\\]" }
+}
--- /dev/null
+// { dg-do compile { target c++26 } }
+// { dg-require-iconv "IBM1047" }
+// { dg-additional-options "-fexec-charset=IBM1047" }
+
+struct A {
+ constexpr const char *data () const { return "foo"; }
+};
+struct B {
+ constexpr decltype (sizeof 0) size () const { return 3; }
+};
+struct C {
+ constexpr const char *data () const { return "bar"; }
+ decltype (sizeof 0) size () const { return 3; }
+};
+struct D {
+ const char *data () const { return "bar"; }
+ constexpr decltype (sizeof 0) size () const { return 3; }
+};
+struct E {};
+struct F {
+ constexpr const char *data () const { return "bar"; }
+ constexpr decltype (sizeof 0) size () const { return 3; }
+};
+struct G {
+ constexpr const char8_t *data () const { return u8"bar"; }
+ constexpr decltype (sizeof 0) size () const { return 3; }
+};
+
+consteval { __builtin_constexpr_diag (0); } // { dg-error "wrong number of arguments to '__builtin_constexpr_diag' call" }
+consteval { __builtin_constexpr_diag (0, ""); } // { dg-error "wrong number of arguments to '__builtin_constexpr_diag' call" }
+consteval { __builtin_constexpr_diag (0, "", "", ""); } // { dg-error "wrong number of arguments to '__builtin_constexpr_diag' call" }
+consteval { __builtin_constexpr_diag (3, "", ""); } // { dg-error "first '__builtin_constexpr_diag' call argument should be 0, 1, 2, 16, 17 or 18" }
+consteval { __builtin_constexpr_diag (-42, "", ""); } // { dg-error "first '__builtin_constexpr_diag' call argument should be 0, 1, 2, 16, 17 or 18" }
+consteval { __builtin_constexpr_diag (1, "abcdABCD_0189", ""); }// { dg-warning "constexpr message: \\\[abcdABCD_0189\\\]" }
+consteval { __builtin_constexpr_diag (2, "%+-", ""); } // { dg-error "'__builtin_constexpr_diag' tag string contains '\\\%' character other than letters, digits or '_'" }
+consteval { __builtin_constexpr_diag (0, u8"foo", "bar"); } // { dg-error "request for member 'size' in" }
+// { dg-error "constexpr string must be a string literal or object with 'size' and 'data' members" "" { target *-*-* } .-1 }
+consteval { __builtin_constexpr_diag (1, u8"foo", "bar"); } // { dg-error "request for member 'size' in" }
+// { dg-error "constexpr string must be a string literal or object with 'size' and 'data' members" "" { target *-*-* } .-1 }
+consteval { __builtin_constexpr_diag (2, u8"foo", "bar"); } // { dg-error "request for member 'size' in" }
+// { dg-error "constexpr string must be a string literal or object with 'size' and 'data' members" "" { target *-*-* } .-1 }
+consteval { __builtin_constexpr_diag (0, "foo", u8"bar"); } // { dg-message "constexpr message: bar \\\[foo\\\]" }
+consteval { __builtin_constexpr_diag (1, "foo", u8"bar"); } // { dg-warning "constexpr message: bar \\\[foo\\\]" }
+consteval { __builtin_constexpr_diag (2, "foo", u8"bar"); } // { dg-error "constexpr message: bar \\\[foo\\\]" }
+consteval { __builtin_constexpr_diag (0, A {}, "foo"); } // { dg-error "'struct A' has no member named 'size'" }
+// { dg-error "constexpr string must be a string literal or object with 'size' and 'data' members" "" { target *-*-* } .-1 }
+consteval { __builtin_constexpr_diag (1, B {}, "foo"); } // { dg-error "'struct B' has no member named 'data'" }
+// { dg-error "constexpr string must be a string literal or object with 'size' and 'data' members" "" { target *-*-* } .-1 }
+consteval { __builtin_constexpr_diag (2, C {}, "foo"); } // { dg-error "call to non-'constexpr' function '\[^\n\r]* C::size\\\(\\\) const'" }
+consteval { __builtin_constexpr_diag (0, D {}, "foo"); } // { dg-error "call to non-'constexpr' function 'const char\\\* D::data\\\(\\\) const'" }
+consteval { __builtin_constexpr_diag (1, E {}, "foo"); } // { dg-error "'struct E' has no member named 'size'" }
+// { dg-error "constexpr string must be a string literal or object with 'size' and 'data' members" "" { target *-*-* } .-1 }
+consteval { __builtin_constexpr_diag (2, F {}, "foo"); } // { dg-error "constexpr message: foo \\\[bar\\\]" }
+consteval { __builtin_constexpr_diag (0, G {}, "foo"); } // { dg-error "conversion from 'const char8_t\\\*' to 'const char\\\*' in a converted constant expression" }
+// { dg-error "could not convert '<anonymous>.G::data\\\(\\\)' from 'const char8_t\\\*' to 'const char\\\*'" "" { target *-*-* } .-1 }
+// { dg-error "constexpr string 'data\\\(\\\)' must be implicitly convertible to 'const char\\\*'" "" { target *-*-* } .-2 }
+consteval { __builtin_constexpr_diag (0, "", A {}); } // { dg-error "'struct A' has no member named 'size'" }
+// { dg-error "constexpr string must be a string literal or object with 'size' and 'data' members" "" { target *-*-* } .-1 }
+consteval { __builtin_constexpr_diag (1, "", B {}); } // { dg-error "'struct B' has no member named 'data'" }
+// { dg-error "constexpr string must be a string literal or object with 'size' and 'data' members" "" { target *-*-* } .-1 }
+consteval { __builtin_constexpr_diag (2, "", C {}); } // { dg-error "call to non-'constexpr' function '\[^\n\r]* C::size\\\(\\\) const'" }
+consteval { __builtin_constexpr_diag (0, "", D {}); } // { dg-error "call to non-'constexpr' function 'const char\\\* D::data\\\(\\\) const'" }
+consteval { __builtin_constexpr_diag (1, "", E {}); } // { dg-error "'struct E' has no member named 'size'" }
+// { dg-error "constexpr string must be a string literal or object with 'size' and 'data' members" "" { target *-*-* } .-1 }
+consteval { __builtin_constexpr_diag (2, "", F {}); } // { dg-error "constexpr message: bar" }
+consteval { __builtin_constexpr_diag (0, "", G {}); } // { dg-message "constexpr message: bar" }