On 11/22/24 4:31 AM, Jakub Jelinek wrote:
On Thu, Nov 21, 2024 at 11:57:13PM +0000, Joseph Myers wrote:
On Wed, 6 Nov 2024, Jakub Jelinek wrote:

+                 error_at (loc, "%<:%> constraint operand is not address "
+                                "of a function or non-automatic variable");

I think a testcase for this error is needed.

Here is an updated patch with the additional test coverage.

The C++ change is OK.

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

gcc/
        * genpreds.cc (mangle): Add ':' mangling.
        (add_constraint): Allow : constraint.
        * common.md (:): New define_constraint.
        * stmt.cc (parse_output_constraint): Diagnose "=:".
        (parse_input_constraint): Handle ":" and diagnose invalid
        uses.
        * doc/md.texi (Simple Constraints): Document ":" constraint.
gcc/c/
        * c-typeck.cc (build_asm_expr): Diagnose invalid ":" constraint
        uses.
gcc/cp/
        * semantics.cc (finish_asm_stmt): Diagnose invalid ":" constraint
        uses.
gcc/testsuite/
        * c-c++-common/toplevel-asm-4.c: New test.
        * c-c++-common/toplevel-asm-5.c: New test.

--- gcc/genpreds.cc.jj  2024-02-10 11:25:10.404468273 +0100
+++ gcc/genpreds.cc     2024-11-05 14:57:14.193060528 +0100
@@ -753,6 +753,7 @@ mangle (const char *name)
        case '_': obstack_grow (rtl_obstack, "__", 2); break;
        case '<':    obstack_grow (rtl_obstack, "_l", 2); break;
        case '>':    obstack_grow (rtl_obstack, "_g", 2); break;
+      case ':': obstack_grow (rtl_obstack, "_c", 2); break;
        default: obstack_1grow (rtl_obstack, *name); break;
        }
@@ -797,12 +798,13 @@ add_constraint (const char *name, const
    for (p = name; *p; p++)
      if (!ISALNUM (*p))
        {
-       if (*p == '<' || *p == '>' || *p == '_')
+       if (*p == '<' || *p == '>' || *p == '_' || *p == ':')
          need_mangled_name = true;
        else
          {
            error_at (loc, "constraint name '%s' must be composed of letters,"
-                     " digits, underscores, and angle brackets", name);
+                     " digits, underscores, colon and angle brackets",
+                     name);
            return;
          }
        }
--- gcc/common.md.jj    2024-01-03 11:51:24.519828508 +0100
+++ gcc/common.md       2024-11-05 14:51:29.098989927 +0100
@@ -100,6 +100,11 @@ (define_constraint "s"
         (match_test "!CONST_SCALAR_INT_P (op)")
         (match_test "!flag_pic || LEGITIMATE_PIC_OPERAND_P (op)")))
