https://gcc.gnu.org/g:38a13ea4117b96e467f78b3f86d737ecbe326935

commit r15-6760-g38a13ea4117b96e467f78b3f86d737ecbe326935
Author: Jakub Jelinek <ja...@redhat.com>
Date:   Fri Jan 10 10:32:36 2025 +0100

    c++: Fix up ICEs on constexpr inline asm strings in templates [PR118277]
    
    The following patch fixes ICEs when the new inline asm syntax
    to use C++26 static_assert-like constant expressions in place
    of string literals is used in templates.
    As finish_asm_stmt doesn't do any checking for
    processing_template_decl, this patch also just defers handling
    those strings in templates rather than say trying fold_non_dependent_expr
    and if the result is non-dependent and usable, try to extract.
    
    The patch also reverts changes to cp_parser_asm_specification_opt
    which allowed something like
    void foo () asm ((std::string_view ("bar")));
    but it would be really hard to support
    template <int N>
    void baz () asm ((std::string_view ("qux")));
    (especially with dependent constant expression).
    
    And the patch adds extensive test coverage for the various errors.
    
    2025-01-10  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.

Diff:
---
 gcc/cp/cp-tree.h                             |   1 +
 gcc/cp/parser.cc                             |  21 +-
 gcc/cp/pt.cc                                 |   9 +-
 gcc/cp/semantics.cc                          |  43 ++++
 gcc/testsuite/g++.dg/cpp1z/constexpr-asm-4.C |  83 ++++++
 gcc/testsuite/g++.dg/cpp1z/constexpr-asm-5.C | 367 +++++++++++++++++++++++++++
 6 files changed, 509 insertions(+), 15 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index c08494705e9f..b65a2677b4ec 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7947,6 +7947,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);
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index f548dc31c2b8..80bc2d8e9e1e 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -23107,15 +23107,11 @@ cp_parser_asm_string_expression (cp_parser *parser)
       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* parser)
                                      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* parser)
 /* 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_parser* parser)
   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);
 
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 19df9ccb6afd..67964d41ab8b 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -19168,9 +19168,12 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
                               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;
 
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 15840e10620c..2039f5266042 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -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 volatile_p, tree 
string,
 
       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);
 
diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-asm-4.C 
b/gcc/testsuite/g++.dg/cpp1z/constexpr-asm-4.C
new file mode 100644
index 000000000000..4beea612761c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-asm-4.C
@@ -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" } } */
diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-asm-5.C 
b/gcc/testsuite/g++.dg/cpp1z/constexpr-asm-5.C
new file mode 100644
index 000000000000..1c20b9dfec1e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-asm-5.C
@@ -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> ();
+  }
+}

Reply via email to