On 2/17/26 5:05 PM, Jakub Jelinek wrote:
On Thu, Feb 12, 2026 at 09:02:55AM +0100, Jakub Jelinek wrote:
On Thu, Feb 12, 2026 at 01:48:59PM +0900, Jason Merrill wrote:
--- gcc/cp/constexpr.cc.jj      2026-02-09 09:06:41.657345262 +0100
+++ gcc/cp/constexpr.cc 2026-02-10 13:09:30.059258053 +0100
@@ -42,6 +42,7 @@ along with GCC; see the file COPYING3.
   #include "intl.h"
   #include "toplev.h"
   #include "contracts.h"
+#include "c-family/c-pragma.h"

Is this still needed for this version?

It is new in this version, so that parse_in can be used when translating
the messages back from exec charset/UTF-8 to SOURCE_CHARSET.
If it is moved to semantics.cc through overload with constexpr_ctx, I guess
it will not be needed.

Changed.

   static bool verify_constant (tree, bool, bool *, bool *);
   #define VERIFY_CONSTANT(X)                                           \
@@ -2314,6 +2315,295 @@ cxx_eval_cxa_builtin_fn (const constexpr
       }
   }
+/* 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) 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.  */

Please explain the significance of the two messages as well.  And also the
expected types.

Will do.

Done.

Why is the tag string before the message string, since the tag is the one
that's sometimes omitted?

Tag comes first because that is what P2758R5 says in its API, the builtin
attempts to match those (except that it has an extra first argument which
differentiates error/warning/print).

+         /* Can't use cstr.extract because it evaluates the
+            arguments in separate constexpr contexts.  */

Didn't I already suggest adding another overload that takes a constexpr_ctx?
This is too much code to duplicate in a user.

Will do.

Done as well.

+  constexpr void constexpr_print_str(string_view __msg) noexcept
+  { return __builtin_constexpr_diag(0, "", __msg); }                 // { dg-message 
"constexpr message: foo" }

Hmm, it would be more useful if the messages were at the call site of this
function rather than at the definition.  I guess you can get that location
from call_stack.  But this can be a followup.

Well, it really depends on whether one uses the builtin directly (when
the thing is not standardized yet, perhaps Jonathan will not want to
add the standard APIs in libstdc++ just yet) or through wrappers like
that.
One option would be figure the location_t of caller vs. of caller's caller
through checking if the caller is std::constexpr_{print,warning,error}_str,
another would be to say or in magic constant (say 16) into the first
argument if it wants caller's caller location_t.

Implemented using {0, 1, 2} | (0, 16} first argument.

Here is a new version, bootstrapped/regtested on x86_64-linux and
i686-linux, ok for trunk?

OK.

2026-02-17  Jakub Jelinek  <[email protected]>

gcc/cp/
        * cp-tree.h (enum cp_built_in_function): Add
        CP_BUILT_IN_CONSTEXPR_DIAG.
        (cexpr_str::cexpr_str): Add new default ctor.
        (cexpr_str::type_check): Add optional allow_char8_t arg.
        (cexpr_str::extract): Add optional ctx, non_constant_p, overflow_p
        and jump_target arguments.
        * cp-gimplify.cc (cp_gimplify_expr): Throw away
        __builtin_constexpr_diag calls after gimplification of
        their arguments.
        * decl.cc (cxx_init_decl_processing): Create __builtin_constexpr_diag
        FE builtin decl.
        * constexpr.cc (call_stack, call_stack_tick, last_cx_error_tick):
        Moved earlier.
        (cxx_eval_constexpr_diag): New function.
        (cxx_eval_builtin_function_call): Handle __builtin_constexpr_diag
        calls.
        * tree.cc (builtin_valid_in_constant_expr_p): Return true for
        CP_BUILT_IN_CONSTEXPR_DIAG.
        * semantics.cc (cexpr_str::type_check): Add allow_char8_t argument,
        if true, allow data to return const char8_t *.
        (cexpr_str::extract): Add ctx, non_constant_p, overflow_p and
        jump_target arguments, if they are non-NULL, evalute expressions
        in that context rather than using cxx_constant_value and translate
        back to SOURCE_CHARSET even if message_data or message_sz are NULL.
gcc/testsuite/
        * g++.dg/ext/constexpr-diag1.C: New test.
        * g++.dg/ext/constexpr-diag2.C: New test.
        * g++.dg/ext/constexpr-diag3.C: New test.
        * g++.dg/ext/constexpr-diag4.C: New test.
        * g++.dg/ext/constexpr-diag5.C: New test.
        * g++.dg/ext/constexpr-diag6.C: New test.

