On 1/8/25 9:19 AM, Jakub Jelinek wrote:
On Tue, Jan 07, 2025 at 03:20:35PM -0800, Andi Kleen wrote:
There is one case I didn't handle and I'd like to discuss.
The initial commit to enable this new extension also changed
cp_parser_asm_specification_opt to use cp_parser_asm_string_expression.
That function doesn't have anything to do with asm statements though,
it is about asm redirection of declarations.

I don't know of a use case for this, so i guess it can be rejected

Ok.

@@ -30067,7 +30063,11 @@ cp_parser_asm_specification_opt (cp_parser* parser)
    parens.require_open (parser);
/* Look for the string-literal. */
+  token = cp_lexer_peek_token (parser->lexer);
    tree asm_specification = cp_parser_asm_string_expression (parser);
+  if (TREE_CODE (asm_specification) != STRING_CST)
+    error_at (token->location,
+             "%<asm%> specification for declaration must be string");

Much easier to just revert your 2024-06-24 changes in that function.

Since you add a return of error_mark_node to finish_asm_stmt you
also need this patchlet:

You're right (just in case also changed it in parser.cc).

It needs a test case with constexpr errors too. In my version I had
a lot of trouble with them.

I've ported my c++26/static_assert1.C testcase for this, just left out

#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; }
};
#endif

void
foo ()
{
#if  __cpp_constexpr_dynamic_alloc >= 201907L
   asm ((T{}));
#endif
}

part which I think should work (it works with static_assert) but doesn't
really work with asm.  Will look at it incrementally, just need to work on
some mass rebuild ICEs and backporting now.

So far just lightly tested, ok for trunk if it passes full
bootstrap/regtest?

OK.

2025-01-08  Jakub Jelinek  <ja...@redhat.com>

        PR c++/118277
        * cp-tree.h (finish_asm_string_expression): Declare.
        * semantics.cc (finish_asm_string_expression): New function.
        (finish_asm_stmt): Use it.
        * parser.cc (cp_parser_asm_string_expression): Likewise.
        Wrap string into PAREN_EXPR in the ("") case.
        (cp_parser_asm_definition): Don't ICE if finish_asm_stmt
        returns error_mark_node.
        (cp_parser_asm_specification_opt): Revert 2024-06-24 changes.
        * pt.cc (tsubst_stmt): Don't ICE if finish_asm_stmt returns
        error_mark_node.

        * g++.dg/cpp1z/constexpr-asm-4.C: New test.
        * g++.dg/cpp1z/constexpr-asm-5.C: New test.

--- gcc/cp/cp-tree.h.jj 2025-01-07 13:13:31.042023537 +0100
+++ gcc/cp/cp-tree.h    2025-01-08 12:17:32.349673711 +0100
@@ -7946,6 +7946,7 @@ enum {
  extern tree begin_compound_stmt                       (unsigned int);
extern void finish_compound_stmt (tree);
+extern tree finish_asm_string_expression       (location_t, tree);
  extern tree finish_asm_stmt                   (location_t, int, tree, tree,
                                                 tree, tree, tree, bool, bool);
  extern tree finish_label_stmt                 (tree);
--- gcc/cp/semantics.cc.jj      2025-01-07 13:13:31.079023023 +0100
+++ gcc/cp/semantics.cc 2025-01-08 14:51:52.583352223 +0100
@@ -2133,6 +2133,29 @@ finish_compound_stmt (tree stmt)
    add_stmt (stmt);
  }
