Hi!

Here is a slightly updated version of the patch.
Fixes the mce_unknown case (sets *non_constant_p in that
case so that we e.g. don't try to cache results without emitting
diagnostics), the previous patch was incorrect in that part
and returned the CALL_EXPR instead of void_node while not setting
*non_constant_p.
Doesn't implicitly add W in front of the tag when looking it up,
I think it is better when people write "Wuninitialized" rather than
just "uninitialized".
Emits the tag whenever it is non-empty and warning doesn't emit it,
in similar style/color to the warning [-Woption] strings.
And adds testsuite coverage.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

Note, haven't added user documentation for this because it might change
behavior before C++29 gets something voted in, or perhaps have
the custom tags support added or whatever.

2025-11-12  Jakub Jelinek  <[email protected]>

gcc/cp/
        * cp-tree.h (enum cp_built_in_function): Add
        CP_BUILT_IN_CONSTEXPR_DIAG.
        (cexpr_str::type_check): Add optional allow_char8_t arg.
        (cexpr_str::get_data, cexpr_str::get_sz): New.
        * 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 (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 *.
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.

--- gcc/cp/cp-tree.h.jj 2025-11-12 18:23:48.790468748 +0100
+++ gcc/cp/cp-tree.h    2025-11-12 18:24:25.463278871 +0100
@@ -6894,6 +6894,7 @@ enum cp_built_in_function {
   CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS,
   CP_BUILT_IN_SOURCE_LOCATION,
   CP_BUILT_IN_EH_PTR_ADJUST_REF,
+  CP_BUILT_IN_CONSTEXPR_DIAG,
   CP_BUILT_IN_LAST
 };
 
@@ -9245,9 +9246,11 @@ public:
   cexpr_str (const cexpr_str &) = delete;
   ~cexpr_str () { XDELETEVEC (buf); }
 
-  bool type_check (location_t location);
+  bool type_check (location_t location, bool allow_char8_t = false);
   bool extract (location_t location, const char * & msg, int &len);
   bool extract (location_t location, tree &str);
+  tree get_data () const { return message_data; }
+  tree get_sz () const { return message_sz; }
   tree message;
 private:
   tree message_data = NULL_TREE;
--- gcc/cp/cp-gimplify.cc.jj    2025-11-12 18:23:48.789468762 +0100
+++ gcc/cp/cp-gimplify.cc       2025-11-12 18:24:25.466907281 +0100
@@ -956,6 +956,9 @@ cp_gimplify_expr (tree *expr_p, gimple_s
                          "__builtin_eh_ptr_adjust_ref");
                *expr_p = void_node;
                break;
+             case CP_BUILT_IN_CONSTEXPR_DIAG:
+               *expr_p = void_node;
+               break;
              default:
                break;
              }