--- gcc/cp/cp-tree.h.jj 2026-02-14 18:04:56.430819319 +0100
+++ gcc/cp/cp-tree.h    2026-02-16 22:25:19.316652891 +0100
@@ -7105,6 +7105,7 @@ enum cp_built_in_function {
    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
  };
@@ -9542,12 +9543,15 @@ struct push_access_scope_guard
  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:
--- gcc/cp/cp-gimplify.cc.jj    2026-02-16 10:36:07.411596441 +0100
+++ gcc/cp/cp-gimplify.cc       2026-02-16 17:14:04.523142349 +0100
@@ -986,6 +986,9 @@ cp_gimplify_expr (tree *expr_p, gimple_s
                                                    &CALL_EXPR_ARG (*expr_p,
                                                                    0));
                break;
+             case CP_BUILT_IN_CONSTEXPR_DIAG:
+               *expr_p = void_node;
+               break;
              default:
                break;
              }
--- gcc/cp/decl.cc.jj   2026-02-14 18:04:51.789897334 +0100
+++ gcc/cp/decl.cc      2026-02-16 17:14:04.524173937 +0100
@@ -5612,6 +5612,15 @@ cxx_init_decl_processing (void)
                            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. */
--- gcc/cp/constexpr.cc.jj      2026-02-12 18:49:18.460869579 +0100
+++ gcc/cp/constexpr.cc 2026-02-16 22:25:34.728397470 +0100
@@ -2314,6 +2314,151 @@ cxx_eval_cxa_builtin_fn (const constexpr
      }
  }
+/* 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.  */
@@ -2374,6 +2519,10 @@ cxx_eval_builtin_function_call (const co
                                    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))
@@ -2846,14 +2995,6 @@ cxx_bind_parameters_in_call (const const
    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)
  {
--- gcc/cp/tree.cc.jj   2026-02-12 18:49:18.466869479 +0100
+++ gcc/cp/tree.cc      2026-02-16 17:14:04.526414882 +0100
@@ -569,6 +569,7 @@ builtin_valid_in_constant_expr_p (const_
          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;
--- gcc/cp/semantics.cc.jj      2026-02-16 17:02:34.144850448 +0100
+++ gcc/cp/semantics.cc 2026-02-16 17:59:43.715058381 +0100
@@ -12706,7 +12706,7 @@ init_cp_semantics (void)
     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;
@@ -12742,7 +12742,7 @@ cexpr_str::type_check (location_t locati
        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()%> "
@@ -12750,8 +12750,17 @@ cexpr_str::type_check (location_t locati
                    "%<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()%> "
@@ -12781,95 +12790,229 @@ cexpr_str::extract (location_t location,
     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
@@ -12880,13 +13023,6 @@ cexpr_str::extract (location_t location,
          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;
  }
--- gcc/testsuite/g++.dg/ext/constexpr-diag1.C.jj       2026-02-16 
17:14:04.527943160 +0100
+++ gcc/testsuite/g++.dg/ext/constexpr-diag1.C  2026-02-16 17:14:04.527943160 
+0100
@@ -0,0 +1,46 @@
+// { 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" }
+}
--- gcc/testsuite/g++.dg/ext/constexpr-diag2.C.jj       2026-02-16 
17:14:04.528031407 +0100
+++ gcc/testsuite/g++.dg/ext/constexpr-diag2.C  2026-02-16 18:27:01.325760506 
+0100
@@ -0,0 +1,63 @@
+// { 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\\\]" }
+}
--- gcc/testsuite/g++.dg/ext/constexpr-diag3.C.jj       2026-02-16 
17:14:04.528309318 +0100
+++ gcc/testsuite/g++.dg/ext/constexpr-diag3.C  2026-02-16 18:29:30.110277489 
+0100
@@ -0,0 +1,64 @@
+// { 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" }
--- gcc/testsuite/g++.dg/ext/constexpr-diag4.C.jj       2026-02-16 
17:14:04.528438567 +0100
+++ gcc/testsuite/g++.dg/ext/constexpr-diag4.C  2026-02-16 17:14:04.528438567 
+0100
@@ -0,0 +1,48 @@
+// { 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" }
+}
--- gcc/testsuite/g++.dg/ext/constexpr-diag5.C.jj       2026-02-16 
17:14:04.528545397 +0100
+++ gcc/testsuite/g++.dg/ext/constexpr-diag5.C  2026-02-16 18:27:31.862249564 
+0100
@@ -0,0 +1,65 @@
+// { 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\\\]" }
+}
--- gcc/testsuite/g++.dg/ext/constexpr-diag6.C.jj       2026-02-16 
17:14:04.528643443 +0100
+++ gcc/testsuite/g++.dg/ext/constexpr-diag6.C  2026-02-16 18:29:42.062078257 
+0100
@@ -0,0 +1,66 @@
+// { 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" }


        Jakub


Reply via email to