tree attrs = TYPE_ATTRIBUTES (reftype);
/* Copy type attributes from REF to DECL. Pass in REF if it's a DECL
- or a type but not if it's an expression. */
+ or a type but not if it's an expression. Set ATTR_FLAG_INTERNAL
+ since the attributes' arguments may be in their internal form. */
for (tree at = attrs; at; at = TREE_CHAIN (at))
- decl_attributes (node, at, flags, EXPR_P (ref) ? NULL_TREE : ref);
+ decl_attributes (node, at, flags | ATTR_FLAG_INTERNAL,
+ EXPR_P (ref) ? NULL_TREE : ref);
return NULL_TREE;
}
the attribute and its arguments into a string. */
static tree
-handle_access_attribute (tree node[3], tree name, tree args,
- int ARG_UNUSED (flags), bool *no_add_attrs)
+handle_access_attribute (tree node[3], tree name, tree args, int flags,
+ bool *no_add_attrs)
{
tree attrs = TYPE_ATTRIBUTES (*node);
tree type = *node;
/* Recursively call self to "replace" the documented/external
form of the attribute with the condensend internal form. */
- decl_attributes (node, axsat, flags);
+ decl_attributes (node, axsat, flags | ATTR_FLAG_INTERNAL);
return NULL_TREE;
}
- /* This is a recursive call to handle the condensed internal form
- of the attribute (see below). Since all validation has been
- done simply return here, accepting the attribute as is. */
- *no_add_attrs = false;
- return NULL_TREE;
+ if (flags & ATTR_FLAG_INTERNAL)
+ {
+ /* This is a recursive call to handle the condensed internal
+ form of the attribute (see below). Since all validation
+ has been done simply return here, accepting the attribute
+ as is. */
+ *no_add_attrs = false;
+ return NULL_TREE;
+ }
}
/* Set to true when the access mode has the form of a function call
access_mode = DECL_NAME (access_mode);
funcall = true;
}
+ else if (TREE_CODE (access_mode) != IDENTIFIER_NODE)
+ {
+ error ("attribute %qE mode %qE is not an identifier; expected one of "
+ "%qs, %qs, %qs, or %qs", name, access_mode,
+ "read_only", "read_write", "write_only", "none");
+ return NULL_TREE;
+ }
const char* const access_str = IDENTIFIER_POINTER (access_mode);
const char *ps = access_str;
/* Recursively call self to "replace" the documented/external form
of the attribute with the condensed internal form. */
- decl_attributes (node, new_attrs, flags);
+ decl_attributes (node, new_attrs, flags | ATTR_FLAG_INTERNAL);
return NULL_TREE;
}
--- /dev/null
+/* PR middle-end/97879 - ICE on invalid mode in attribute access
+ { dg-do compile }
+ { dg-options "-Wall" } */
+
+#define A(...) __attribute__ ((access (__VA_ARGS__)))
+
+A (" ", 1) void f1 (int *); // { dg-error "attribute 'access' mode '\" \"' is not an identifier; expected one of 'read_only', 'read_write', 'write_only', or 'none'" }
+ void f1 (int *);
+
+
+A ("none", 1) void f2 (char *); // { dg-error "not an identifier" }
+ void f2 (char *);
+
+A (1) void f3 (); // { dg-error "not an identifier" }
+
+A (1, 2) void f4 (); // { dg-error "not an identifier" }
+A (2., 3.) void f5 (); // { dg-error "not an identifier" }
+
+// Verify that copying a valid access attribute doesn't cause errors.
+A (read_only, 1, 2) void f6 (void*, int);
+__attribute__ ((copy (f6))) void f7 (void*, int);