+(define_constraint ":"
+  "Defines a symbol."
+  (and (match_test "CONSTANT_P (op)")
+       (match_test "!CONST_SCALAR_INT_P (op)")))
+
  (define_constraint "n"
    "Matches a non-symbolic integer constant."
    (and (match_test "CONST_SCALAR_INT_P (op)")
--- gcc/stmt.cc.jj      2024-10-25 10:00:29.523767070 +0200
+++ gcc/stmt.cc 2024-11-05 18:31:11.518948252 +0100
@@ -278,6 +278,10 @@ parse_output_constraint (const char **co
          error ("matching constraint not valid in output operand");
          return false;
+ case ':':
+         error ("%<:%> constraint used for output operand");
+         return false;
+
        case '<':  case '>':
          /* ??? Before flow, auto inc/dec insns are not supposed to exist,
             excepting those that expand_call created.  So match memory
@@ -325,6 +329,7 @@ parse_input_constraint (const char **con
    size_t c_len = strlen (constraint);
    size_t j;
    bool saw_match = false;
+  bool at_checked = false;
/* Assume the constraint doesn't allow the use of either
       a register or memory.  */
@@ -362,6 +367,21 @@ parse_input_constraint (const char **con
        case 'N':  case 'O':  case 'P':  case ',':
        break;
+ case ':':
+       /* Verify that if : is used, it is just ":" or say ":,:" but not
+          mixed with other constraints or say ",:,," etc.  */
+       if (!at_checked)
+         {
+           for (size_t k = 0; k < c_len; ++k)
+             if (constraint[k] != ((k & 1) ? ',' : ':') || (c_len & 1) == 0)
+               {
+                 error ("%<:%> constraint mixed with other constraints");
+                 return false;
+               }
+           at_checked = true;
+         }
+       break;
+
        /* Whether or not a numeric constraint allows a register is
           decided by the matching constraint, and so there is no need
           to do anything special with them.  We must handle them in
--- gcc/doc/md.texi.jj  2024-10-16 14:41:45.553757783 +0200
+++ gcc/doc/md.texi     2024-11-05 18:46:30.795896301 +0100
@@ -1504,6 +1504,13 @@ as the predicate in the @code{match_oper
  the mode specified in the @code{match_operand} as the mode of the memory
  reference for which the address would be valid.
+@cindex @samp{:} in constraint
+@item @samp{:}
+This constraint, allowed only in input operands, says the inline @code{asm}
+pattern defines specific function or variable symbol.  The constraint
+shouldn't be mixed with other constraints on the same operand and
+the operand should be address of a function or non-automatic variable.
+
  @cindex other register constraints
  @cindex extensible constraints
  @item @var{other-letters}
--- gcc/c/c-typeck.cc.jj        2024-11-05 14:44:35.904892730 +0100
+++ gcc/c/c-typeck.cc   2024-11-05 18:25:34.837723892 +0100
@@ -12246,6 +12246,20 @@ build_asm_expr (location_t loc, tree str
              error_at (loc, "invalid constraint outside of a function");
              input = error_mark_node;
            }
+         if (constraint[0] == ':' && input != error_mark_node)
+           {
+             tree t = input;
+             STRIP_NOPS (t);
+             if (TREE_CODE (t) != ADDR_EXPR
+                 || !(TREE_CODE (TREE_OPERAND (t, 0)) == FUNCTION_DECL
+                      || (VAR_P (TREE_OPERAND (t, 0))
+                          && is_global_var (TREE_OPERAND (t, 0)))))
+               {
+                 error_at (loc, "%<:%> constraint operand is not address "
+                                "of a function or non-automatic variable");
+                 input = error_mark_node;
+               }
+           }
        }
        else
        input = error_mark_node;
--- gcc/cp/semantics.cc.jj      2024-11-05 14:44:35.911892630 +0100
+++ gcc/cp/semantics.cc 2024-11-05 18:27:05.162442682 +0100
@@ -2325,6 +2325,20 @@ finish_asm_stmt (location_t loc, int vol
                  error_at (loc, "invalid constraint outside of a function");
                  operand = error_mark_node;
                }
+             if (constraint[0] == ':' && operand != error_mark_node)
+               {
+                 tree t = operand;
+                 STRIP_NOPS (t);
+                 if (TREE_CODE (t) != ADDR_EXPR
+                     || !(TREE_CODE (TREE_OPERAND (t, 0)) == FUNCTION_DECL
+                          || (VAR_P (TREE_OPERAND (t, 0))
+                              && is_global_var (TREE_OPERAND (t, 0)))))
+                   {
+                     error_at (loc, "%<:%> constraint operand is not address "
+                               "of a function or non-automatic variable");
+                     operand = error_mark_node;
+                   }
+               }
            }
          else
            operand = error_mark_node;
--- gcc/testsuite/c-c++-common/toplevel-asm-4.c.jj      2024-11-05 
18:13:20.062136936 +0100
+++ gcc/testsuite/c-c++-common/toplevel-asm-4.c 2024-11-05 18:36:26.800476151 
+0100
@@ -0,0 +1,9 @@
+/* PR c/41045 */
+/* { dg-do compile } */
+/* { dg-options "-O0" } */
+/* { dg-additional-options "-fno-pie" { target pie } } */
+
+int v[42], w;
+void foo (void);
+
+asm ("# %c0: %c1:" :: ":" (foo), ":" (v), ":" (&w));
--- gcc/testsuite/c-c++-common/toplevel-asm-5.c.jj      2024-11-05 
18:14:44.449941185 +0100
+++ gcc/testsuite/c-c++-common/toplevel-asm-5.c 2024-11-22 10:28:42.873355264 
+0100
@@ -0,0 +1,28 @@
+/* PR c/41045 */
+/* { dg-do compile } */
+/* { dg-options "-O0" } */
+/* { dg-additional-options "-fno-pie" { target pie } } */
+
+extern int v[42];
+
+asm ("# %0" : "=:" (32));          /* { dg-error "lvalue required in 'asm' 
statement" } */
+                                       /* { dg-error "':' constraint used for output 
operand" "" { target *-*-* } .-1 } */
+asm ("# %0" : "=:" (v));           /* { dg-error "':' constraint used for output 
operand" } */
+asm ("# %0" : : "i:" (v));         /* { dg-error "':' constraint mixed with other 
constraints" } */
+asm ("# %0" : : ":i" (v));         /* { dg-error "':' constraint mixed with other 
constraints" } */
+asm ("# %0" : : ",:" (v));         /* { dg-error "':' constraint mixed with other 
constraints" } */
+asm ("# %0" : : ":,:" (v));
+asm ("# %0" : : ":," (v));         /* { dg-error "':' constraint mixed with other 
constraints" } */
+asm ("# %0" : : ":,,:" (v));               /* { dg-error "':' constraint mixed with 
other constraints" } */
+asm ("" : : ":" (0));                      /* { dg-error "constraint operand is not 
address of a function or non-automatic variable" } */
+
+void
+foo (int x)
+{
+  int y;
+  l:;
+  asm ("" : : ":" (&x));               /* { dg-error "constraint operand is not 
address of a function or non-automatic variable" } */
+  asm ("" : : ":" (&&l));          /* { dg-error "constraint operand is not address 
of a function or non-automatic variable" } */
+  asm ("" : : ":" (&y));               /* { dg-error "constraint operand is not 
address of a function or non-automatic variable" } */
+  asm ("" : : ":" (0));                    /* { dg-error "constraint operand is not 
address of a function or non-automatic variable" } */
+}


        Jakub


Reply via email to