+/* Finish an asm string literal, which can be a string literal
+   or parenthesized constant expression.  Extract the string literal
+   from the latter.  */
+
+tree
+finish_asm_string_expression (location_t loc, tree string)
+{
+  if (string == error_mark_node
+      || TREE_CODE (string) == STRING_CST
+      || processing_template_decl)
+    return string;
+  string = cxx_constant_value (string, tf_error);
+  if (TREE_CODE (string) == STRING_CST)
+    string = build1_loc (loc, PAREN_EXPR, TREE_TYPE (string),
+                        string);
+  cexpr_str cstr (string);
+  if (!cstr.type_check (loc))
+    return error_mark_node;
+  if (!cstr.extract (loc, string))
+    string = error_mark_node;
+  return string;
+}
+
  /* Finish an asm-statement, whose components are a STRING, some
     OUTPUT_OPERANDS, some INPUT_OPERANDS, some CLOBBERS and some
     LABELS.  Also note whether the asm-statement should be
@@ -2159,6 +2182,26 @@ finish_asm_stmt (location_t loc, int vol
oconstraints = XALLOCAVEC (const char *, noutputs); + string = finish_asm_string_expression (cp_expr_loc_or_loc (string, loc),
+                                            string);
+      if (string == error_mark_node)
+       return error_mark_node;
+      for (int i = 0; i < 2; ++i)
+       for (t = i ? input_operands : output_operands; t; t = TREE_CHAIN (t))
+         {
+           tree s = TREE_VALUE (TREE_PURPOSE (t));
+           s = finish_asm_string_expression (cp_expr_loc_or_loc (s, loc), s);
+           if (s == error_mark_node)
+             return error_mark_node;
+           TREE_VALUE (TREE_PURPOSE (t)) = s;
+         }
+      for (t = clobbers; t; t = TREE_CHAIN (t))
+       {
+         tree s = TREE_VALUE (t);
+         s = finish_asm_string_expression (cp_expr_loc_or_loc (s, loc), s);
+         TREE_VALUE (t) = s;
+       }
+
        string = resolve_asm_operand_names (string, output_operands,
                                          input_operands, labels);
--- gcc/cp/parser.cc.jj 2025-01-07 13:13:31.061023273 +0100
+++ gcc/cp/parser.cc    2025-01-08 13:15:05.515288631 +0100
@@ -23107,15 +23107,11 @@ cp_parser_asm_string_expression (cp_pars
        matching_parens parens;
        parens.consume_open (parser);
        tree string = cp_parser_constant_expression (parser);
-      if (string != error_mark_node)
-       string = cxx_constant_value (string, tf_error);
-      cexpr_str cstr (string);
-      if (!cstr.type_check (tok->location))
-       return error_mark_node;
-      if (!cstr.extract (tok->location, string))
-       string = error_mark_node;
        parens.require_close (parser);
-      return string;
+      if (TREE_CODE (string) == STRING_CST)
+       string = build1_loc (tok->location, PAREN_EXPR, TREE_TYPE (string),
+                            string);
+      return finish_asm_string_expression (tok->location, string);
      }
    else if (!cp_parser_is_string_literal (tok))
      {
@@ -23396,7 +23392,7 @@ cp_parser_asm_definition (cp_parser* par
                                      inputs, clobbers, labels, inline_p,
                                      false);
          /* If the extended syntax was not used, mark the ASM_EXPR.  */