--- gcc/cp/decl.cc.jj   2025-11-12 18:23:48.792468720 +0100
+++ gcc/cp/decl.cc      2025-11-12 18:24:25.465689864 +0100
@@ -5574,6 +5574,15 @@ cxx_init_decl_processing (void)
       set_call_expr_flags (decl, 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      2025-11-12 18:23:48.767469067 +0100
+++ gcc/cp/constexpr.cc 2025-11-12 19:11:04.085138360 +0100
@@ -2262,6 +2262,268 @@ 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.  */
+
+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]) > 2)
+    {
+      if (!ctx->quiet)
+       error_at (loc, "first %qs call argument should be 0, 1 or 2",
+                 "__builtin_constexpr_diag");
+      *non_constant_p = true;
+      return t;
+    }
+  const char *msgs[2] = {};
+  bool to_free[2] = {};
+  int lens[3] = {};
+  int opt_index = OPT_SPECIAL_unknown;
+  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;
+           }
+       }
+      cexpr_str cstr (arg);
+      if (!cstr.type_check (loc, i == 2))
+       {
+         *non_constant_p = true;
+         return t;
+       }
+      if (TREE_CODE (arg) == STRING_CST)
+       cstr.extract (loc, msgs[i - 1], lens[i - 1]);
+      else
+       {
+         /* Can't use cstr.extract because it evaluates the
+            arguments in separate constexpr contexts.  */
+         tree msz = cstr.get_sz ();
+         tree mdata = cstr.get_data ();
+         msz = cxx_eval_constant_expression (ctx, msz, vc_prvalue,
+                                             non_constant_p, overflow_p,
+                                             jump_target);
+         if (*jump_target)
+           return NULL_TREE;
+         if (*non_constant_p)
+           return t;
+         if (!tree_fits_uhwi_p (msz))
+           {
+             if (!ctx->quiet)
+               error_at (loc, "constexpr string %<size()%> "
+                         "must be a constant expression");
+             *non_constant_p = true;
+             goto out;
+           }
+         else if ((unsigned HOST_WIDE_INT) (int) tree_to_uhwi (msz)
+                  != tree_to_uhwi (msz))
+           {
+             if (!ctx->quiet)
+               error_at (loc, "constexpr string message %<size()%> "
+                         "%qE too large", msz);
+             *non_constant_p = true;
+             goto out;
+           }
+         lens[i - 1] = tree_to_uhwi (msz);
+         mdata = cxx_eval_constant_expression (ctx, mdata, vc_prvalue,
+                                               non_constant_p, overflow_p,
+                                               jump_target);
+         if (*jump_target)
+           {
+             t = NULL_TREE;
+             goto out;
+           }
+         if (*non_constant_p)
+           goto out;
+         STRIP_NOPS (mdata);
+         if (TREE_CODE (mdata) != ADDR_EXPR)
+           {
+           unhandled:
+             if (!ctx->quiet)
+               error_at (loc, "unhandled return from %<data()%>");
+             *non_constant_p = true;
+             goto out;
+           }
+         tree str = TREE_OPERAND (mdata, 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)
+           {
+             t = NULL_TREE;
+             goto out;
+           }
+         if (*non_constant_p)
+           goto out;
+         if (TREE_CODE (str) == STRING_CST)
+           {
+             if (TREE_STRING_LENGTH (str) < lens[i - 1]
+                 || (unsigned) TREE_STRING_LENGTH (str) < off
+                 || (unsigned) TREE_STRING_LENGTH (str) < off + lens[i - 1])
+               goto unhandled;
+             msgs[i - 1] = TREE_STRING_POINTER (str) + off;
+             continue;
+           }
+         if (TREE_CODE (str) != CONSTRUCTOR
+             || TREE_CODE (TREE_TYPE (str)) != ARRAY_TYPE)
+           goto unhandled;
+         char *buf;
+         if (lens[i - 1] < 64)
+           buf = XALLOCAVEC (char, lens[i - 1] + 1);
+         else
+           {
+             buf = XNEWVEC (char, lens[i - 1] + 1);
+             to_free[i - 1] = true;
+           }
+         msgs[i - 1] = buf;
+         memset (buf, 0, lens[i - 1] + 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 + lens[i - 1])
+                 buf[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 + lens[i - 1])
+                   buf[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 + lens[i - 1])
+                 buf[l - off] = tree_to_shwi (value);
+               l++;
+             }
+         buf[lens[i - 1]] = '\0';
+       }
+    }
+  if (msgs[0])
+    {
+      for (int i = 0; i < lens[0]; ++i)
+       if (!ISALNUM (msgs[0][i]) && 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;
+           goto out;
+         }
+    }
+  if (ctx->manifestly_const_eval == mce_unknown)
+    {
+      *non_constant_p = true;
+      goto out;
+    }
+  if (msgs[0] && lens[0])
+    {
+      char *new_option = XNEWVEC (char, lens[0] + 1);
+      memcpy (new_option, msgs[0], lens[0]);
+      new_option[lens[0]] = '\0';
+      opt_index = find_opt (new_option, CL_CXX);
+      XDELETEVEC (new_option);
+      if (opt_index != OPT_SPECIAL_unknown
+         && !(cl_options[opt_index].flags & CL_WARNING))
+       opt_index = OPT_SPECIAL_unknown;
+    }
+  if (integer_zerop (args[0]))
+    kind = diagnostics::kind::note;
+  else if (integer_onep (args[0]))
+    kind = diagnostics::kind::warning;
+  if (opt_index != OPT_SPECIAL_unknown && kind == diagnostics::kind::warning)
+    emit_diagnostic (kind, loc, opt_index, "constexpr message: %.*s",
+                    lens[1], msgs[1]);
+  else 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]);
+  t = void_node;
+out:
+  if (to_free[0])
+    XDELETEVEC (const_cast <char *> (msgs[0]));
+  if (to_free[1])
+    XDELETEVEC (const_cast <char *> (msgs[1]));
+  return t;
+}
+
 /* 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.  */
