"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;
(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)")
"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;
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}
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;
}
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;
}
}
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
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. */
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
--- /dev/null
+/* 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));
--- /dev/null
+/* 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" } */
+}