On Tue, Nov 21, 2023 at 11:19:56PM +0100, Jakub Jelinek wrote:
> > > +   error_at (location, "%<static_assert%> message must be a string "
> > > +                       "literal or object with %<size%> and "
> > > +                       "%<data%> members");
> > 
> > Let's print the type of the message as well.
> 
> so add " while it has type %qT", TREE_TYPE (message) or something else?

Now in patch form (except for the removal of warning_at for now):

2023-11-21  Jakub Jelinek  <ja...@redhat.com>

        PR c++/110348
gcc/
        * doc/invoke.texi (-Wno-c++26-extensions): Document.
gcc/c-family/
        * c.opt (Wc++26-extensions): New option.
        * c-cppbuiltin.cc (c_cpp_builtins): For C++26 predefine
        __cpp_static_assert to 202306L rather than 201411L.
gcc/cp/
        * parser.cc: Implement C++26 P2741R3 - user-generated static_assert
        messages.
        (cp_parser_static_assert): Parse message argument as
        conditional-expression if it is not a pure string literal or
        several of them concatenated followed by closing paren.
        * semantics.cc (finish_static_assert): Handle message which is not
        STRING_CST.  For condition with bare parameter packs return early.
        * pt.cc (tsubst_expr) <case STATIC_ASSERT>: Also tsubst_expr
        message and make sure that if it wasn't originally STRING_CST, it
        isn't after tsubst_expr either.
gcc/testsuite/
        * g++.dg/cpp26/static_assert1.C: New test.
        * g++.dg/cpp26/feat-cxx26.C (__cpp_static_assert): Expect
        202306L rather than 201411L.
        * g++.dg/cpp0x/udlit-error1.C: Expect different diagnostics for
        static_assert with user-defined literal.

--- gcc/doc/invoke.texi.jj      2023-11-21 21:00:41.980429829 +0100
+++ gcc/doc/invoke.texi 2023-11-21 23:25:16.849237207 +0100
@@ -9106,6 +9106,13 @@ Do not warn about C++23 constructs in co
 an older C++ standard.  Even without this option, some C++23 constructs
 will only be diagnosed if @option{-Wpedantic} is used.
 
+@opindex Wc++26-extensions
+@opindex Wno-c++26-extensions
+@item -Wno-c++26-extensions @r{(C++ and Objective-C++ only)}
+Do not warn about C++26 constructs in code being compiled using
+an older C++ standard.  Even without this option, some C++26 constructs
+will only be diagnosed if @option{-Wpedantic} is used.
+
 @opindex Wcast-qual
 @opindex Wno-cast-qual
 @item -Wcast-qual
--- gcc/c-family/c.opt.jj       2023-11-21 21:00:41.865431433 +0100
+++ gcc/c-family/c.opt  2023-11-21 23:25:16.850237193 +0100
@@ -498,6 +498,10 @@ Wc++23-extensions
 C++ ObjC++ Var(warn_cxx23_extensions) Warning Init(1)
 Warn about C++23 constructs in code compiled with an older standard.
 
+Wc++26-extensions
+C++ ObjC++ Var(warn_cxx26_extensions) Warning Init(1)
+Warn about C++26 constructs in code compiled with an older standard.
+
 Wcast-function-type
 C ObjC C++ ObjC++ Var(warn_cast_function_type) Warning EnabledBy(Wextra)
 Warn about casts between incompatible function types.