@@ -2322,6 +2584,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))
--- gcc/cp/tree.cc.jj   2025-11-12 18:23:48.793468706 +0100
+++ gcc/cp/tree.cc      2025-11-12 18:24:25.459960406 +0100
@@ -489,6 +489,7 @@ builtin_valid_in_constant_expr_p (const_
          case CP_BUILT_IN_IS_CORRESPONDING_MEMBER:
          case CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS:
          case CP_BUILT_IN_EH_PTR_ADJUST_REF:
+         case CP_BUILT_IN_CONSTEXPR_DIAG:
            return true;
          default:
            break;
--- gcc/cp/semantics.cc.jj      2025-11-12 18:23:48.793468706 +0100
+++ gcc/cp/semantics.cc 2025-11-12 18:24:25.464252942 +0100
@@ -12493,7 +12493,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;
 
@@ -12529,7 +12529,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()%> "
@@ -12537,8 +12537,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()%> "
--- gcc/testsuite/g++.dg/ext/constexpr-diag1.C.jj       2025-11-12 
18:45:16.433607544 +0100
+++ gcc/testsuite/g++.dg/ext/constexpr-diag1.C  2025-11-12 18:53:18.465917008 
+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, "Wformat=", "bar");     // { dg-message 
"constexpr message: bar \\\[Wformat=\\\]" }
+  __builtin_constexpr_diag (1, "Wformat=", "bar");
+  __builtin_constexpr_diag (2, "Wformat=", "bar");     // { dg-error 
"constexpr message: bar \\\[Wformat=\\\]" }
+  __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       2025-11-12 
18:45:19.579563878 +0100
+++ gcc/testsuite/g++.dg/ext/constexpr-diag2.C  2025-11-12 18:57:11.963676082 
+0100
@@ -0,0 +1,64 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-Wuninitialized" }
+
+#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(0, "", __msg); }                   // { 
dg-message "constexpr message: foo" }
+  constexpr void constexpr_print_str(u8string_view __msg) noexcept
+  { return __builtin_constexpr_diag(0, "", __msg); }                   // { 
dg-message "constexpr message: bar" }
+  constexpr void constexpr_print_str(_S_constexpr_tag_str __tag,
+                                    string_view __msg) noexcept
+  { return __builtin_constexpr_diag(0, __tag._M_str, __msg); }         // { 
dg-message "constexpr message: foo \\\[Wuninitialized\\\]" }
+  constexpr void constexpr_print_str(_S_constexpr_tag_str __tag,
+                                    u8string_view __msg) noexcept
+  { return __builtin_constexpr_diag(0, __tag._M_str, __msg); }         // { 
dg-message "constexpr message: bar \\\[Wuninitialized\\\]" }
+  constexpr void constexpr_warning_str(_S_constexpr_tag_str __tag,
+                                      string_view __msg) noexcept
+  { return __builtin_constexpr_diag(1, __tag._M_str, __msg); }         // { 
dg-warning "constexpr message: foo \\\[-Wuninitialized\\\]" }
+  constexpr void constexpr_warning_str(_S_constexpr_tag_str __tag,
+                                      u8string_view __msg) noexcept
+  { return __builtin_constexpr_diag(1, __tag._M_str, __msg); }         // { 
dg-warning "constexpr message: bar \\\[-Wuninitialized\\\]" }
+  constexpr void constexpr_error_str(_S_constexpr_tag_str __tag,
+                                    string_view __msg) noexcept
+  { return __builtin_constexpr_diag(2, __tag._M_str, __msg); }         // { 
dg-error "constexpr message: foo \\\[Wuninitialized\\\]" }
+  constexpr void constexpr_error_str(_S_constexpr_tag_str __tag,
+                                    u8string_view __msg) noexcept
+  { return __builtin_constexpr_diag(2, __tag._M_str, __msg); }         // { 
dg-error "constexpr message: bar \\\[Wuninitialized\\\]" }
+#endif
+}
+
+consteval
+{
+  std::constexpr_print_str("foo");
+  std::constexpr_print_str(u8"bar");
+  std::constexpr_print_str("Wuninitialized", "foo");
+  std::constexpr_print_str("Wuninitialized", u8"bar");
+  std::constexpr_warning_str("Wuninitialized", "foo");
+  std::constexpr_warning_str("Wuninitialized", u8"bar");
+  std::constexpr_error_str("Wuninitialized", "foo");
+  std::constexpr_error_str("Wuninitialized", u8"bar");
+}
--- gcc/testsuite/g++.dg/ext/constexpr-diag3.C.jj       2025-11-12 
18:45:34.674354365 +0100
+++ gcc/testsuite/g++.dg/ext/constexpr-diag3.C  2025-11-12 18:53:51.911452783 
+0100
@@ -0,0 +1,47 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-Wformat=2" }
+
+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, "Wformat=", "bar");     // { dg-message 
"constexpr message: bar \\\[Wformat=\\\]" }
+  __builtin_constexpr_diag (1, "Wformat=", "bar");     // { dg-warning 
"constexpr message: bar \\\[-Wformat=\\\]" }
+  __builtin_constexpr_diag (2, "Wformat=", "bar");     // { dg-error 
"constexpr message: bar \\\[Wformat=\\\]" }
+  __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-diag4.C.jj       2025-11-12 
18:58:44.709388779 +0100
+++ gcc/testsuite/g++.dg/ext/constexpr-diag4.C  2025-11-12 19:19:48.401871274 
+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 or 2" }
+consteval { __builtin_constexpr_diag (-42, "", ""); }          // { dg-error 
"first '__builtin_constexpr_diag' call argument should be 0, 1 or 2" }
+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