-         if (!extended_p)
+         if (!extended_p && asm_stmt != error_mark_node)
            {
              tree temp = asm_stmt;
              if (TREE_CODE (temp) == CLEANUP_POINT_EXPR)
@@ -30044,7 +30040,7 @@ cp_parser_yield_expression (cp_parser* p
  /* Parse an (optional) asm-specification.
asm-specification:
-     asm ( asm-string-expr )
+     asm ( string-literal )
If the asm-specification is present, returns a STRING_CST
     corresponding to the string-literal.  Otherwise, returns
@@ -30067,8 +30063,9 @@ cp_parser_asm_specification_opt (cp_pars
    parens.require_open (parser);
/* Look for the string-literal. */
-  tree asm_specification = cp_parser_asm_string_expression (parser);
-
+  tree asm_specification = cp_parser_string_literal (parser,
+                                                    /*translate=*/false,
+                                                    /*wide_ok=*/false);
    /* Look for the `)'.  */
    parens.require_close (parser);
--- gcc/cp/pt.cc.jj 2025-01-07 13:13:31.077023050 +0100
+++ gcc/cp/pt.cc        2025-01-08 12:21:18.154510158 +0100
@@ -19168,9 +19168,12 @@ tsubst_stmt (tree t, tree args, tsubst_f
                               outputs, inputs, clobbers, labels,
                               ASM_INLINE_P (t), false);
        tree asm_expr = tmp;
-       if (TREE_CODE (asm_expr) == CLEANUP_POINT_EXPR)
-         asm_expr = TREE_OPERAND (asm_expr, 0);
-       ASM_BASIC_P (asm_expr) = ASM_BASIC_P (t);
+       if (asm_expr != error_mark_node)
+         {
+           if (TREE_CODE (asm_expr) == CLEANUP_POINT_EXPR)
+             asm_expr = TREE_OPERAND (asm_expr, 0);
+           ASM_BASIC_P (asm_expr) = ASM_BASIC_P (t);
+         }
        }
        break;
--- gcc/testsuite/g++.dg/cpp1z/constexpr-asm-4.C.jj 2025-01-08 12:17:32.781667659 +0100
+++ gcc/testsuite/g++.dg/cpp1z/constexpr-asm-4.C        2025-01-08 
13:29:48.266922987 +0100
@@ -0,0 +1,83 @@
+// PR c++/118277
+// { dg-do compile { target c++14 } }
+// { dg-options "" }
+
+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; }
+};
+
+template <typename T>
+constexpr T
+gen (int n)
+{
+  switch (n)
+    {
+    case 0: return "foo %3,%2,%1,%0";
+    case 1: return "=r";
+    case 2: return "r";
+    case 3: return "memory";
+    case 4: return "cc";
+    case 5: return "goo %3,%2,%1,%0";
+    case 6: return "hoo %3,%2,%1,%0";
+    case 7: return "ioo";
+    case 8: return "joo";
+    case 9: return "koo";
+    default: return "";
+    }
+}
+
+int
+bar ()
+{
+  int a, b;
+  asm ((gen <string_view> (0))
+       : (gen <string_view> (1)) (a), (gen <string_view> (1)) (b)
+       : (gen <string_view> (2)) (1), (gen <string_view> (2)) (2)
+       : (gen <string_view> (3)), (gen <string_view> (4)));
+  asm ((gen <string_view> (7)));
+  return a + b;
+}
+
+template <typename T, typename U>
+U
+baz ()
+{
+  U a, b;
+  asm ((gen <T> (5))
+       : (gen <T> (1)) (a), (gen <T> (1)) (b)
+       : (gen <T> (2)) (U(1)), (gen <T> (2)) (U(2))
+       : (gen <T> (3)), (gen <T> (4)));
+  asm ((gen <string_view> (8)));
+  return a + b;
+}
+
+template <typename T, typename U>
+U
+qux ()
+{
+  U a, b;
+  asm ((gen <T> (6))
+       : (gen <T> (1)) (a), (gen <T> (1)) (b)
+       : (gen <T> (2)) (U(1)), (gen <T> (2)) (U(2))
+       : (gen <T> (3)), (gen <T> (4)));
+  asm ((gen <string_view> (9)));
+  return a + b;
+}
+
+int
+corge ()
+{
+  return qux <string_view, int> ();
+}
+
+/* { dg-final { scan-assembler "foo" } } */
+/* { dg-final { scan-assembler "hoo" } } */
+/* { dg-final { scan-assembler "ioo" } } */
+/* { dg-final { scan-assembler "koo" } } */
--- gcc/testsuite/g++.dg/cpp1z/constexpr-asm-5.C.jj     2025-01-08 
12:38:38.430935760 +0100
+++ gcc/testsuite/g++.dg/cpp1z/constexpr-asm-5.C        2025-01-08 
15:09:14.522912468 +0100
@@ -0,0 +1,367 @@
+// PR c++/118277
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+// Override any default-'-fno-exceptions':
+// { dg-additional-options -fexceptions }
+
+struct A {};
+struct B { int size; };
+struct C { constexpr int size () const { return 0; } };
+struct D { constexpr int size () const { return 0; } int data; };
+struct E { int size = 0;
+          constexpr const char *data () const { return ""; } };
+struct F { constexpr const char *size () const { return ""; }
+          constexpr const char *data () const { return ""; } };
+struct G { constexpr long size () const { return 0; }
+          constexpr float data () const { return 0.0f; } };
+struct H { short size () const { return 0; }
+          constexpr const char *data () const { return ""; } };
+struct I { constexpr signed char size () const { return 0; }
+          const char *data () const { return ""; } };
+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; };
+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 {}; } };
+#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 } }
+#endif
+constexpr const char a[] = { 't', 'e', 's', 't' };
+struct O { constexpr int size () const { return 4; }
+          constexpr const char *data () const { return a; } };
+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; };
+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; };
+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; };
+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"; } };
+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; }
+};
+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];
+};
+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 {}; } };
+#endif
+struct W { constexpr int size (int) const { return 4; }
+          constexpr const char *data () const { return "test"; } };
+struct X { constexpr int size () const { return 4; }
+          constexpr const char *data (int) const { return "test"; } };
+struct Y { constexpr int size () { return 4; }
+          constexpr const char *data (int) { return "test"; } };
+#if __cpp_concepts >= 201907L
+struct Z { constexpr int size (auto...) const { return 4; }
+          constexpr const char *data (auto...) const { return "test"; } };
+#endif
+
+void
+foo ()
+{
+  int v1, v2;
+  asm ("");
+  asm ((""));                        // { dg-error "constexpr string must be a 
string literal or object with 'size' and 'data' members" }
+                               // { dg-error "request for member 'size' in 
'\\\(\\\"\\\"\\\)', which is of non-class type 'const char \\\[1\\\]'" "" { target 
*-*-* } .-1 }
+  asm (("" + 0));            // { dg-error "constexpr string must be a string 
literal or object with 'size' and 'data' members" }
+                               // { dg-error "request for member 'size' in '\\\(const 
char\\\*\\\)\\\"\\\"', which is of non-class type 'const char\\\*'" "" { target 
*-*-* } .-1 }
+  asm ((0) ::);                        // { dg-error "constexpr string must be a 
string literal or object with 'size' and 'data' members" }
+                               // { dg-error "request for member 'size' in '0', which is of 
non-class type 'int'" "" { target *-*-* } .-1 }
+  asm ("" : (A {}) (v1));    // { dg-error "constexpr string must be a string 
literal or object with 'size' and 'data' members" }
+                               // { dg-error "'struct A' has no member named 'size'" 
"" { target *-*-* } .-1 }
+  asm ("" : : (B {}) (1));   // { dg-error "constexpr string must be a string 
literal or object with 'size' and 'data' members" }
+                               // { dg-error "'struct B' has no member named 'data'" 
"" { target *-*-* } .-1 }
+  asm ("" ::: (C {}));               // { dg-error "constexpr string must be a 
string literal or object with 'size' and 'data' members" }
+                               // { dg-error "'struct C' has no member named 'data'" 
"" { target *-*-* } .-1 }
+  asm ((D {}));                        // { dg-error "'D\\\(\\\).D::data' cannot be 
used as a function" }
+  asm ("" : (E {}) (v1));    // { dg-error "'E\\\{0\\\}.E::size' cannot be used as 
a function" }
+  __asm ("" :: (F {}) (1));  // { dg-error "constexpr string 'size\\\(\\\)' must be 
implicitly convertible to 'std::size_t'" }
+                               // { dg-error "could not convert 'F\\\(\\\).F::size\\\(\\\)' 
from 'const char\\\*' to '\[^']*'" "" { target *-*-* } .-1 }
+                               // { dg-error "conversion from 'const char\\\*' to '\[^']*' in 
a converted constant expression" "" { target *-*-* } .-2 }
+  asm ("" : : : (G {}));     // { dg-error "constexpr string 'data\\\(\\\)' must be 
implicitly convertible to 'const char\\\*'" }
+                               // { dg-error "could not convert 'G\\\(\\\).G::data\\\(\\\)' 
from 'float' to 'const char\\\*'" "" { target *-*-* } .-1 }
+  asm ("" : "=r" (v1), (H {}) (v2)); // { dg-error "call to non-'constexpr' 
function 'short int H::size\\\(\\\) const'" }
+                               // { dg-error "constexpr string 'size\\\(\\\)' must be a 
constant expression" "" { target *-*-* } .-1 }
+  asm ((I {}));                        // { dg-error "call to non-'constexpr' 
function 'const char\\\* I::data\\\(\\\) const'" }
+                               // { dg-error "constexpr string 'data\\\(\\\)' must be a core 
constant expression" "" { target *-*-* } .-1 }
+
+  asm ((J (0)));
+  asm ("" :: (J (1)) (1));   // { dg-error "constexpr string 'size\\\(\\\)' must be 
a constant expression" }
+  asm ((M {}));
+#if __cpp_constexpr_dynamic_alloc >= 201907L
+  asm ((N {}));                        // { dg-error "constexpr string 
'data\\\(\\\)\\\[0\\\]' must be a constant expression" "" { target c++20 } }
+#endif
+  asm ((O {}));
+  asm ((P (0)));
+  asm ((P (2)));
+  asm ((Q (0)));
+  asm ((Q (1)));
+  asm ((R (0)));
+  asm ((R (2)));
+  asm ((S {}));
+
+  asm ((string_view {}));
+  asm ((string_view ("test")));
+  asm ((string_view ("א")));
+  asm ((string_view (0, nullptr)));
+  asm ((string_view (4, "testwithextrachars")));
+  asm ((string_view (42, "test")));                          // { dg-error "array 
subscript value '41' is outside the bounds of array type 'const char \\\[5\\\]'" }
+                                                               // { dg-error "constexpr 
string 'data\\\(\\\)\\\[41\\\]' must be a constant expression" "" { target *-*-* } 
.-1 }
+
+  asm ((array<char, 2> { 'O', 'K' }));
+  asm ((array<wchar_t, 2> { L'O', L'K' }));                      // { dg-error 
"constexpr string 'data\\\(\\\)' must be implicitly convertible to 'const char\\\*'" }
+                                                               // { dg-error "could not convert 
'array<wchar_t, 2>{const wchar_t \\\[2\\\]{\[0-9]+, \[0-9]+}}.array<wchar_t, 2>::data\\\(\\\)' from 
'const wchar_t\\\*' to 'const char\\\*'" "" { target *-*-* } .-1 }
+  asm ((array<char, 4> { 't', 'e', 's', 't' }));
+  {
+    constexpr auto a = array<char, 4> { 't', 'e', 's', 't' };
+    asm ((a));
+  }
+
+#if __cplusplus >= 201402L
+  asm ((V {}));
+#endif
+  asm ((W {}));                                // { dg-error "no matching function 
for call to 'W::size\\\(\\\)'" }
+  asm ((X {}));                                // { dg-error "no matching function 
for call to 'X::data\\\(\\\)'" }
+  asm ((Y {}));                                // { dg-error "no matching function 
for call to 'Y::data\\\(\\\)'" }
+#if __cpp_concepts >= 201907L
+  asm ((Z {}) :::);
+#endif
+}
+
+template <typename TT>
+void
+bar ()
+{
+  int v1, v2;
+  asm ("");
+  asm ((""));                        // { dg-error "constexpr string must be a 
string literal or object with 'size' and 'data' members" }
+                               // { dg-error "request for member 'size' in 
'\\\(\\\"\\\"\\\)', which is of non-class type 'const char \\\[1\\\]'" "" { target 
*-*-* } .-1 }
+  asm (("" + 0));            // { dg-error "constexpr string must be a string 
literal or object with 'size' and 'data' members" }
+                               // { dg-error "request for member 'size' in '\\\(const 
char\\\*\\\)\\\"\\\"', which is of non-class type 'const char\\\*'" "" { target 
*-*-* } .-1 }
+  asm ((0) ::);                        // { dg-error "constexpr string must be a 
string literal or object with 'size' and 'data' members" }
+                               // { dg-error "request for member 'size' in '0', which is of 
non-class type 'int'" "" { target *-*-* } .-1 }
+  asm ("" : (A {}) (v1));    // { dg-error "constexpr string must be a string 
literal or object with 'size' and 'data' members" }
+                               // { dg-error "'struct A' has no member named 'size'" 
"" { target *-*-* } .-1 }
+  asm ("" : : (B {}) (1));   // { dg-error "constexpr string must be a string 
literal or object with 'size' and 'data' members" }
+                               // { dg-error "'struct B' has no member named 'data'" 
"" { target *-*-* } .-1 }
+  asm ("" ::: (C {}));               // { dg-error "constexpr string must be a 
string literal or object with 'size' and 'data' members" }
+                               // { dg-error "'struct C' has no member named 'data'" 
"" { target *-*-* } .-1 }
+  asm ((D {}));                        // { dg-error "'D\\\(\\\).D::data' cannot be 
used as a function" }
+  asm ("" : (E {}) (v1));    // { dg-error "'E\\\{0\\\}.E::size' cannot be used as 
a function" }
+  __asm ("" :: (F {}) (1));  // { dg-error "constexpr string 'size\\\(\\\)' must be 
implicitly convertible to 'std::size_t'" }
+                               // { dg-error "could not convert 'F\\\(\\\).F::size\\\(\\\)' 
from 'const char\\\*' to '\[^']*'" "" { target *-*-* } .-1 }
+                               // { dg-error "conversion from 'const char\\\*' to '\[^']*' in 
a converted constant expression" "" { target *-*-* } .-2 }
+  asm ("" : : : (G {}));     // { dg-error "constexpr string 'data\\\(\\\)' must be 
implicitly convertible to 'const char\\\*'" }
+                               // { dg-error "could not convert 'G\\\(\\\).G::data\\\(\\\)' 
from 'float' to 'const char\\\*'" "" { target *-*-* } .-1 }
+  asm ("" : "=r" (v1), (H {}) (v2)); // { dg-error "call to non-'constexpr' 
function 'short int H::size\\\(\\\) const'" }
+                               // { dg-error "constexpr string 'size\\\(\\\)' must be a 
constant expression" "" { target *-*-* } .-1 }
+  asm ((I {}));                        // { dg-error "call to non-'constexpr' 
function 'const char\\\* I::data\\\(\\\) const'" }
+                               // { dg-error "constexpr string 'data\\\(\\\)' must be a core 
constant expression" "" { target *-*-* } .-1 }
+
+  asm ((J (0)));
+  asm ("" :: (J (1)) (1));   // { dg-error "constexpr string 'size\\\(\\\)' must be 
a constant expression" }
+  asm ((M {}));
+#if __cpp_constexpr_dynamic_alloc >= 201907L
+  asm ((N {}));                        // { dg-error "constexpr string 
'data\\\(\\\)\\\[0\\\]' must be a constant expression" "" { target c++20 } }
+#endif
+  asm ((O {}));
+  asm ((P (0)));
+  asm ((P (2)));
+  asm ((Q (0)));
+  asm ((Q (1)));
+  asm ((R (0)));
+  asm ((R (2)));
+  asm ((S {}));
+
+  asm ((string_view {}));
+  asm ((string_view ("test")));
+  asm ((string_view ("א")));
+  asm ((string_view (0, nullptr)));
+  asm ((string_view (4, "testwithextrachars")));
+  asm ((string_view (42, "test")));                          // { dg-error "array 
subscript value '41' is outside the bounds of array type 'const char \\\[5\\\]'" }
+                                                               // { dg-error "constexpr 
string 'data\\\(\\\)\\\[41\\\]' must be a constant expression" "" { target *-*-* } 
.-1 }
+
+  asm ((array<char, 2> { 'O', 'K' }));
+  asm ((array<wchar_t, 2> { L'O', L'K' }));                      // { dg-error 
"constexpr string 'data\\\(\\\)' must be implicitly convertible to 'const char\\\*'" }
+                                                               // { dg-error "could not convert 
'array<wchar_t, 2>{const wchar_t \\\[2\\\]{\[0-9]+, \[0-9]+}}.array<wchar_t, 2>::data\\\(\\\)' from 
'const wchar_t\\\*' to 'const char\\\*'" "" { target *-*-* } .-1 }
+  asm ((array<char, 4> { 't', 'e', 's', 't' }));
+  {
+    constexpr auto a = array<char, 4> { 't', 'e', 's', 't' };
+    asm ((a));
+  }
+
+#if __cplusplus >= 201402L
+  asm ((V {}));
+#endif
+  asm ((W {}));                                // { dg-error "no matching function 
for call to 'W::size\\\(\\\)'" }
+  asm ((X {}));                                // { dg-error "no matching function 
for call to 'X::data\\\(\\\)'" }
+  asm ((Y {}));                                // { dg-error "no matching function 
for call to 'Y::data\\\(\\\)'" }
+#if __cpp_concepts >= 201907L
+  asm ((Z {}) :::);
+#endif
+}
+
+void
+baz ()
+{
+  bar<int> ();
+}
+
+namespace NN
+{
+  template <typename T>
+  struct A {
+    constexpr int size () const = delete;
+    constexpr const char *data () const { return "test"; } };
+#if __cpp_concepts >= 201907L
+  template <typename T>
+  struct B {
+    constexpr int size () const { return 4; }
+    constexpr const char *data () const requires false { return "test"; } };
+#endif
+  class C {
+    constexpr int size () const = delete;
+    constexpr const char *data () const { return "test"; } };
+#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"; } };
+#endif
+  struct E {
+    constexpr int size () const { return 4; }
+    constexpr const char *data () const { return "test"; } };
+  constexpr E operator ""_myd (const char *, size_t) { return E {}; }
+  constexpr E operator + (const char *, const E &) { return E {}; }
+  struct H {
+    static constexpr int size () { return 7; }
+    static constexpr const char *data () { return "message"; } };
+  struct I {
+    static constexpr int size () { return 0; }
+    static constexpr const char *data () { return nullptr; } };
+#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 } }
+#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"; }
+  };
+  struct L {
+    static constexpr int size () { return 4; }
+    static constexpr const char *data () { if consteval { return "test"; } 
else { throw 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"; }
+  };
+  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 
} }
+  };
+#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; };
+  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; };
+
+  void
+  bar ()
+  {
+    asm ((A<int> {}));           // { dg-error "use of deleted function 'constexpr int 
NN::A<T>::size\\\(\\\) const \\\[with T = int\\\]'" }
+#if __cpp_concepts >= 201907L
+    asm ((B<short> {})); // { dg-error "no matching function for call to 'NN::B<short 
int>::data\\\(\\\)'" "" { target c++20 } }
+#endif
+    asm ((C {}));              // { dg-error "use of deleted function 'constexpr 
int NN::C::size\\\(\\\) const'" }
+                               // { dg-error "'constexpr const char\\\* NN::C::data\\\(\\\) 
const' is private within this context" "" { target *-*-* } .-1 }
+#if __cplusplus >= 201402L
+    asm ((D {}));
+#endif
+    asm (("foo"_myd));
+    asm (("foo" + E {}));
+    asm ((H {}));
+    asm ((I {}));
+#if __cplusplus >= 201402L
+    asm ((J {}));              // { dg-error "constexpr string 'data\\\(\\\)' must be a core 
constant expression" "" { target c++14 } }
+#endif
+#if __cpp_if_consteval >= 202106L
+    asm ((K {}));
+    asm ((L {}));
+    asm ((M {}));              // { dg-error "constexpr string 'size\\\(\\\)' must be a 
constant expression" "" { target c++23 } }
+    asm ((N {}));              // { dg-error "constexpr string 'data\\\(\\\)\\\[0\\\]' must 
be a constant expression" "" { target c++23 } }
+#endif
+    asm ((Q {}));
+    asm ((R {}));
+  }
+
+  template <typename TT, typename UU, typename VV, typename WW>
+  void
+  baz ()
+  {
+    asm ((A<VV> {}));            // { dg-error "use of deleted function 'constexpr int 
NN::A<T>::size\\\(\\\) const \\\[with T = int\\\]'" }
+#if __cpp_concepts >= 201907L
+    asm ((B<WW> {}));            // { dg-error "no matching function for call to 'NN::B<short 
int>::data\\\(\\\)'" "" { target c++20 } }
+#endif
+    asm ((C {}));              // { dg-error "use of deleted function 'constexpr 
int NN::C::size\\\(\\\) const'" }
+                               // { dg-error "'constexpr const char\\\* NN::C::data\\\(\\\) 
const' is private within this context" "" { target *-*-* } .-1 }
+#if __cplusplus >= 201402L
+    asm ((D {}));
+#endif
+    asm (("foo"_myd));
+    asm (("foo" + E {}));
+    asm ((H {}));
+    asm ((I {}));
+#if __cplusplus >= 201402L
+    asm ((J {}));              // { dg-error "constexpr string 'data\\\(\\\)' must be a core 
constant expression" "" { target c++14 } }
+#endif
+#if __cpp_if_consteval >= 202106L
+    asm ((K {}));
+    asm ((L {}));
+    asm ((M {}));              // { dg-error "constexpr string 'size\\\(\\\)' must be a 
constant expression" "" { target c++23 } }
+    asm ((N {}));              // { dg-error "constexpr string 'data\\\(\\\)\\\[0\\\]' must 
be a constant expression" "" { target c++23 } }
+#endif
+    asm ((Q {}));
+    asm ((R {}));
+    asm ((TT {}));
+    asm ((UU {}));             // { dg-error "constexpr string must be a string 
literal or object with 'size' and 'data' members" }
+                               // { dg-error "request for member 'size' in '0', which is of 
non-class type 'long int'" "" { target *-*-* } .-1 }
+  }
+  void
+  qux ()
+  {
+    baz<E, long, int, short> ();
+  }
+}


        Jakub


Reply via email to