--- gcc/c-family/c-cppbuiltin.cc.jj     2023-11-21 21:00:41.865431433 +0100
+++ gcc/c-family/c-cppbuiltin.cc        2023-11-21 23:25:16.850237193 +0100
@@ -1023,7 +1023,8 @@ c_cpp_builtins (cpp_reader *pfile)
        {
          /* Set feature test macros for C++17.  */
          cpp_define (pfile, "__cpp_unicode_characters=201411L");
-         cpp_define (pfile, "__cpp_static_assert=201411L");
+         if (cxx_dialect <= cxx23)
+           cpp_define (pfile, "__cpp_static_assert=201411L");
          cpp_define (pfile, "__cpp_namespace_attributes=201411L");
          cpp_define (pfile, "__cpp_enumerator_attributes=201411L");
          cpp_define (pfile, "__cpp_nested_namespace_definitions=201411L");
@@ -1086,6 +1087,7 @@ c_cpp_builtins (cpp_reader *pfile)
        {
          /* Set feature test macros for C++26.  */
          cpp_define (pfile, "__cpp_constexpr=202306L");
+         cpp_define (pfile, "__cpp_static_assert=202306L");
        }
       if (flag_concepts)
         {
--- gcc/cp/parser.cc.jj 2023-11-21 21:00:41.933430484 +0100
+++ gcc/cp/parser.cc    2023-11-21 23:25:16.856237110 +0100
@@ -16616,6 +16616,7 @@ cp_parser_linkage_specification (cp_pars
    static_assert-declaration:
      static_assert ( constant-expression , string-literal ) ;
      static_assert ( constant-expression ) ; (C++17)
+     static_assert ( constant-expression, conditional-expression ) ; (C++26)
 
    If MEMBER_P, this static_assert is a class member.  */
 
@@ -16646,10 +16647,10 @@ cp_parser_static_assert (cp_parser *pars
 
   /* Parse the constant-expression.  Allow a non-constant expression
      here in order to give better diagnostics in finish_static_assert.  */
-  condition =
-    cp_parser_constant_expression (parser,
-                                   /*allow_non_constant_p=*/true,
-                                  /*non_constant_p=*/nullptr);
+  condition
+    = cp_parser_constant_expression (parser,
+                                    /*allow_non_constant_p=*/true,
+                                    /*non_constant_p=*/nullptr);
 
   if (cp_lexer_peek_token (parser->lexer)->type == CPP_CLOSE_PAREN)
     {
@@ -16668,8 +16669,32 @@ cp_parser_static_assert (cp_parser *pars
       /* Parse the separating `,'.  */
       cp_parser_require (parser, CPP_COMMA, RT_COMMA);
 
-      /* Parse the string-literal message.  */
-      if (cxx_dialect >= cxx26)
+      /* Parse the message expression.  */
+      bool string_lit = true;
+      for (unsigned int i = 1; ; ++i)
+       {
+         cp_token *tok = cp_lexer_peek_nth_token (parser->lexer, i);
+         if (cp_parser_is_pure_string_literal (tok))
+           continue;
+         else if (tok->type == CPP_CLOSE_PAREN)
+           break;
+         string_lit = false;
+         break;
+       }
+      if (!string_lit)
+       {
+         location_t loc = cp_lexer_peek_token (parser->lexer)->location;
+         if (cxx_dialect < cxx26)
+           pedwarn (loc, OPT_Wc__26_extensions,
+                    "%<static_assert%> with non-string message only "
+                    "available with %<-std=c++2c%> or %<-std=gnu++2c%>");
+
+         message = cp_parser_conditional_expression (parser);
+         if (TREE_CODE (message) == STRING_CST)
+           message = build1_loc (loc, PAREN_EXPR, TREE_TYPE (message),
+                                 message);
+       }
+      else if (cxx_dialect >= cxx26)
        message = cp_parser_unevaluated_string_literal (parser);
       else
        message = cp_parser_string_literal (parser, /*translate=*/false,
--- gcc/cp/semantics.cc.jj      2023-11-21 21:00:41.960430108 +0100
+++ gcc/cp/semantics.cc 2023-11-21 23:39:04.861665987 +0100
@@ -11434,6 +11434,7 @@ finish_static_assert (tree condition, tr
                      bool member_p, bool show_expr_p)
 {
   tsubst_flags_t complain = tf_warning_or_error;
+  tree message_sz = NULL_TREE, message_data = NULL_TREE;
 
   if (message == NULL_TREE
       || message == error_mark_node
@@ -11441,13 +11442,73 @@ finish_static_assert (tree condition, tr
       || condition == error_mark_node)
     return;
 
-  if (check_for_bare_parameter_packs (condition))
-    condition = error_mark_node;
+  if (check_for_bare_parameter_packs (condition)
+      || check_for_bare_parameter_packs (message))
+    return;
+
+  if (TREE_CODE (message) != STRING_CST
+      && !type_dependent_expression_p (message))
+    {
+      message_sz
+       = finish_class_member_access_expr (message,
+                                          get_identifier ("size"),
+                                          false, tf_none);
+      message_data
+       = finish_class_member_access_expr (message,
+                                          get_identifier ("data"),
+                                          false, tf_none);
+      if (message_sz == error_mark_node || message_data == error_mark_node)
+       {
+         error_at (location, "%<static_assert%> message must be a string "
+                             "literal or object with %<size%> and "
+                             "%<data%> members while it has type %qT",
+                             TREE_TYPE (message));
+         return;
+       }
+      releasing_vec size_args, data_args;
+      message_sz = finish_call_expr (message_sz, &size_args, false, false,
+                                    tf_warning_or_error);
+      message_data = finish_call_expr (message_data, &data_args, false, false,
+                                      tf_warning_or_error);
+      if (message_sz == error_mark_node || message_data == error_mark_node)
+       return;
+      if (tree s
+         = cp_get_callee_fndecl_nofold (extract_call_expr (message_sz)))
+       if (!DECL_DECLARED_CONSTEXPR_P (s))
+         warning_at (location, 0, "%qD used in %<static_assert%> message "
+                                  "is not %<constexpr%>", s);
+      tree t = build_converted_constant_expr (size_type_node, message_sz,
+                                             tf_none);
+      if (t == error_mark_node)
+       {
+         error_at (location, "%<static_assert%> message %<size()%> "
+                             "with type %qT must be implicitly convertible "
+                             "to %<std::size_t%>", TREE_TYPE (message_sz));
+         return;
+       }
+      message_sz = t;
+      if (tree d
+         = cp_get_callee_fndecl_nofold (extract_call_expr (message_data)))
+       if (!DECL_DECLARED_CONSTEXPR_P (d))
+         warning_at (location, 0, "%qD used in %<static_assert%> message "
+                                  "is not %<constexpr%>", d);
+      t = build_converted_constant_expr (const_string_type_node,
+                                        message_data, tf_none);
+      if (t == error_mark_node)
+       {
+         error_at (location, "%<static_assert%> message %<data()%> "
+                             "with type %qT must be implicitly convertible "
+                             "to %<const char*%>", TREE_TYPE (message_data));
+         return;
+       }
+      message_data = t;
+    }
 
   /* Save the condition in case it was a concept check.  */
   tree orig_condition = condition;
 
-  if (instantiation_dependent_expression_p (condition))
+  if (instantiation_dependent_expression_p (condition)
+      || instantiation_dependent_expression_p (message))
     {
       /* We're in a template; build a STATIC_ASSERT and put it in
          the right place. */
@@ -11485,9 +11546,89 @@ finish_static_assert (tree condition, tr
          if (processing_template_decl)
            goto defer;
 
-         int sz = TREE_INT_CST_LOW (TYPE_SIZE_UNIT
-                                    (TREE_TYPE (TREE_TYPE (message))));
-         int len = TREE_STRING_LENGTH (message) / sz - 1;
+         int len;
+         const char *msg = NULL;
+         char *buf = NULL;
+         if (message_sz && message_data)
+           {
+             tree msz = cxx_constant_value (message_sz, NULL_TREE, complain);
+             if (!tree_fits_uhwi_p (msz))
+               {
+                 error_at (location,
+                           "%<static_assert%> message %<size()%> "
+                           "must be a constant expression");
+                 return;
+               }
+             else if ((unsigned HOST_WIDE_INT) (int) tree_to_uhwi (msz)
+                      != tree_to_uhwi (msz))
+               {
+                 error_at (location,
+                           "%<static_assert%> message %<size()%> "
+                           "%qE too large", msz);
+                 return;
+               }
+             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))
+                       {
+                         error_at (location,
+                                   "%<static_assert%> message %<data()[%d]%> "
+                                   "must be a constant expression", i);
+                         return;
+                       }
+                     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,
+                               "%<static_assert%> message %<data()%> "
+                               "must be a core constant expression");
+                     return;
+                   }
+               }
+           }
+         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;
+           }
 
          /* See if we can find which clause was failing (for logical AND).  */
          tree bad = find_failing_clause (NULL, orig_condition);
@@ -11497,12 +11638,13 @@ finish_static_assert (tree condition, tr
 
          auto_diagnostic_group d;
 
-          /* Report the error. */
+         /* Report the error. */
          if (len == 0)
            error_at (cloc, "static assertion failed");
          else
-           error_at (cloc, "static assertion failed: %s",
-                     TREE_STRING_POINTER (message));
+           error_at (cloc, "static assertion failed: %.*s", len, msg);
+
+         XDELETEVEC (buf);
 
          diagnose_failing_condition (bad, cloc, show_expr_p);
        }
--- gcc/cp/pt.cc.jj     2023-11-21 21:00:41.938430415 +0100
+++ gcc/cp/pt.cc        2023-11-21 23:25:16.861237040 +0100
@@ -18701,15 +18701,20 @@ tsubst_stmt (tree t, tree args, tsubst_f
 
     case STATIC_ASSERT:
       {
-       tree condition;
+       tree condition, message;
 
        ++c_inhibit_evaluation_warnings;
        condition = tsubst_expr (STATIC_ASSERT_CONDITION (t), args,
                                 complain, in_decl);
+       message = tsubst_expr (STATIC_ASSERT_MESSAGE (t), args,
+                              complain, in_decl);
+       if (TREE_CODE (STATIC_ASSERT_MESSAGE (t)) != STRING_CST
+           && TREE_CODE (message) == STRING_CST)
+         message = build1_loc (STATIC_ASSERT_SOURCE_LOCATION (t),
+                               PAREN_EXPR, TREE_TYPE (message), message);
        --c_inhibit_evaluation_warnings;
 
-        finish_static_assert (condition,
-                              STATIC_ASSERT_MESSAGE (t),
+       finish_static_assert (condition, message,
                               STATIC_ASSERT_SOURCE_LOCATION (t),
                              /*member_p=*/false, /*show_expr_p=*/true);
       }
--- gcc/testsuite/g++.dg/cpp26/static_assert1.C.jj      2023-11-21 
23:25:16.861237040 +0100
+++ gcc/testsuite/g++.dg/cpp26/static_assert1.C 2023-11-21 23:48:10.630030663 
+0100
@@ -0,0 +1,300 @@
+// C++26 P2741R3 - user-generated static_assert messages
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+static_assert (true, "");
+static_assert (true, (""));    // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+                               // { dg-error "'static_assert' message must be 
a string literal or object with 'size' and 'data' members while it has type 
'const char \\\[1\\\]'" "" { target *-*-* } .-1 }
+static_assert (true, "" + 0);  // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+                               // { dg-error "'static_assert' message must be 
a string literal or object with 'size' and 'data' members while it has type 
'const char\\\*'" "" { target *-*-* } .-1 }
+static_assert (true, 0);       // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+                               // { dg-error "'static_assert' message must be 
a string literal or object with 'size' and 'data' members while it has type 
'int'" "" { target *-*-* } .-1 }
+struct A {};
+static_assert (true, A {});    // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+                               // { dg-error "'static_assert' message must be 
a string literal or object with 'size' and 'data' members while it has type 
'A'" "" { target *-*-* } .-1 }
+struct B { int size; };
+static_assert (true, B {});    // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+                               // { dg-error "'static_assert' message must be 
a string literal or object with 'size' and 'data' members while it has type 
'B'" "" { target *-*-* } .-1 }
+struct C { constexpr int size () const { return 0; } };
+static_assert (true, C {});    // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+                               // { dg-error "'static_assert' message must be 
a string literal or object with 'size' and 'data' members while it has type 
'C'" "" { target *-*-* } .-1 }
+struct D { constexpr int size () const { return 0; } int data; };
+static_assert (true, D {});    // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+                               // { dg-error "'D\\\(\\\).D::data' cannot be 
used as a function" "" { target *-*-* } .-1 }
+struct E { int size = 0;
+          constexpr const char *data () const { return ""; } };
+static_assert (true, E {});    // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+                               // { dg-error "'E\\\(\\\).E::size' cannot be 
used as a function" "" { target c++11_only } .-1 }
+                               // { dg-error "'E\\\{0\\\}.E::size' cannot be 
used as a function" "" { target c++14 } .-2 }
+struct F { constexpr const char *size () const { return ""; }
+          constexpr const char *data () const { return ""; } };
+static_assert (true, F {});    // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+                               // { dg-error "'static_assert' message 
'size\\\(\\\)' with type 'const char\\\*' must be implicitly convertible to 
'std::size_t'" "" { target *-*-* } .-1 }
+struct G { constexpr long size () const { return 0; }
+          constexpr float data () const { return 0.0f; } };
+static_assert (true, G {});    // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+                               // { dg-error "'static_assert' message 
'data\\\(\\\)' with type 'float' must be implicitly convertible to 'const 
char\\\*'" "" { target *-*-* } .-1 }
+struct H { short size () const { return 0; }
+          constexpr const char *data () const { return ""; } };
+static_assert (true, H {});    // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+                               // { dg-warning "'short int H::size\\\(\\\) 
const' used in 'static_assert' message is not 'constexpr'" "" { target *-*-* } 
.-1 }
+struct I { constexpr signed char size () const { return 0; }
+          const char *data () const { return ""; } };
+static_assert (true, I {});    // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+                               // { dg-warning "'const char\\\* 
I::data\\\(\\\) const' used in 'static_assert' message is not 'constexpr'" "" { 
target *-*-* } .-1 }
+struct J { constexpr int size () const { return j ? throw 1 : 0; }     // { 
dg-error "expression '<throw-expression>' is not a constant expression" }
+          constexpr const char *data () const { return ""; };
+          constexpr J (int x) : j (x) {}
+          int j; };
+static_assert (true, J (1));   // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+static_assert (false, J (0));  // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+                               // { dg-error "static assertion failed" "" { 
target *-*-* } .-1 }
+static_assert (false, J (1));  // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+                               // { dg-error "'static_assert' message 
'size\\\(\\\)' must be a constant expression" "" { target *-*-* } .-1 }
+struct K { constexpr operator int () { return 4; } };
+struct L { constexpr operator const char * () { return "test"; } };
+struct M { constexpr K size () const { return {}; }
+          constexpr L data () const { return {}; } };
+static_assert (true, M {});    // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+static_assert (false, M {});   // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+                               // { dg-error "static assertion failed: test" 
"" { target *-*-* } .-1 }
+#if  __cpp_constexpr_dynamic_alloc >= 201907L
+struct N { constexpr int size () const { return 3; }
+          constexpr const char *data () const { return new char[3] { 'b', 'a', 
'd' }; } }; // { dg-error "'\\\* N\\\(\\\).N::data\\\(\\\)' is not a constant 
expression because allocated storage has not been deallocated" "" { target 
c++20 } }
+static_assert (true, N {});    // { dg-warning "'static_assert' with 
non-string message only available with" "" { target { c++20 && c++23_down } } }
+static_assert (false, N {});   // { dg-warning "'static_assert' with 
non-string message only available with" "" { target { c++20 && c++23_down } } }
+                               // { dg-error "'static_assert' message 
'data\\\(\\\)\\\[0\\\]' must be a constant expression" "" { target c++20 } .-1 }
+#endif
+constexpr const char a[] = { 't', 'e', 's', 't' };
+struct O { constexpr int size () const { return 4; }
+          constexpr const char *data () const { return a; } };
+static_assert (false, O {});   // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+                               // { dg-error "static assertion failed: test" 
"" { target *-*-* } .-1 }
+struct P { constexpr int size () const { return 4 - p; }
+          constexpr const char *data () const { return &a[p]; }
+          constexpr P (int x) : p (x) {}
+          int p; };
+static_assert (false, P (0));  // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+                               // { dg-error "static assertion failed: test" 
"" { target *-*-* } .-1 }
+static_assert (false, P (2));  // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+                               // { dg-error "static assertion failed: st" "" 
{ target *-*-* } .-1 }
+struct Q { constexpr int size () const { return 4 - q; }
+          constexpr const char *data () const { return &"test"[q]; }
+          constexpr Q (int x) : q (x) {}
+          int q; };
+static_assert (false, Q (0));  // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+                               // { dg-error "static assertion failed: test" 
"" { target *-*-* } .-1 }
+static_assert (false, Q (1));  // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+                               // { dg-error "static assertion failed: est" "" 
{ target *-*-* } .-1 }
+struct R { constexpr int size () const { return 4 - r; }
+          constexpr const char *d () const { return "test"; }
+          constexpr const char *data () const { return d () + r; }
+          constexpr R (int x) : r (x) {}
+          int r; };
+static_assert (false, R (0));  // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+                               // { dg-error "static assertion failed: test" 
"" { target *-*-* } .-1 }
+static_assert (false, R (2));  // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+                               // { dg-error "static assertion failed: st" "" 
{ target *-*-* } .-1 }
+struct S { constexpr float size (float) const { return 42.0f; }
+          constexpr int size (void * = nullptr) const { return 4; }
+          constexpr double data (double) const { return 42.0; }
+          constexpr const char *data (int = 0) const { return "test"; } };
+static_assert (true, S {});    // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+static_assert (false, S {});   // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+                               // { dg-error "static assertion failed: test" 
"" { target *-*-* } .-1 }
+
+using size_t = decltype (sizeof (0));
+struct string_view {
+  size_t s;
+  const char *d;
+  constexpr string_view () : s (0), d (nullptr) {}
+  constexpr string_view (const char *p) : s (__builtin_strlen (p)), d (p) {}
+  constexpr string_view (size_t l, const char *p) : s (l), d (p) {}
+  constexpr size_t size () const noexcept { return s; }
+  constexpr const char *data () const noexcept { return d; }
+};
+static_assert (true, string_view{});                           // { dg-warning 
"'static_assert' with non-string message only available with" "" { target 
c++23_down } }
+static_assert (false, string_view ("test"));                   // { dg-warning 
"'static_assert' with non-string message only available with" "" { target 
c++23_down } }
+                                                               // { dg-error 
"static assertion failed: test" "" { target *-*-* } .-1 }
+static_assert (false, string_view ("א"));                      // { dg-warning 
"'static_assert' with non-string message only available with" "" { target 
c++23_down } }
+                                                               // { dg-error 
"static assertion failed: א" "" { target *-*-* } .-1 }
+static_assert (false, string_view (0, nullptr));               // { dg-warning 
"'static_assert' with non-string message only available with" "" { target 
c++23_down } }
+                                                               // { dg-error 
"static assertion failed" "" { target *-*-* } .-1 }
+static_assert (false, string_view (4, "testwithextrachars"));  // { dg-warning 
"'static_assert' with non-string message only available with" "" { target 
c++23_down } }
+                                                               // { dg-error 
"static assertion failed: test" "" { target *-*-* } .-1 }
+static_assert (false, string_view (42, "test"));               // { dg-warning 
"'static_assert' with non-string message only available with" "" { target 
c++23_down } }
+                                                               // { dg-error 
"array subscript value '41' is outside the bounds of array type 'const char 
\\\[5\\\]'" "" { target *-*-* } .-1 }
+                                                               // { dg-error 
"'static_assert' message 'data\\\(\\\)\\\[41\\\]' must be a constant 
expression" "" { target *-*-* } .-2 }
+
+template <typename T, size_t N>
+struct array {
+  constexpr size_t size () const { return N; }
+  constexpr const T *data () const { return a; }
+  const T a[N];
+};
+static_assert (true, array<char, 2> { 'O', 'K' });             // { dg-warning 
"'static_assert' with non-string message only available with" "" { target 
c++23_down } }
+static_assert (true, array<wchar_t, 2> { L'O', L'K' });                // { 
dg-warning "'static_assert' with non-string message only available with" "" { 
target c++23_down } }
+                                                               // { dg-error 
"'static_assert' message 'data\\\(\\\)' with type 'const wchar_t\\\*' must be 
implicitly convertible to 'const char\\\*'" "" { target *-*-* } .-1 }
+static_assert (false, array<char, 4> { 't', 'e', 's', 't' });  // { dg-warning 
"'static_assert' with non-string message only available with" "" { target 
c++23_down } }
+                                                               // { dg-error 
"static assertion failed: test" "" { target *-*-* } .-1 }
+
+void
+foo ()
+{
+  constexpr auto a = array<char, 4> { 't', 'e', 's', 't' };
+  static_assert (false, a);                                    // { dg-warning 
"'static_assert' with non-string message only available with" "" { target 
c++23_down } }
+}                                                              // { dg-error 
"static assertion failed: test" "" { target *-*-* } .-1 }
+
+#if  __cpp_constexpr_dynamic_alloc >= 201907L
+struct T {
+  const char *d = init ();
+  constexpr int size () const { return 4; }
+  constexpr const char *data () const { return d; }
+  constexpr const char *init () const { return new char[4] { 't', 'e', 's', 
't' }; }
+  constexpr ~T () { delete[] d; }
+};
+static_assert (false, T{});            // { dg-warning "'static_assert' with 
non-string message only available with" "" { target { c++20 && c++23_down } } }
+                                       // { dg-error "static assertion failed: 
test" "" { target c++20 } .-1 }
+#endif
+struct U { constexpr operator const char * () const { return u; }
+          char u[5] = "test"; };
+#if __cplusplus >= 201402L
+struct V { constexpr auto size () const { return K{}; }
+          constexpr auto data () const { return U{}; } };
+static_assert (false, V{});            // { dg-warning "'static_assert' with 
non-string message only available with" "" { target { c++14 && c++23_down } } }
+                                       // { dg-error "static assertion failed: 
test" "" { target c++14 } .-1 }
+#endif
+struct W { constexpr int size (int) const { return 4; }
+          constexpr const char *data () const { return "test"; } };
+static_assert (true, W{});             // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+                                       // { dg-error "no matching function for 
call to 'W::size\\\(\\\)'" "" { target *-*-* } .-1 }
+struct X { constexpr int size () const { return 4; }
+          constexpr const char *data (int) const { return "test"; } };
+static_assert (true, X{});             // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+                                       // { dg-error "no matching function for 
call to 'X::data\\\(\\\)'" "" { target *-*-* } .-1 }
+struct Y { constexpr int size () { return 4; }
+          constexpr const char *data (int) { return "test"; } };
+static_assert (true, Y{});             // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+                                       // { dg-error "no matching function for 
call to 'Y::data\\\(\\\)'" "" { target *-*-* } .-1 }
+#if __cpp_concepts >= 201907L
+struct Z { constexpr int size (auto...) const { return 4; }
+          constexpr const char *data (auto...) const { return "test"; } };
+static_assert (false, Z{});            // { dg-warning "'static_assert' with 
non-string message only available with" "" { target { c++20 && c++23_down } } }
+                                       // { dg-error "static assertion failed: 
test" "" { target c++20 } .-1 }
+#endif
+
+namespace NN
+{
+  template <typename T>
+  struct A {
+    constexpr int size () const = delete;
+    constexpr const char *data () const { return "test"; } };
+  static_assert (true, A<int>{});      // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+                                       // { dg-error "use of deleted function 
'constexpr int NN::A<T>::size\\\(\\\) const \\\[with T = int\\\]'" "" { target 
*-*-* } .-1 }
+#if __cpp_concepts >= 201907L
+  template <typename T>
+  struct B {
+    constexpr int size () const { return 4; }
+    constexpr const char *data () const requires false { return "test"; } };
+  static_assert (true, B<short>{});    // { dg-warning "'static_assert' with 
non-string message only available with" "" { target { c++20 && c++23_down } } }
+                                       // { dg-error "no matching function for 
call to 'NN::B<short int>::data\\\(\\\)'" "" { target c++20 } .-1 }
+#endif
+  class C {
+    constexpr int size () const = delete;
+    constexpr const char *data () const { return "test"; } };
+  static_assert (true, C{});           // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+                                       // { dg-error "use of deleted function 
'constexpr int NN::C::size\\\(\\\) const'" "" { target *-*-* } .-1 }
+                                       // { dg-error "'constexpr const 
char\\\* NN::C::data\\\(\\\) const' is private within this context" "" { target 
*-*-* } .-2 }
+#if __cplusplus >= 201402L
+  struct D {
+    constexpr int size () { return 4; }
+    constexpr int size () const { return 3; }
+    constexpr const char *data () { return "test"; }
+    constexpr const char *data () const { return "ehlo"; } };
+  static_assert (true, D{});   // { dg-warning "'static_assert' with 
non-string message only available with" "" { target { c++14 && c++23_down } } }
+  static_assert (false, D{});  // { dg-warning "'static_assert' with 
non-string message only available with" "" { target { c++14 && c++23_down } } }
+                               // { dg-error "static assertion failed: test" 
"" { target c++14 } .-1 }
+#endif
+  struct E {
+    constexpr int size () const { return 4; }
+    constexpr const char *data () const { return "test"; } };
+  template <typename T>
+  struct F {
+    static_assert (false, T{});        // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+  };                           // { dg-error "static assertion failed: test" 
"" { target *-*-* } .-1 }
+  template <typename T>
+  struct G {
+    static_assert (false, T{});        // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+  };                           // { dg-error "'static_assert' message must be 
a string literal or object with 'size' and 'data' members while it has type 
'long int'" "" { target *-*-* } .-1 }
+  F<E> fe;
+  G<long> gl;
+  constexpr E operator ""_myd (const char *, size_t) { return E{}; }
+  static_assert (false, "foo"_myd);    // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+                                       // { dg-error "static assertion failed: 
test" "" { target *-*-* } .-1 }
+  constexpr E operator + (const char *, const E &) { return E{}; }
+  static_assert (false, "foo" + E{});  // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+                                       // { dg-error "static assertion failed: 
test" "" { target *-*-* } .-1 }
+  struct H {
+    static constexpr int size () { return 7; }
+    static constexpr const char *data () { return "message"; } };
+  static_assert (true, H{});           // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+  static_assert (false, H{});          // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+                                       // { dg-error "static assertion failed: 
message" "" { target *-*-* } .-1 }
+  struct I {
+    static constexpr int size () { return 0; }
+    static constexpr const char *data () { return nullptr; } };
+  static_assert (true, I{});           // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+  static_assert (false, I{});          // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+                                       // { dg-error "static assertion failed" 
"" { target *-*-* } .-1 }
+#if __cplusplus >= 201402L
+  struct J {
+    static constexpr int size () { return 0; }
+    static constexpr const char *data (int x = 0) { if (x) return nullptr; 
else throw 1; } }; // { dg-error "expression '<throw-expression>' is not a 
constant expression" "" { target c++14 } } 
+  static_assert (true, J{});           // { dg-warning "'static_assert' with 
non-string message only available with" "" { target { c++14 && c++23_down } } }
+  static_assert (false, J{});          // { dg-warning "'static_assert' with 
non-string message only available with" "" { target { c++14 && c++23_down } } }
+                                       // { dg-error "'static_assert' message 
'data\\\(\\\)' must be a core constant expression" "" { target c++14 } .-1 }
+#endif
+#if __cpp_if_consteval >= 202106L
+  struct K {
+    static constexpr int size () { if consteval { return 4; } else { throw 1; 
} }
+    static constexpr const char *data () { return "test"; }
+  };
+  static_assert (true, K{});           // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_only } }
+  static_assert (false, K{});          // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_only } }
+                                       // { dg-error "static assertion failed: 
test" "" { target c++23 } .-1 }
+  struct L {
+    static constexpr int size () { return 4; }
+    static constexpr const char *data () { if consteval { return "test"; } 
else { throw 1; } }
+  };
+  static_assert (true, L{});           // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_only } }
+  static_assert (false, L{});          // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_only } }
+                                       // { dg-error "static assertion failed: 
test" "" { target c++23 } .-1 }
+  struct M {
+    static constexpr int size () { if consteval { throw 1; } else { return 4; 
} } // { dg-error "expression '<throw-expression>' is not a constant 
expression" "" { target c++23 } }
+    static constexpr const char *data () { return "test"; }
+  };
+  static_assert (true, M{});           // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_only } }
+  static_assert (false, M{});          // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_only } }
+                                       // { dg-error "'static_assert' message 
'size\\\(\\\)' must be a constant expression" "" { target c++23 } .-1 }
+  struct N {
+    static constexpr int size () { return 4; }
+    static constexpr const char *data () { if consteval { throw 1; } else { 
return "test"; } } // { dg-error "expression '<throw-expression>' is not a 
constant expression" "" { target c++23 } }
+  };
+  static_assert (true, N{});           // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_only } }
+  static_assert (false, N{});          // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_only } }
+                                       // { dg-error "'static_assert' message 
'data\\\(\\\)\\\[0\\\]' must be a constant expression" "" { target c++23 } .-1 }
+#endif
+  struct O { constexpr int operator () () const { return 12; } };
+  struct P { constexpr const char *operator () () const { return "another 
test"; } };
+  struct Q { O size; P data; };
+  static_assert (true, Q ());  // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+  static_assert (false, Q {}); // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+                               // { dg-error "static assertion failed: another 
test" "" { target *-*-* } .-1 }
+  constexpr int get_size () { return 16; }
+  constexpr const char *get_data () { return "yet another test"; }
+  struct R { int (*size) () = NN::get_size;
+            const char *(*data) () = NN::get_data; };
+  static_assert (true, R ());  // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+  static_assert (false, R {}); // { dg-warning "'static_assert' with 
non-string message only available with" "" { target c++23_down } }
+                               // { dg-error "static assertion failed: yet 
another test" "" { target *-*-* } .-1 }
+}
--- gcc/testsuite/g++.dg/cpp26/feat-cxx26.C.jj  2023-11-21 21:00:42.024429214 
+0100
+++ gcc/testsuite/g++.dg/cpp26/feat-cxx26.C     2023-11-21 23:25:16.861237040 
+0100
@@ -304,8 +304,8 @@
 
 #ifndef __cpp_static_assert
 #  error "__cpp_static_assert"
-#elif __cpp_static_assert != 201411
-#  error "__cpp_static_assert != 201411"
+#elif __cpp_static_assert != 202306
+#  error "__cpp_static_assert != 202306"
 #endif
 
 #ifndef __cpp_namespace_attributes
--- gcc/testsuite/g++.dg/cpp0x/udlit-error1.C.jj        2023-11-21 
21:00:42.004429494 +0100
+++ gcc/testsuite/g++.dg/cpp0x/udlit-error1.C   2023-11-21 23:25:16.861237040 
+0100
@@ -11,7 +11,8 @@ void operator""_x(const char *, decltype
 #pragma message "hi"_x   // { dg-warning "string literal with user-defined 
suffix is invalid in this context" }
 
 extern "C"_x { void g(); } // { dg-error "before user-defined string literal" }
-static_assert(true, "foo"_x); // { dg-error "string literal with user-defined 
suffix is invalid in this context|expected" }
+static_assert(true, "foo"_x);  // { dg-error "'static_assert' with non-string 
message only available with" "" { target c++23_down } }
+                               // { dg-error "'static_assert' message must be 
a string literal or object with 'size' and 'data' members" "" { target *-*-* } 
.-1 }
 
 [[deprecated("oof"_x)]]        // { dg-error "string literal with user-defined 
suffix is invalid in this context" "" { target c++26 } }
 void


        Jakub

Reply via email to