public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/vendors/ARM/heads/morello)] c, cp: Switch to handling __capability as a keyword
@ 2022-11-14 13:24 Alex Coplan
  0 siblings, 0 replies; 2+ messages in thread
From: Alex Coplan @ 2022-11-14 13:24 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:3645660c38d7df6bf95b42e731da4010020de8bb

commit 3645660c38d7df6bf95b42e731da4010020de8bb
Author: Alex Coplan <alex.coplan@arm.com>
Date:   Tue Nov 1 10:57:39 2022 +0000

    c, cp: Switch to handling __capability as a keyword
    
    Prior to this patch, __capability was handled as a built-in macro which
    expanded to __attribute__((__cheri_capability__)). This is how Morello
    LLVM also used to handle this construct, but LLVM has since switched to
    treating __capability as a proper keyword instead. This patch makes the
    corresponding change for GCC.
    
    This change is important because keywords / type qualifiers are treated
    differently to GNU attributes in the C/C++ grammars, so some parses are
    different. E.g. we used to reject code like:
    
    struct {
      int x;
    } __capability *p;
    
    since, when treated as an attribute, __capability binds to the struct.
    However, when treated as a keyword, we effectively parse __capability as
    a type qualifier on the pointer type.
    
    The above case in particular is important as it occurs in the Morello
    Linux kernel.
    
    N.B. (like LLVM) we still use an attribute internally to represent
    __capability to avoid too much churn outside of the parser. Since we no
    longer want to accept the attribute from C/C++ code, though, we rename
    the attribute to "cheri capability" (with a space) like other internal
    GCC attributes.
    
    We then adjust the testsuite accordingly.
    
    While writing the patch for the C front end, it became apparent that we
    have some tests that rely on __capability being accepted from C++,
    despite us never really having added support for this. This happened to
    work before since __capability got expanded to a GNU attribute, but the
    C++ frontend was missing some diagnostics that we added for C, and
    naturally had similar shortcomings due to relying on parsing
    __capability as a GNU attribute.
    
    Hence, we also update the C++ front end to handle __capability properly
    as a cv-qualifier. For C++, we handle __capability in decl spec
    sequences (i.e. in the deprecated prefix position) by making it a
    first-class declaration specifier, and we handle the proper type
    qualifier variant internally by plumbing through the attribute as a
    C++11 standard attribute (which eventually gets applied in the
    cdk_pointer case of the main loop in grokdeclarator). This proved to be
    the least disruptive way of doing this.
    
    N.B. for now we only support __capability on pointers in C++, in
    particular we do not support the __capability keyword on reference
    types. These are rejected. Since we don't currently support hybrid C++,
    we have chosen to implement a minimal level of support such that
    pure-capability code depending on the __capability keyword (e.g.
    intrinsic wrappers and builtin tests) can be compiled. Adding support
    for __capability references would require a wider adaptation of the C++
    frontend code for hybrid CHERI.

Diff:
---
 gcc/attribs.c                                      |   6 +-
 gcc/c-family/c-attribs.c                           |  10 +-
 gcc/c-family/c-common.c                            |   3 +-
 gcc/c-family/c-common.h                            |   5 +-
 gcc/c-family/c-cppbuiltin.c                        |   6 --
 gcc/c/c-decl.c                                     |  11 +--
 gcc/c/c-parser.c                                   |  39 ++++----
 gcc/cp/cp-tree.h                                   |   1 +
 gcc/cp/decl.c                                      |  44 ++++++++-
 gcc/cp/parser.c                                    |  53 ++++++++---
 .../builtin_alignment_ret_types_hybrid-3.C         |  12 +--
 .../aarch64/morello/cap-keyword-helpers.h          |  14 +++
 .../aarch64/morello/capability-keyword-errors.C    |  18 ++++
 .../aarch64/morello/capability-keyword-valid.C     | 101 +++++++++++++++++++++
 .../aarch64/morello/capability-keyword-warn.C      |  44 +++++++++
 .../aarch64/capability-keyword-invalid.c           |   6 ++
 .../aarch64/capability_attribute_invalid.c         |   8 --
 .../aarch64/morello/capability-keyword-struct.c    |   4 +
 .../morello/capability_attribute_macro_check.c     |  12 ---
 ...bute_errors_1.c => capability_keyword_errors.c} |  45 +++++----
 ..._attribute_uses.c => capability_keyword_uses.c} |  11 ---
 ..._warnings_1.c => capability_keyword_warnings.c} |   2 +-
 22 files changed, 343 insertions(+), 112 deletions(-)

diff --git a/gcc/attribs.c b/gcc/attribs.c
index 5e8ec4b4326..5b9612d2343 100644
--- a/gcc/attribs.c
+++ b/gcc/attribs.c
@@ -1155,7 +1155,7 @@ build_type_attribute_qual_variant (tree otype, tree attribute, int quals)
 	  && !capability_type_p (ptr_type_node))
 	{
 	  bool old_cap = capability_type_p (ttype);
-	  bool new_cap = lookup_attribute ("cheri_capability", attribute);
+	  bool new_cap = lookup_attribute ("cheri capability", attribute);
 	  if (old_cap != new_cap)
 	    {
 	      auto as = TYPE_ADDR_SPACE (TREE_TYPE (ntype));
@@ -1366,8 +1366,8 @@ comp_type_attributes (const_tree type1, const_tree type2)
   if ((lookup_attribute ("nocf_check", TYPE_ATTRIBUTES (type1)) != NULL)
       ^ (lookup_attribute ("nocf_check", TYPE_ATTRIBUTES (type2)) != NULL))
     return 0;
-  if (bool (lookup_attribute ("cheri_capability", TYPE_ATTRIBUTES (type1)))
-      != bool (lookup_attribute ("cheri_capability", TYPE_ATTRIBUTES (type2))))
+  if (bool (lookup_attribute ("cheri capability", TYPE_ATTRIBUTES (type1)))
+      != bool (lookup_attribute ("cheri capability", TYPE_ATTRIBUTES (type2))))
     return 0;
   /* As some type combinations - like default calling-convention - might
      be compatible, we have to call the target hook to get the final result.  */
diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index a5996eaf0d2..0216592b1f2 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -261,7 +261,9 @@ const struct attribute_spec c_common_attribute_table[] =
   /* MORELLO TODO: The `affects_type_identity` has been set to true based on
      what is done in `attribs.c:comp_type_attributes`, but it is also used in
      the C++ frontend. Re-examine this when enabling C++.  */
-  { "cheri_capability",       0, 0, false, true, false, true,
+  /* For internal use only.  The name contains a space to prevent its
+     usage in source code.  */
+  { "cheri capability",       0, 0, false, true, false, true,
 			      handle_cheri_capability_attribute, NULL },
   { "cheri_no_provenance",    0, 0, false, true, false, false,
 			      handle_cheri_no_provenance_attribute, NULL },
@@ -804,8 +806,8 @@ handle_cheri_capability_attribute (tree *node, tree, tree, int,
   *no_add_attrs = true;
 
   if (!targetm.capability_mode ().exists ())
-    error_at (input_location, "%<__capability%> attribute is not supported for"
-			      "this architecture");
+    error_at (input_location, "%<__capability%> is not supported on"
+			      " this target");
   else if (TREE_CODE (*node) != POINTER_TYPE)
     error_at (input_location, "%<__capability%> only applies to pointers");
   else if (!capability_type_p (*node))
@@ -814,7 +816,7 @@ handle_cheri_capability_attribute (tree *node, tree, tree, int,
 	 includes REFERENCE_TYPE which would then need a call to
 	 `build_reference_type_for_mode`. I have not included this for now
 	 but it may be needed in the future for C++ frontend support.  */
-      tree attrs = tree_cons (get_identifier ("cheri_capability"),
+      tree attrs = tree_cons (get_identifier ("cheri capability"),
 				  NULL_TREE, TYPE_ATTRIBUTES (*node));
 
       /* Use build_type_attribute_qual_variant to reapply the
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 4f90f4ac1a4..f554598c9ac 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -388,6 +388,7 @@ const struct c_common_resword c_common_reswords[] =
   { "__builtin_offsetof", RID_OFFSETOF, 0 },
   { "__builtin_types_compatible_p", RID_TYPES_COMPATIBLE_P, D_CONLY },
   { "__builtin_va_arg",	RID_VA_ARG,	0 },
+  { "__capability",	RID_CAPABILITY,	0 },
   { "__complex",	RID_COMPLEX,	0 },
   { "__complex__",	RID_COMPLEX,	0 },
   { "__const",		RID_CONST,	0 },
@@ -462,7 +463,6 @@ const struct c_common_resword c_common_reswords[] =
   { "char8_t",		RID_CHAR8,	D_CXX_CHAR8_T_FLAGS | D_CXXWARN },
   { "char16_t",		RID_CHAR16,	D_CXXONLY | D_CXX11 | D_CXXWARN },
   { "char32_t",		RID_CHAR32,	D_CXXONLY | D_CXX11 | D_CXXWARN },
-  { "cheri_capability", RID_CHERI_CAPABILITY,	0 },
   { "class",		RID_CLASS,	D_CXX_OBJC | D_CXXWARN },
   { "const",		RID_CONST,	0 },
   { "consteval",	RID_CONSTEVAL,	D_CXXONLY | D_CXX20 | D_CXXWARN },
@@ -8655,6 +8655,7 @@ keyword_is_type_qualifier (enum rid keyword)
     case RID_VOLATILE:
     case RID_RESTRICT:
     case RID_ATOMIC:
+    case RID_CAPABILITY:
       return true;
     default:
       return false;
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 9382383fc46..11be2b1c81f 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -249,9 +249,8 @@ enum rid
   RID_FIRST_INT_N = RID_INT_N_0,
   RID_LAST_INT_N = RID_INT_N_3,
 
-  /* Reserved Identifier for the __capability or cheri_capability type
-     attribute.  */
-  RID_CHERI_CAPABILITY,
+  /* Reserved Identifier for the __capability keyword.  */
+  RID_CAPABILITY,
 
   RID_MAX,
 
diff --git a/gcc/c-family/c-cppbuiltin.c b/gcc/c-family/c-cppbuiltin.c
index 5a0bb473b43..1fa88d023a7 100644
--- a/gcc/c-family/c-cppbuiltin.c
+++ b/gcc/c-family/c-cppbuiltin.c
@@ -1490,12 +1490,6 @@ c_cpp_builtins (cpp_reader *pfile)
      format.  */
   if (ENABLE_DECIMAL_FLOAT && ENABLE_DECIMAL_BID_FORMAT)
     cpp_define (pfile, "__DECIMAL_BID_FORMAT__");
-
-  opt_scalar_addr_mode opt_cap_mode = targetm.capability_mode();
-  if (opt_cap_mode.exists())
-    {
-      cpp_define (pfile, "__capability=__attribute__((__cheri_capability__))");
-    }
 }
 
 /* Pass an object-like macro.  If it doesn't lie in the user's
diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index e9b05efcd99..bb503862786 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -6318,16 +6318,16 @@ grokdeclarator (const struct c_declarator *declarator,
 	}
     }
 
-  /* Check if the cheri_capability attribute is in decl_attrs. If it is, then
+  /* Check if the cheri capability attribute is in decl_attrs. If it is, then
      we have a deprecated use of the __capability type attribute before the
      `*` pointer indirection.  For now, this is still supported.  */
   bool deprecated_capability_attribute_use = false;
   int deprecated_capability_uses = 0;
-  if (lookup_attribute ("cheri_capability", *decl_attrs))
+  if (lookup_attribute ("cheri capability", *decl_attrs))
     {
       deprecated_capability_attribute_use = true;
       /* Remove the __capability attribute from the decl attributes.  */
-      (*decl_attrs) = remove_attribute ("cheri_capability",
+      (*decl_attrs) = remove_attribute ("cheri capability",
 					*decl_attrs);
     }
 
@@ -6364,7 +6364,7 @@ grokdeclarator (const struct c_declarator *declarator,
 		 `int __capability * __capability x;  */
 	      if (!capability_type_p (type))
 		{
-		  tree attr_name = get_identifier ("cheri_capability");
+		  tree attr_name = get_identifier ("cheri capability");
 		  tree new_attrs = tree_cons (attr_name, NULL_TREE,
 					  returned_attrs);
 		  returned_attrs = decl_attributes (&type, new_attrs, 0);
@@ -7029,8 +7029,7 @@ grokdeclarator (const struct c_declarator *declarator,
 	    declarator = declarator->declarator;
 	    if (test_fake_hybrid ())
 	      {
-		tree attr_name = get_identifier ("cheri_capability");
-		// tree attr_args = tree_cons (NULL_TREE, NULL_TREE, NULL_TREE);
+		tree attr_name = get_identifier ("cheri capability");
 		tree new_attrs = tree_cons (attr_name, NULL_TREE, returned_attrs);
 		returned_attrs = decl_attributes (&type, new_attrs, 0);
 	      }
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index dc8893d3f5c..db804ff7601 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -579,6 +579,7 @@ c_keyword_starts_typename (enum rid keyword)
     case RID_SAT:
     case RID_AUTO_TYPE:
     case RID_ALIGNAS:
+    case RID_CAPABILITY:
       return true;
     default:
       if (keyword >= RID_FIRST_INT_N
@@ -674,6 +675,7 @@ c_token_is_qualifier (c_token *token)
 	case RID_RESTRICT:
 	case RID_ATTRIBUTE:
 	case RID_ATOMIC:
+	case RID_CAPABILITY:
 	  return true;
 	default:
 	  return false;
@@ -757,6 +759,7 @@ c_token_starts_declspecs (c_token *token)
 	case RID_ALIGNAS:
 	case RID_ATOMIC:
 	case RID_AUTO_TYPE:
+	case RID_CAPABILITY:
 	  return true;
 	default:
 	  if (token->keyword >= RID_FIRST_INT_N
@@ -2198,15 +2201,6 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 		}
 	    }
 
-	  if (lookup_attribute ("cheri_capability", postfix_attrs))
-	    {
-	      error_at (here,
-			"%<__capability%> type specifier must"
-			" precede the declarator");
-	      c_parser_skip_to_end_of_block_or_statement (parser);
-	      return;
-	    }
-
 	  if (c_parser_next_token_is (parser, CPP_EQ))
 	    {
 	      tree d;
@@ -3072,6 +3066,20 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
 	  declspecs_add_qual (loc, specs, c_parser_peek_token (parser)->value);
 	  c_parser_consume_token (parser);
 	  break;
+	case RID_CAPABILITY:
+	  {
+	    if (targetm.capability_mode ().exists ())
+	      {
+		tree attrs = build_tree_list (get_identifier ("cheri capability"),
+					      NULL_TREE);
+		declspecs_add_attrs (loc, specs, attrs);
+	      }
+	    else
+	      error_at (loc, ("%<__capability%> is not supported on this "
+			      "target"));
+	    c_parser_consume_token (parser);
+	    break;
+	  }
 	case RID_ATTRIBUTE:
 	  if (!attrs_ok)
 	    goto out;
@@ -3656,10 +3664,6 @@ c_parser_struct_declaration (c_parser *parser)
 	  if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
 	    postfix_attrs = c_parser_gnu_attributes (parser);
 
-	  if (lookup_attribute ("cheri_capability", postfix_attrs))
-	    c_parser_error (parser, "%<__capability%> type specifier must"
-				    " precede the declarator");
-
 	  d = grokfield (c_parser_peek_token (parser)->location,
 			 declarator, specs, width, &all_prefix_attrs);
 	  decl_attributes (&d, chainon (postfix_attrs,
@@ -4431,14 +4435,6 @@ c_parser_parameter_declaration (c_parser *parser, tree attrs,
   if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
     postfix_attrs = c_parser_gnu_attributes (parser);
 
-  if (lookup_attribute ("cheri_capability", postfix_attrs))
-    {
-      error ("%<__capability%> type specifier must"
-	     " precede the declarator");
-      c_parser_skip_to_end_of_parameter (parser);
-      return NULL;
-    }
-
   /* Generate a location for the parameter, ranging from the start of the
      initial token to the end of the final token.
 
@@ -4541,7 +4537,6 @@ c_parser_gnu_attribute_any_word (c_parser *parser)
 	case RID_THREAD:
 	case RID_INT:
 	case RID_INTCAP:
-	case RID_CHERI_CAPABILITY:
 	case RID_CHAR:
 	case RID_FLOAT:
 	case RID_DOUBLE:
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index b9bbdd05a93..03ca0809077 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5945,6 +5945,7 @@ enum cp_decl_spec {
   ds_complex,
   ds_constinit,
   ds_consteval,
+  ds_capability,
   ds_thread,
   ds_type_spec,
   ds_redefined_builtin_type_spec,
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 2b742b0c6c0..cda5ef2a0a8 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -11039,10 +11039,14 @@ grokdeclarator (const cp_declarator *declarator,
   bool constexpr_p = decl_spec_seq_has_spec_p (declspecs, ds_constexpr);
   bool constinit_p = decl_spec_seq_has_spec_p (declspecs, ds_constinit);
   bool consteval_p = decl_spec_seq_has_spec_p (declspecs, ds_consteval);
+  bool decl_capability_p
+    = decl_spec_seq_has_spec_p (declspecs, ds_capability);
   bool late_return_type_p = false;
   bool array_parameter_p = false;
   tree reqs = NULL_TREE;
 
+  int deprecated_capability_uses = 0;
+
   signed_p = decl_spec_seq_has_spec_p (declspecs, ds_signed);
   unsigned_p = decl_spec_seq_has_spec_p (declspecs, ds_unsigned);
   short_p = decl_spec_seq_has_spec_p (declspecs, ds_short);
@@ -11998,8 +12002,36 @@ grokdeclarator (const cp_declarator *declarator,
 
   /* Determine the type of the entity declared by recurring on the
      declarator.  */
-  for (; declarator; declarator = declarator->declarator)
+  for (;; declarator = declarator->declarator)
     {
+      if (decl_capability_p
+	  && POINTER_TYPE_P (type)
+	  && deprecated_capability_uses++ == 0)
+	{
+	  /* For __capability in the deprecated prefix position, we can apply it
+	     at most once.  */
+	  if (!capability_type_p (type))
+	    {
+	      tree attr_name = get_identifier ("cheri capability");
+	      tree to_apply = tree_cons (attr_name, NULL_TREE,
+					 returned_attrs);
+	      returned_attrs = decl_attributes (&type, to_apply, 0);
+	    }
+
+	  /* Raise the deprecated declaration warning, but only if
+	     the base type wasn't already a typedef to a pointer type.  */
+	  if (!declspecs->type
+	      || TREE_CODE (declspecs->type) != TYPE_DECL
+	      || !POINTER_TYPE_P (TREE_TYPE (declspecs->type)))
+	    warning_at (declspecs->locations[ds_capability],
+			OPT_Wdeprecated_declarations,
+			"use of %<__capability%> before the pointer "
+			"type is deprecated");
+	}
+
+      if (!declarator)
+	break;
+
       const cp_declarator *inner_declarator;
       tree attrs;
 
@@ -12628,6 +12660,16 @@ grokdeclarator (const cp_declarator *declarator,
 	}
     }
 
+  if (decl_capability_p
+      && deprecated_capability_uses == 0)
+    error_at (declspecs->locations[ds_capability],
+	      "%<__capability%> only applies to pointers");
+
+  if (decl_capability_p
+      && deprecated_capability_uses > 1)
+    error_at (declspecs->locations[ds_capability],
+	      "use of %<__capability%> is ambiguous");
+
   id_loc = declarator ? declarator->id_loc : input_location;
 
   /* A `constexpr' specifier used in an object declaration declares
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 568f0809963..a3812e4849f 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -2259,7 +2259,7 @@ static cp_declarator *cp_parser_direct_declarator
 static enum tree_code cp_parser_ptr_operator
   (cp_parser *, tree *, cp_cv_quals *, tree *);
 static cp_cv_quals cp_parser_cv_qualifier_seq_opt
-  (cp_parser *);
+  (cp_parser *, tree *);
 static cp_virt_specifiers cp_parser_virt_specifier_seq_opt
   (cp_parser *);
 static cp_ref_qualifier cp_parser_ref_qualifier_opt
@@ -17863,6 +17863,12 @@ cp_parser_type_specifier (cp_parser* parser,
 	*is_cv_qualifier = true;
       break;
 
+    case RID_CAPABILITY:
+      ds = ds_capability;
+      if (is_cv_qualifier)
+	*is_cv_qualifier = true;
+      break;
+
     case RID_COMPLEX:
       /* The `__complex__' keyword is a GNU extension.  */
       ds = ds_complex;
@@ -21332,7 +21338,7 @@ cp_parser_direct_declarator (cp_parser* parser,
 		  first = false;
 
 		  /* Parse the cv-qualifier-seq.  */
-		  cv_quals = cp_parser_cv_qualifier_seq_opt (parser);
+		  cv_quals = cp_parser_cv_qualifier_seq_opt (parser, NULL);
 		  /* Parse the ref-qualifier. */
 		  ref_qual = cp_parser_ref_qualifier_opt (parser);
 		  /* Parse the tx-qualifier.  */
@@ -21842,6 +21848,7 @@ cp_parser_ptr_operator (cp_parser* parser,
   enum tree_code code = ERROR_MARK;
   cp_token *token;
   tree attrs = NULL_TREE;
+  tree qual_attrs = NULL_TREE;
 
   /* Assume that it's not a pointer-to-member.  */
   *type = NULL_TREE;
@@ -21871,9 +21878,10 @@ cp_parser_ptr_operator (cp_parser* parser,
 	 enforced during semantic analysis.  */
       if (code == INDIRECT_REF
 	  || cp_parser_allow_gnu_extensions_p (parser))
-	*cv_quals = cp_parser_cv_qualifier_seq_opt (parser);
+	*cv_quals = cp_parser_cv_qualifier_seq_opt (parser, &qual_attrs);
 
       attrs = cp_parser_std_attribute_spec_seq (parser);
+      attrs = chainon (attrs, qual_attrs);
       if (attributes != NULL)
 	*attributes = attrs;
     }
@@ -21915,10 +21923,12 @@ cp_parser_ptr_operator (cp_parser* parser,
 	      parser->object_scope = NULL_TREE;
 	      /* Look for optional c++11 attributes.  */
 	      attrs = cp_parser_std_attribute_spec_seq (parser);
+	      /* Look for the optional cv-qualifier-seq.  */
+	      *cv_quals = cp_parser_cv_qualifier_seq_opt (parser,
+							  &qual_attrs);
+	      attrs = chainon (attrs, qual_attrs);
 	      if (attributes != NULL)
 		*attributes = attrs;
-	      /* Look for the optional cv-qualifier-seq.  */
-	      *cv_quals = cp_parser_cv_qualifier_seq_opt (parser);
 	    }
 	}
       /* If that didn't work we don't have a ptr-operator.  */
@@ -21946,14 +21956,16 @@ cp_parser_ptr_operator (cp_parser* parser,
    Returns a bitmask representing the cv-qualifiers.  */
 
 static cp_cv_quals
-cp_parser_cv_qualifier_seq_opt (cp_parser* parser)
+cp_parser_cv_qualifier_seq_opt (cp_parser* parser, tree *attributes)
 {
   cp_cv_quals cv_quals = TYPE_UNQUALIFIED;
+  tree attr_list = NULL_TREE;
 
   while (true)
     {
       cp_token *token;
-      cp_cv_quals cv_qualifier;
+      cp_cv_quals cv_qualifier = TYPE_UNQUALIFIED;
+      tree attr = NULL_TREE;
 
       /* Peek at the next token.  */
       token = cp_lexer_peek_token (parser->lexer);
@@ -21972,12 +21984,18 @@ cp_parser_cv_qualifier_seq_opt (cp_parser* parser)
 	  cv_qualifier = TYPE_QUAL_RESTRICT;
 	  break;
 
+	case RID_CAPABILITY:
+	  if (attributes)
+	    attr = get_identifier ("cheri capability");
+	  else
+	    error_at (token->location, "unexpected %<__capability%>");
+	  break;
+
 	default:
-	  cv_qualifier = TYPE_UNQUALIFIED;
 	  break;
 	}
 
-      if (!cv_qualifier)
+      if (!cv_qualifier && !attr)
 	break;
 
       if (cv_quals & cv_qualifier)
@@ -21987,13 +22005,25 @@ cp_parser_cv_qualifier_seq_opt (cp_parser* parser)
 	  error_at (&richloc, "duplicate cv-qualifier");
 	  cp_lexer_purge_token (parser->lexer);
 	}
+      else if (attr && attr_list)
+	{
+	  gcc_rich_location richloc (token->location);
+	  richloc.add_fixit_remove ();
+	  error_at (&richloc, "duplicate %<__capability%>");
+	  cp_lexer_purge_token (parser->lexer);
+	}
       else
 	{
 	  cp_lexer_consume_token (parser->lexer);
-	  cv_quals |= cv_qualifier;
+	  if (attr)
+	    attr_list = build_tree_list (attr, NULL_TREE);
+	  else
+	    cv_quals |= cv_qualifier;
 	}
     }
 
+  if (attributes)
+    *attributes = attr_list;
   return cv_quals;
 }
 
@@ -30576,7 +30606,8 @@ set_and_check_decl_spec_loc (cp_decl_specifier_seq *decl_specs,
 	    "constexpr",
 	    "__complex",
 	    "constinit",
-	    "consteval"
+	    "consteval",
+	    "__capability",
 	  };
 	  gcc_rich_location richloc (location);
 	  richloc.add_fixit_remove ();
diff --git a/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_ret_types_hybrid-3.C b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_ret_types_hybrid-3.C
index 4571206f040..74046a00c4c 100644
--- a/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_ret_types_hybrid-3.C
+++ b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_ret_types_hybrid-3.C
@@ -9,16 +9,16 @@ void
 check_return_types_for_alignment_builtin_overloads_cap (size_t a,
         int * __capability i, char * __capability c,  void * __capability v)
 {
-  static_assert (__is_same (decltype (__builtin_align_down (i, a)), int __capability*), "");
-  static_assert (__is_same (decltype (__builtin_align_down (c, a)), char __capability*), "");
-  static_assert (__is_same (decltype (__builtin_align_down (v, a)), void __capability*), "");
+  static_assert (__is_same (decltype (__builtin_align_down (i, a)), int * __capability), "");
+  static_assert (__is_same (decltype (__builtin_align_down (c, a)), char * __capability), "");
+  static_assert (__is_same (decltype (__builtin_align_down (v, a)), void * __capability), "");
   static_assert (__is_same (decltype (__builtin_align_down (128, a)), int), "");
   static_assert (__is_same (decltype (__builtin_align_down ((intptr_t)128, a)), intptr_t), "");
   static_assert (__is_same (decltype (__builtin_align_down ((uintptr_t)128, a)), uintptr_t), "");
 
-  static_assert (__is_same (decltype (__builtin_align_up (i, a)), int __capability*), "");
-  static_assert (__is_same (decltype (__builtin_align_up (c, a)), char __capability*), "");
-  static_assert (__is_same (decltype (__builtin_align_up (v, a)), void __capability*), "");
+  static_assert (__is_same (decltype (__builtin_align_up (i, a)), int * __capability), "");
+  static_assert (__is_same (decltype (__builtin_align_up (c, a)), char * __capability), "");
+  static_assert (__is_same (decltype (__builtin_align_up (v, a)), void * __capability), "");
   static_assert (__is_same (decltype (__builtin_align_up (128, a)), int), "");
   static_assert (__is_same (decltype (__builtin_align_up ((intptr_t)128, a)), intptr_t), "");
   static_assert (__is_same (decltype (__builtin_align_up ((uintptr_t)128, a)), uintptr_t), "");
diff --git a/gcc/testsuite/g++.target/aarch64/morello/cap-keyword-helpers.h b/gcc/testsuite/g++.target/aarch64/morello/cap-keyword-helpers.h
new file mode 100644
index 00000000000..bb4a83f4c41
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/cap-keyword-helpers.h
@@ -0,0 +1,14 @@
+enum {
+  CAP_SIZE = sizeof (void * __capability),
+  PTR_SIZE = sizeof (void *),
+};
+#define CHECK_CAP(e) static_assert (sizeof (e) == CAP_SIZE)
+#define CHECK_PTR(e) static_assert (sizeof (e) == PTR_SIZE)
+
+#ifdef __CHERI__
+#ifdef __CHERI_PURE_CAPABILITY__
+static_assert (CAP_SIZE == PTR_SIZE);
+#else
+static_assert (CAP_SIZE > PTR_SIZE);
+#endif
+#endif
diff --git a/gcc/testsuite/g++.target/aarch64/morello/capability-keyword-errors.C b/gcc/testsuite/g++.target/aarch64/morello/capability-keyword-errors.C
new file mode 100644
index 00000000000..739f5a60af8
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/capability-keyword-errors.C
@@ -0,0 +1,18 @@
+// { dg-do compile }
+__capability int x1; // { dg-error "'__capability' only applies to pointers" }
+int __capability x2; // { dg-error "'__capability' only applies to pointers" }
+int x3 __capability; // { dg-error "expected initializer before '__capability'" }
+int * __capability __capability p1; // { dg-error "duplicate '__capability'" }
+__capability __capability int *p2; // { dg-error "duplicate '__capability'" }
+// { dg-warning "use of '__capability' before the pointer type" "" { target *-*-* } .-1 }
+__capability int **p3; // { dg-error "use of '__capability' is ambiguous" }
+// { dg-warning "use of '__capability' before the pointer type" "" { target *-*-* } .-1 }
+
+int f1() __capability; // { dg-error "unexpected '__capability'" }
+// { dg-error "expected initializer before '__capability'" "" { target *-*-* } .-1 }
+__capability int g1(); // { dg-error "'__capability' only applies to pointers" }
+int __capability g2(); // { dg-error "'__capability' only applies to pointers" }
+
+auto f2() {
+  return new int __capability; // { dg-error "'__capability' only applies to pointers" }
+}
diff --git a/gcc/testsuite/g++.target/aarch64/morello/capability-keyword-valid.C b/gcc/testsuite/g++.target/aarch64/morello/capability-keyword-valid.C
new file mode 100644
index 00000000000..cb156bfef84
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/capability-keyword-valid.C
@@ -0,0 +1,101 @@
+/* { dg-do compile } */
+
+#include "cap-keyword-helpers.h"
+
+int * __capability p1;
+CHECK_CAP (p1);
+
+int * __capability p2, * __capability p3;
+CHECK_CAP (p2);
+CHECK_CAP (p3);
+
+const int * __capability p4;
+CHECK_CAP (p4);
+
+int * const __capability p5 = 0;
+CHECK_CAP (p5);
+
+char *p6, * __capability p7;
+CHECK_PTR (p6);
+CHECK_CAP (p7);
+
+int * __capability * __capability p8;
+CHECK_CAP (p8);
+CHECK_CAP (*p8);
+
+int ** __capability p9;
+CHECK_CAP (p9);
+CHECK_PTR (*p9);
+
+char * __capability return_cap ();
+CHECK_CAP (return_cap ());
+
+void pass_cap (void * __capability arg)
+{
+  CHECK_CAP (arg);
+}
+
+// Check typedef cases.
+typedef int *int_star;
+int_star t1;
+CHECK_PTR (t1);
+
+__capability int_star t2;
+int_star __capability t3;
+CHECK_CAP (t2);
+CHECK_CAP (t3);
+
+int_star * __capability t4;
+CHECK_CAP (t4);
+CHECK_PTR (*t4);
+
+typedef int * __capability T;
+CHECK_CAP (T);
+
+__capability T t5;
+T __capability t6;
+T * __capability t7;
+T *t8;
+CHECK_CAP (t5);
+CHECK_CAP (t6);
+CHECK_CAP (t7);
+CHECK_CAP (*t7);
+CHECK_PTR (t8);
+CHECK_CAP (*t8);
+
+
+struct S1 {
+  int x;
+} * __capability ps;
+CHECK_CAP (ps);
+
+struct S2 {
+  float * __capability p;
+  char * __capability mem_fn ();
+};
+void foo(struct S2 *arg)
+{
+  CHECK_CAP (arg->p);
+  CHECK_CAP (arg->mem_fn ());
+}
+
+int * __capability *do_new()
+{
+  return new int * __capability;
+}
+CHECK_PTR (do_new ());
+CHECK_CAP (*do_new ());
+
+using U1 = int * __capability;
+CHECK_CAP (U1);
+
+template<typename Targ>
+void templ_fn()
+{
+  CHECK_CAP (Targ);
+}
+
+void call_templ_fn ()
+{
+  templ_fn<int * __capability>();
+}
diff --git a/gcc/testsuite/g++.target/aarch64/morello/capability-keyword-warn.C b/gcc/testsuite/g++.target/aarch64/morello/capability-keyword-warn.C
new file mode 100644
index 00000000000..6ddaf669de9
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/capability-keyword-warn.C
@@ -0,0 +1,44 @@
+// { dg-do compile }
+
+#include "cap-keyword-helpers.h"
+
+__capability char *p1; // { dg-warning "use of '__capability' before the pointer type" }
+char __capability *p2; // { dg-warning "use of '__capability' before the pointer type" }
+CHECK_CAP (p1);
+CHECK_CAP (p2);
+
+__capability short *f1(); // { dg-warning "use of '__capability' before the pointer type" }
+CHECK_CAP (f1 ());
+
+struct S1 {
+  __capability long *m1;  // { dg-warning "use of '__capability' before the pointer type" }
+  long __capability * m2; // { dg-warning "use of '__capability' before the pointer type" }
+  __capability double *f1(); // { dg-warning "use of '__capability' before the pointer type" }
+  double __capability *f2(); // { dg-warning "use of '__capability' before the pointer type" }
+};
+S1 s1;
+CHECK_CAP (s1.m1);
+CHECK_CAP (s1.m2);
+CHECK_CAP (s1.f1 ());
+CHECK_CAP (s1.f2 ());
+
+struct s {
+  int x;
+} __capability *ps; // { dg-warning "use of '__capability' before the pointer type is deprecated" }
+CHECK_CAP (ps);
+
+bool * __capability *do_new (int x)
+{
+  if (x)
+    return new __capability bool *; // { dg-warning "use of '__capability' before the pointer type is deprecated" }
+  else
+    return new bool __capability *; // { dg-warning "use of '__capability' before the pointer type is deprecated" }
+}
+CHECK_PTR (do_new (0));
+CHECK_CAP (*do_new (0));
+
+typedef __capability int *T1; // { dg-warning "use of '__capability' before the pointer type is deprecated" }
+CHECK_CAP (T1);
+
+typedef int __capability *T2; // { dg-warning "use of '__capability' before the pointer type is deprecated" }
+CHECK_CAP (T2);
diff --git a/gcc/testsuite/gcc.target/aarch64/capability-keyword-invalid.c b/gcc/testsuite/gcc.target/aarch64/capability-keyword-invalid.c
new file mode 100644
index 00000000000..77c6e8aa065
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/capability-keyword-invalid.c
@@ -0,0 +1,6 @@
+/* { dg-do compile { target { aarch64*-*-* && { ! { aarch64_capability_any } } } } } */
+
+/* Check that we error on non-capability targets.  */
+int * __capability var1; /* { dg-error "'__capability' is not supported on this target" } */
+__capability int * var2; /* { dg-error "'__capability' is not supported on this target" } */
+int __capability * var3; /* { dg-error "'__capability' is not supported on this target" } */
diff --git a/gcc/testsuite/gcc.target/aarch64/capability_attribute_invalid.c b/gcc/testsuite/gcc.target/aarch64/capability_attribute_invalid.c
deleted file mode 100644
index f679c7cb1f2..00000000000
--- a/gcc/testsuite/gcc.target/aarch64/capability_attribute_invalid.c
+++ /dev/null
@@ -1,8 +0,0 @@
-/* { dg-do compile { target { aarch64*-*-* && { ! { aarch64_capability_any } } } } } */
-
-/* Error if Morello not enabled. Currently the macro mapping __capability to __attribute__((__cheri_capability__))
-   is conditionally enabled on having a capability type enabled: targetm.capability_mode (), so in the first case
-   we do ugly-error instead of gracefully-error.  */
-int * __capability var1; /* { dg-error "" } */
-int * __attribute__((__cheri_capability__)) var2; /* { dg-error "'__capability' attribute is not supported for this architecture" } */
-int * __attribute__((cheri_capability)) var3; /* { dg-error "'__capability' attribute is not supported for this architecture" } */
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/capability-keyword-struct.c b/gcc/testsuite/gcc.target/aarch64/morello/capability-keyword-struct.c
new file mode 100644
index 00000000000..0c2454b792e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/morello/capability-keyword-struct.c
@@ -0,0 +1,4 @@
+/* { dg-do compile } */
+struct s {
+  int x;
+} __capability *p; /* { dg-warning "use of '__capability' before the pointer type is deprecated" } */
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/capability_attribute_macro_check.c b/gcc/testsuite/gcc.target/aarch64/morello/capability_attribute_macro_check.c
deleted file mode 100644
index f6913571361..00000000000
--- a/gcc/testsuite/gcc.target/aarch64/morello/capability_attribute_macro_check.c
+++ /dev/null
@@ -1,12 +0,0 @@
-/* { dg-do preprocess { target aarch64*-*-* } } */
-
-/* Test that the __capability macro and __attribute__((__cheri_capability__))
-   produce exactly the same result.  */
-
-int *__capability macrotestvar1;
-int *__attribute__((__cheri_capability__)) macrotestvar2;
-int *__attribute__((cheri_capability)) macrotestvar3;
-
-/* Sadly there's no such thing as a scan-file-times to use here,
-   so just do !__capability instead.  */
-/* { dg-final { scan-file-not capability_attribute_macro_check.i "__capability" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/capability_attribute_errors_1.c b/gcc/testsuite/gcc.target/aarch64/morello/capability_keyword_errors.c
similarity index 63%
rename from gcc/testsuite/gcc.target/aarch64/morello/capability_attribute_errors_1.c
rename to gcc/testsuite/gcc.target/aarch64/morello/capability_keyword_errors.c
index 77f19f7b021..b9f0190a887 100644
--- a/gcc/testsuite/gcc.target/aarch64/morello/capability_attribute_errors_1.c
+++ b/gcc/testsuite/gcc.target/aarch64/morello/capability_keyword_errors.c
@@ -4,7 +4,8 @@
 /* Error on non-pointers.  */
 int __capability var1;  /* { dg-error "'__capability' only applies to pointers" } */
 __capability int var2;  /* { dg-error "'__capability' only applies to pointers" } */
-int var3 __capability;  /* { dg-error "'__capability' type specifier must precede the declarator" } */
+int var3 __capability;  /* { dg-error "expected ';' before '__capability'" } */
+/* { dg-warning "empty declaration" "" { target *-*-* } .-1 } */
 char __capability string1[]  = "abcdef" ;  /* { dg-error "'__capability' only applies to pointers" } */
 void f1 (int __capability x); /* { dg-error "'__capability' only applies to pointers" } */
 void __capability f2 (); /* { dg-error "'__capability' only applies to pointers" } */
@@ -13,9 +14,12 @@ int __capability f3 (); /* { dg-error "'__capability' only applies to pointers"
 typedef int __capability noncapptr; /* { dg-error "'__capability' only applies to pointers" } */
 
 /* Improper ordering: Error cases.  */
-int * var4 __capability ; /* { dg-error "'__capability' type specifier must precede the declarator" } */
-int *var5 __capability; /* { dg-error "'__capability' type specifier must precede the declarator" } */
-int* var6 __capability; /* { dg-error "'__capability' type specifier must precede the declarator" } */
+int * var4 __capability ; /* { dg-error "expected ';' before '__capability'" } */
+/* { dg-warning "empty declaration" "" { target *-*-* } .-1 } */
+int *var5 __capability; /* { dg-error "expected ';' before '__capability'" } */
+/* { dg-warning "empty declaration" "" { target *-*-* } .-1 } */
+int* var6 __capability; /* { dg-error "expected ';' before '__capability'" } */
+/* { dg-warning "empty declaration" "" { target *-*-* } .-1 } */
 int __capability **var7; /* { dg-error "use of '__capability' is ambiguous" } */
 /* { dg-warning "use of '__capability' before the pointer type is deprecated" "" { target *-*-* } .-1 } */
 __capability int ** var8; /* { dg-error "use of '__capability' is ambiguous" } */
@@ -39,16 +43,20 @@ int __capability * __capability * var11; /* { dg-error "use of '__capability' is
 /* { dg-warning "use of '__capability' before the pointer type is deprecated" "" { target *-*-* } .-1 } */
 
 /* Adding attribute to a function. Improper ordering: Error cases. */
-void *f4 __capability (void);   /* { dg-error "'__capability' type specifier must precede the declarator" } */
-void (*f5) __capability (void); /* { dg-error "'__capability' type specifier must precede the declarator" } */
-void* f6 __capability (void);  /* { dg-error "'__capability' type specifier must precede the declarator" } */
-int *f7 __capability (void);   /* { dg-error "'__capability' type specifier must precede the declarator" } */
-int* f8 __capability (void);   /* { dg-error "'__capability' type specifier must precede the declarator" } */
-int* f9 (void) __capability;   /* { dg-error "'__capability' type specifier must precede the declarator" } */
+void *f4 __capability (void);   /* { dg-error "expected ';' before '__capability'" } */
+/* { dg-error "expected identifier or '\\(' before 'void'" "" { target *-*-* } .-1 } */
+void (*f5) __capability (void); /* { dg-error "expected ';' before '__capability'" } */
+/* { dg-error "expected identifier or '\\(' before 'void'" "" { target *-*-* } .-1 } */
+void* f6 __capability (void);  /* { dg-error "expected ';' before '__capability'" } */
+/* { dg-error "expected identifier or '\\(' before 'void'" "" { target *-*-* } .-1 } */
+int *f7 __capability (void);   /* { dg-error "expected ';' before '__capability'" } */
+/* { dg-error "expected identifier or '\\(' before 'void'" "" { target *-*-* } .-1 } */
+int* f8 __capability (void);   /* { dg-error "expected ';' before '__capability'" } */
+/* { dg-error "expected identifier or '\\(' before 'void'" "" { target *-*-* } .-1 } */
 
 /* Adding attribute to a function parameter. Improper ordering: Error cases. */
-void f10 (int* var12 __capability);/* { dg-error "'__capability' type specifier must precede the declarator" } */
-void f11 (int *var13 __capability);/* { dg-error "'__capability' type specifier must precede the declarator" } */
+void f10 (int* var12 __capability);/* { dg-error "expected ';', ',' or '\\)' before '__capability'" } */
+void f11 (int *var13 __capability);/* { dg-error "expected ';', ',' or '\\)' before '__capability'" } */
 void f12 (int __capability ** var14); /* { dg-error "use of '__capability' is ambiguous" } */
 /* { dg-warning "use of '__capability' before the pointer type is deprecated" "" { target *-*-* } .-1 } */
 void f13 (__capability int ** var15);  /* { dg-error "use of '__capability' is ambiguous" } */
@@ -56,21 +64,24 @@ void f13 (__capability int ** var15);  /* { dg-error "use of '__capability' is a
 
 /* Putting int* in a typedef...  */
 typedef int* intptr;
-intptr var16 __capability;  /* { dg-error "'__capability' type specifier must precede the declarator" } */
-intptr* var17 __capability; /* { dg-error "'__capability' type specifier must precede the declarator" } */
+intptr var16 __capability;  /* { dg-error "expected ';' before '__capability'" } */
+/* { dg-warning "empty declaration" "" { target *-*-* } .-1 } */
+intptr* var17 __capability; /* { dg-error "expected ';' before '__capability'" } */
+/* { dg-warning "empty declaration" "" { target *-*-* } .-1 } */
 
 /* Putting int*__capability in a typedef...  */
 typedef int * __capability intptr2;
-intptr2* var18 __capability;   /* { dg-error "'__capability' type specifier must precede the declarator" } */
+intptr2* var18 __capability;   /* { dg-error "expected ';' before '__capability'" } */
+/* { dg-warning "empty declaration" "" { target *-*-* } .-1 } */
 
 /* Try putting pointers in a struct.  */
 struct cheri_object1
 {
-   void *var19 __capability, *var20; /* { dg-error "'__capability' type specifier must precede the declarator" } */
+   void *var19 __capability, *var20; /* { dg-error "expected ':', ',', ';', '\}' or '__attribute__' before '__capability'" } */
 };
 struct cheri_object2
 {
-  void * var19, *var20 __capability; /* { dg-error "'__capability' type specifier must precede the declarator" } */
+  void * var19, *var20 __capability; /* { dg-error "expected ':', ',', ';', '\}' or '__attribute__' before '__capability'" } */
 };
 struct cheri_object3
 {
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/capability_attribute_uses.c b/gcc/testsuite/gcc.target/aarch64/morello/capability_keyword_uses.c
similarity index 86%
rename from gcc/testsuite/gcc.target/aarch64/morello/capability_attribute_uses.c
rename to gcc/testsuite/gcc.target/aarch64/morello/capability_keyword_uses.c
index ee20cf34412..3f80b7602d9 100644
--- a/gcc/testsuite/gcc.target/aarch64/morello/capability_attribute_uses.c
+++ b/gcc/testsuite/gcc.target/aarch64/morello/capability_keyword_uses.c
@@ -81,13 +81,6 @@ struct cheri_object6
   void ** __capability var32;
 };
 
-/* Simple uses of defining the attribute as __attribute__, also with multiple
-   attribute definitions.  */
-char *__attribute__((__cheri_capability__)) attrtestvar1;
-char *__attribute__((cheri_capability)) attrtestvar2;
-char *__attribute__((cheri_capability, used)) attrtestvar3;
-char *__attribute__((__cheri_capability__, __used__)) attrtestvar4;
-
 /* And a quick runtime test.  */
 int main()
 {
@@ -110,10 +103,6 @@ int main()
   printf("%c\n", *test);
   printf("%c\n", *test2);
 
-  /* Simple test of assignments on the __attribute__-defined pointers.  */
-  attrtestvar1 = stringpointer;
-  attrtestvar3 = attrtestvar1;
-
   /* Simple test zero-assignment.  */
   test3 = 0;
 
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/capability_attribute_warnings_1.c b/gcc/testsuite/gcc.target/aarch64/morello/capability_keyword_warnings.c
similarity index 96%
rename from gcc/testsuite/gcc.target/aarch64/morello/capability_attribute_warnings_1.c
rename to gcc/testsuite/gcc.target/aarch64/morello/capability_keyword_warnings.c
index 7acc9b8c7f8..967b8c8fe0c 100644
--- a/gcc/testsuite/gcc.target/aarch64/morello/capability_attribute_warnings_1.c
+++ b/gcc/testsuite/gcc.target/aarch64/morello/capability_keyword_warnings.c
@@ -7,9 +7,9 @@ __capability int *var2; /* { dg-warning "use of '__capability' before the pointe
 __capability int ** __capability var3; /* { dg-warning "use of '__capability' before the pointer type is deprecated" } */
 __capability void *var4, *var5; /* { dg-warning "use of '__capability' before the pointer type is deprecated" } */
 void __capability *var6, *var7; /* { dg-warning "use of '__capability' before the pointer type is deprecated" } */
-void *var8, __capability *var9;   /* { dg-warning "use of '__capability' before the pointer type is deprecated" } */
 __capability int **__capability z2;/* { dg-warning "use of '__capability' before the pointer type is deprecated" } */
 __capability int *__capability z3; /* { dg-warning "use of '__capability' before the pointer type is deprecated" } */
+typeof (__capability int *) x; /* { dg-warning "use of '__capability' before the pointer type is deprecated" } */
 
 /* Adding attribute to a function. Improper ordering: Warning cases. */
 __capability void *f1 (void);/* { dg-warning "use of '__capability' before the pointer type is deprecated" } */

^ permalink raw reply	[flat|nested] 2+ messages in thread

* [gcc(refs/vendors/ARM/heads/morello)] c, cp: Switch to handling __capability as a keyword
@ 2022-11-22 12:42 Stam Markianos-Wright
  0 siblings, 0 replies; 2+ messages in thread
From: Stam Markianos-Wright @ 2022-11-22 12:42 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:3645660c38d7df6bf95b42e731da4010020de8bb

commit 3645660c38d7df6bf95b42e731da4010020de8bb
Author: Alex Coplan <alex.coplan@arm.com>
Date:   Tue Nov 1 10:57:39 2022 +0000

    c, cp: Switch to handling __capability as a keyword
    
    Prior to this patch, __capability was handled as a built-in macro which
    expanded to __attribute__((__cheri_capability__)). This is how Morello
    LLVM also used to handle this construct, but LLVM has since switched to
    treating __capability as a proper keyword instead. This patch makes the
    corresponding change for GCC.
    
    This change is important because keywords / type qualifiers are treated
    differently to GNU attributes in the C/C++ grammars, so some parses are
    different. E.g. we used to reject code like:
    
    struct {
      int x;
    } __capability *p;
    
    since, when treated as an attribute, __capability binds to the struct.
    However, when treated as a keyword, we effectively parse __capability as
    a type qualifier on the pointer type.
    
    The above case in particular is important as it occurs in the Morello
    Linux kernel.
    
    N.B. (like LLVM) we still use an attribute internally to represent
    __capability to avoid too much churn outside of the parser. Since we no
    longer want to accept the attribute from C/C++ code, though, we rename
    the attribute to "cheri capability" (with a space) like other internal
    GCC attributes.
    
    We then adjust the testsuite accordingly.
    
    While writing the patch for the C front end, it became apparent that we
    have some tests that rely on __capability being accepted from C++,
    despite us never really having added support for this. This happened to
    work before since __capability got expanded to a GNU attribute, but the
    C++ frontend was missing some diagnostics that we added for C, and
    naturally had similar shortcomings due to relying on parsing
    __capability as a GNU attribute.
    
    Hence, we also update the C++ front end to handle __capability properly
    as a cv-qualifier. For C++, we handle __capability in decl spec
    sequences (i.e. in the deprecated prefix position) by making it a
    first-class declaration specifier, and we handle the proper type
    qualifier variant internally by plumbing through the attribute as a
    C++11 standard attribute (which eventually gets applied in the
    cdk_pointer case of the main loop in grokdeclarator). This proved to be
    the least disruptive way of doing this.
    
    N.B. for now we only support __capability on pointers in C++, in
    particular we do not support the __capability keyword on reference
    types. These are rejected. Since we don't currently support hybrid C++,
    we have chosen to implement a minimal level of support such that
    pure-capability code depending on the __capability keyword (e.g.
    intrinsic wrappers and builtin tests) can be compiled. Adding support
    for __capability references would require a wider adaptation of the C++
    frontend code for hybrid CHERI.

Diff:
---
 gcc/attribs.c                                      |   6 +-
 gcc/c-family/c-attribs.c                           |  10 +-
 gcc/c-family/c-common.c                            |   3 +-
 gcc/c-family/c-common.h                            |   5 +-
 gcc/c-family/c-cppbuiltin.c                        |   6 --
 gcc/c/c-decl.c                                     |  11 +--
 gcc/c/c-parser.c                                   |  39 ++++----
 gcc/cp/cp-tree.h                                   |   1 +
 gcc/cp/decl.c                                      |  44 ++++++++-
 gcc/cp/parser.c                                    |  53 ++++++++---
 .../builtin_alignment_ret_types_hybrid-3.C         |  12 +--
 .../aarch64/morello/cap-keyword-helpers.h          |  14 +++
 .../aarch64/morello/capability-keyword-errors.C    |  18 ++++
 .../aarch64/morello/capability-keyword-valid.C     | 101 +++++++++++++++++++++
 .../aarch64/morello/capability-keyword-warn.C      |  44 +++++++++
 .../aarch64/capability-keyword-invalid.c           |   6 ++
 .../aarch64/capability_attribute_invalid.c         |   8 --
 .../aarch64/morello/capability-keyword-struct.c    |   4 +
 .../morello/capability_attribute_macro_check.c     |  12 ---
 ...bute_errors_1.c => capability_keyword_errors.c} |  45 +++++----
 ..._attribute_uses.c => capability_keyword_uses.c} |  11 ---
 ..._warnings_1.c => capability_keyword_warnings.c} |   2 +-
 22 files changed, 343 insertions(+), 112 deletions(-)

diff --git a/gcc/attribs.c b/gcc/attribs.c
index 5e8ec4b4326..5b9612d2343 100644
--- a/gcc/attribs.c
+++ b/gcc/attribs.c
@@ -1155,7 +1155,7 @@ build_type_attribute_qual_variant (tree otype, tree attribute, int quals)
 	  && !capability_type_p (ptr_type_node))
 	{
 	  bool old_cap = capability_type_p (ttype);
-	  bool new_cap = lookup_attribute ("cheri_capability", attribute);
+	  bool new_cap = lookup_attribute ("cheri capability", attribute);
 	  if (old_cap != new_cap)
 	    {
 	      auto as = TYPE_ADDR_SPACE (TREE_TYPE (ntype));
@@ -1366,8 +1366,8 @@ comp_type_attributes (const_tree type1, const_tree type2)
   if ((lookup_attribute ("nocf_check", TYPE_ATTRIBUTES (type1)) != NULL)
       ^ (lookup_attribute ("nocf_check", TYPE_ATTRIBUTES (type2)) != NULL))
     return 0;
-  if (bool (lookup_attribute ("cheri_capability", TYPE_ATTRIBUTES (type1)))
-      != bool (lookup_attribute ("cheri_capability", TYPE_ATTRIBUTES (type2))))
+  if (bool (lookup_attribute ("cheri capability", TYPE_ATTRIBUTES (type1)))
+      != bool (lookup_attribute ("cheri capability", TYPE_ATTRIBUTES (type2))))
     return 0;
   /* As some type combinations - like default calling-convention - might
      be compatible, we have to call the target hook to get the final result.  */
diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index a5996eaf0d2..0216592b1f2 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -261,7 +261,9 @@ const struct attribute_spec c_common_attribute_table[] =
   /* MORELLO TODO: The `affects_type_identity` has been set to true based on
      what is done in `attribs.c:comp_type_attributes`, but it is also used in
      the C++ frontend. Re-examine this when enabling C++.  */
-  { "cheri_capability",       0, 0, false, true, false, true,
+  /* For internal use only.  The name contains a space to prevent its
+     usage in source code.  */
+  { "cheri capability",       0, 0, false, true, false, true,
 			      handle_cheri_capability_attribute, NULL },
   { "cheri_no_provenance",    0, 0, false, true, false, false,
 			      handle_cheri_no_provenance_attribute, NULL },
@@ -804,8 +806,8 @@ handle_cheri_capability_attribute (tree *node, tree, tree, int,
   *no_add_attrs = true;
 
   if (!targetm.capability_mode ().exists ())
-    error_at (input_location, "%<__capability%> attribute is not supported for"
-			      "this architecture");
+    error_at (input_location, "%<__capability%> is not supported on"
+			      " this target");
   else if (TREE_CODE (*node) != POINTER_TYPE)
     error_at (input_location, "%<__capability%> only applies to pointers");
   else if (!capability_type_p (*node))
@@ -814,7 +816,7 @@ handle_cheri_capability_attribute (tree *node, tree, tree, int,
 	 includes REFERENCE_TYPE which would then need a call to
 	 `build_reference_type_for_mode`. I have not included this for now
 	 but it may be needed in the future for C++ frontend support.  */
-      tree attrs = tree_cons (get_identifier ("cheri_capability"),
+      tree attrs = tree_cons (get_identifier ("cheri capability"),
 				  NULL_TREE, TYPE_ATTRIBUTES (*node));
 
       /* Use build_type_attribute_qual_variant to reapply the
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 4f90f4ac1a4..f554598c9ac 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -388,6 +388,7 @@ const struct c_common_resword c_common_reswords[] =
   { "__builtin_offsetof", RID_OFFSETOF, 0 },
   { "__builtin_types_compatible_p", RID_TYPES_COMPATIBLE_P, D_CONLY },
   { "__builtin_va_arg",	RID_VA_ARG,	0 },
+  { "__capability",	RID_CAPABILITY,	0 },
   { "__complex",	RID_COMPLEX,	0 },
   { "__complex__",	RID_COMPLEX,	0 },
   { "__const",		RID_CONST,	0 },
@@ -462,7 +463,6 @@ const struct c_common_resword c_common_reswords[] =
   { "char8_t",		RID_CHAR8,	D_CXX_CHAR8_T_FLAGS | D_CXXWARN },
   { "char16_t",		RID_CHAR16,	D_CXXONLY | D_CXX11 | D_CXXWARN },
   { "char32_t",		RID_CHAR32,	D_CXXONLY | D_CXX11 | D_CXXWARN },
-  { "cheri_capability", RID_CHERI_CAPABILITY,	0 },
   { "class",		RID_CLASS,	D_CXX_OBJC | D_CXXWARN },
   { "const",		RID_CONST,	0 },
   { "consteval",	RID_CONSTEVAL,	D_CXXONLY | D_CXX20 | D_CXXWARN },
@@ -8655,6 +8655,7 @@ keyword_is_type_qualifier (enum rid keyword)
     case RID_VOLATILE:
     case RID_RESTRICT:
     case RID_ATOMIC:
+    case RID_CAPABILITY:
       return true;
     default:
       return false;
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 9382383fc46..11be2b1c81f 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -249,9 +249,8 @@ enum rid
   RID_FIRST_INT_N = RID_INT_N_0,
   RID_LAST_INT_N = RID_INT_N_3,
 
-  /* Reserved Identifier for the __capability or cheri_capability type
-     attribute.  */
-  RID_CHERI_CAPABILITY,
+  /* Reserved Identifier for the __capability keyword.  */
+  RID_CAPABILITY,
 
   RID_MAX,
 
diff --git a/gcc/c-family/c-cppbuiltin.c b/gcc/c-family/c-cppbuiltin.c
index 5a0bb473b43..1fa88d023a7 100644
--- a/gcc/c-family/c-cppbuiltin.c
+++ b/gcc/c-family/c-cppbuiltin.c
@@ -1490,12 +1490,6 @@ c_cpp_builtins (cpp_reader *pfile)
      format.  */
   if (ENABLE_DECIMAL_FLOAT && ENABLE_DECIMAL_BID_FORMAT)
     cpp_define (pfile, "__DECIMAL_BID_FORMAT__");
-
-  opt_scalar_addr_mode opt_cap_mode = targetm.capability_mode();
-  if (opt_cap_mode.exists())
-    {
-      cpp_define (pfile, "__capability=__attribute__((__cheri_capability__))");
-    }
 }
 
 /* Pass an object-like macro.  If it doesn't lie in the user's
diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index e9b05efcd99..bb503862786 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -6318,16 +6318,16 @@ grokdeclarator (const struct c_declarator *declarator,
 	}
     }
 
-  /* Check if the cheri_capability attribute is in decl_attrs. If it is, then
+  /* Check if the cheri capability attribute is in decl_attrs. If it is, then
      we have a deprecated use of the __capability type attribute before the
      `*` pointer indirection.  For now, this is still supported.  */
   bool deprecated_capability_attribute_use = false;
   int deprecated_capability_uses = 0;
-  if (lookup_attribute ("cheri_capability", *decl_attrs))
+  if (lookup_attribute ("cheri capability", *decl_attrs))
     {
       deprecated_capability_attribute_use = true;
       /* Remove the __capability attribute from the decl attributes.  */
-      (*decl_attrs) = remove_attribute ("cheri_capability",
+      (*decl_attrs) = remove_attribute ("cheri capability",
 					*decl_attrs);
     }
 
@@ -6364,7 +6364,7 @@ grokdeclarator (const struct c_declarator *declarator,
 		 `int __capability * __capability x;  */
 	      if (!capability_type_p (type))
 		{
-		  tree attr_name = get_identifier ("cheri_capability");
+		  tree attr_name = get_identifier ("cheri capability");
 		  tree new_attrs = tree_cons (attr_name, NULL_TREE,
 					  returned_attrs);
 		  returned_attrs = decl_attributes (&type, new_attrs, 0);
@@ -7029,8 +7029,7 @@ grokdeclarator (const struct c_declarator *declarator,
 	    declarator = declarator->declarator;
 	    if (test_fake_hybrid ())
 	      {
-		tree attr_name = get_identifier ("cheri_capability");
-		// tree attr_args = tree_cons (NULL_TREE, NULL_TREE, NULL_TREE);
+		tree attr_name = get_identifier ("cheri capability");
 		tree new_attrs = tree_cons (attr_name, NULL_TREE, returned_attrs);
 		returned_attrs = decl_attributes (&type, new_attrs, 0);
 	      }
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index dc8893d3f5c..db804ff7601 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -579,6 +579,7 @@ c_keyword_starts_typename (enum rid keyword)
     case RID_SAT:
     case RID_AUTO_TYPE:
     case RID_ALIGNAS:
+    case RID_CAPABILITY:
       return true;
     default:
       if (keyword >= RID_FIRST_INT_N
@@ -674,6 +675,7 @@ c_token_is_qualifier (c_token *token)
 	case RID_RESTRICT:
 	case RID_ATTRIBUTE:
 	case RID_ATOMIC:
+	case RID_CAPABILITY:
 	  return true;
 	default:
 	  return false;
@@ -757,6 +759,7 @@ c_token_starts_declspecs (c_token *token)
 	case RID_ALIGNAS:
 	case RID_ATOMIC:
 	case RID_AUTO_TYPE:
+	case RID_CAPABILITY:
 	  return true;
 	default:
 	  if (token->keyword >= RID_FIRST_INT_N
@@ -2198,15 +2201,6 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 		}
 	    }
 
-	  if (lookup_attribute ("cheri_capability", postfix_attrs))
-	    {
-	      error_at (here,
-			"%<__capability%> type specifier must"
-			" precede the declarator");
-	      c_parser_skip_to_end_of_block_or_statement (parser);
-	      return;
-	    }
-
 	  if (c_parser_next_token_is (parser, CPP_EQ))
 	    {
 	      tree d;
@@ -3072,6 +3066,20 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
 	  declspecs_add_qual (loc, specs, c_parser_peek_token (parser)->value);
 	  c_parser_consume_token (parser);
 	  break;
+	case RID_CAPABILITY:
+	  {
+	    if (targetm.capability_mode ().exists ())
+	      {
+		tree attrs = build_tree_list (get_identifier ("cheri capability"),
+					      NULL_TREE);
+		declspecs_add_attrs (loc, specs, attrs);
+	      }
+	    else
+	      error_at (loc, ("%<__capability%> is not supported on this "
+			      "target"));
+	    c_parser_consume_token (parser);
+	    break;
+	  }
 	case RID_ATTRIBUTE:
 	  if (!attrs_ok)
 	    goto out;
@@ -3656,10 +3664,6 @@ c_parser_struct_declaration (c_parser *parser)
 	  if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
 	    postfix_attrs = c_parser_gnu_attributes (parser);
 
-	  if (lookup_attribute ("cheri_capability", postfix_attrs))
-	    c_parser_error (parser, "%<__capability%> type specifier must"
-				    " precede the declarator");
-
 	  d = grokfield (c_parser_peek_token (parser)->location,
 			 declarator, specs, width, &all_prefix_attrs);
 	  decl_attributes (&d, chainon (postfix_attrs,
@@ -4431,14 +4435,6 @@ c_parser_parameter_declaration (c_parser *parser, tree attrs,
   if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
     postfix_attrs = c_parser_gnu_attributes (parser);
 
-  if (lookup_attribute ("cheri_capability", postfix_attrs))
-    {
-      error ("%<__capability%> type specifier must"
-	     " precede the declarator");
-      c_parser_skip_to_end_of_parameter (parser);
-      return NULL;
-    }
-
   /* Generate a location for the parameter, ranging from the start of the
      initial token to the end of the final token.
 
@@ -4541,7 +4537,6 @@ c_parser_gnu_attribute_any_word (c_parser *parser)
 	case RID_THREAD:
 	case RID_INT:
 	case RID_INTCAP:
-	case RID_CHERI_CAPABILITY:
 	case RID_CHAR:
 	case RID_FLOAT:
 	case RID_DOUBLE:
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index b9bbdd05a93..03ca0809077 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5945,6 +5945,7 @@ enum cp_decl_spec {
   ds_complex,
   ds_constinit,
   ds_consteval,
+  ds_capability,
   ds_thread,
   ds_type_spec,
   ds_redefined_builtin_type_spec,
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 2b742b0c6c0..cda5ef2a0a8 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -11039,10 +11039,14 @@ grokdeclarator (const cp_declarator *declarator,
   bool constexpr_p = decl_spec_seq_has_spec_p (declspecs, ds_constexpr);
   bool constinit_p = decl_spec_seq_has_spec_p (declspecs, ds_constinit);
   bool consteval_p = decl_spec_seq_has_spec_p (declspecs, ds_consteval);
+  bool decl_capability_p
+    = decl_spec_seq_has_spec_p (declspecs, ds_capability);
   bool late_return_type_p = false;
   bool array_parameter_p = false;
   tree reqs = NULL_TREE;
 
+  int deprecated_capability_uses = 0;
+
   signed_p = decl_spec_seq_has_spec_p (declspecs, ds_signed);
   unsigned_p = decl_spec_seq_has_spec_p (declspecs, ds_unsigned);
   short_p = decl_spec_seq_has_spec_p (declspecs, ds_short);
@@ -11998,8 +12002,36 @@ grokdeclarator (const cp_declarator *declarator,
 
   /* Determine the type of the entity declared by recurring on the
      declarator.  */
-  for (; declarator; declarator = declarator->declarator)
+  for (;; declarator = declarator->declarator)
     {
+      if (decl_capability_p
+	  && POINTER_TYPE_P (type)
+	  && deprecated_capability_uses++ == 0)
+	{
+	  /* For __capability in the deprecated prefix position, we can apply it
+	     at most once.  */
+	  if (!capability_type_p (type))
+	    {
+	      tree attr_name = get_identifier ("cheri capability");
+	      tree to_apply = tree_cons (attr_name, NULL_TREE,
+					 returned_attrs);
+	      returned_attrs = decl_attributes (&type, to_apply, 0);
+	    }
+
+	  /* Raise the deprecated declaration warning, but only if
+	     the base type wasn't already a typedef to a pointer type.  */
+	  if (!declspecs->type
+	      || TREE_CODE (declspecs->type) != TYPE_DECL
+	      || !POINTER_TYPE_P (TREE_TYPE (declspecs->type)))
+	    warning_at (declspecs->locations[ds_capability],
+			OPT_Wdeprecated_declarations,
+			"use of %<__capability%> before the pointer "
+			"type is deprecated");
+	}
+
+      if (!declarator)
+	break;
+
       const cp_declarator *inner_declarator;
       tree attrs;
 
@@ -12628,6 +12660,16 @@ grokdeclarator (const cp_declarator *declarator,
 	}
     }
 
+  if (decl_capability_p
+      && deprecated_capability_uses == 0)
+    error_at (declspecs->locations[ds_capability],
+	      "%<__capability%> only applies to pointers");
+
+  if (decl_capability_p
+      && deprecated_capability_uses > 1)
+    error_at (declspecs->locations[ds_capability],
+	      "use of %<__capability%> is ambiguous");
+
   id_loc = declarator ? declarator->id_loc : input_location;
 
   /* A `constexpr' specifier used in an object declaration declares
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 568f0809963..a3812e4849f 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -2259,7 +2259,7 @@ static cp_declarator *cp_parser_direct_declarator
 static enum tree_code cp_parser_ptr_operator
   (cp_parser *, tree *, cp_cv_quals *, tree *);
 static cp_cv_quals cp_parser_cv_qualifier_seq_opt
-  (cp_parser *);
+  (cp_parser *, tree *);
 static cp_virt_specifiers cp_parser_virt_specifier_seq_opt
   (cp_parser *);
 static cp_ref_qualifier cp_parser_ref_qualifier_opt
@@ -17863,6 +17863,12 @@ cp_parser_type_specifier (cp_parser* parser,
 	*is_cv_qualifier = true;
       break;
 
+    case RID_CAPABILITY:
+      ds = ds_capability;
+      if (is_cv_qualifier)
+	*is_cv_qualifier = true;
+      break;
+
     case RID_COMPLEX:
       /* The `__complex__' keyword is a GNU extension.  */
       ds = ds_complex;
@@ -21332,7 +21338,7 @@ cp_parser_direct_declarator (cp_parser* parser,
 		  first = false;
 
 		  /* Parse the cv-qualifier-seq.  */
-		  cv_quals = cp_parser_cv_qualifier_seq_opt (parser);
+		  cv_quals = cp_parser_cv_qualifier_seq_opt (parser, NULL);
 		  /* Parse the ref-qualifier. */
 		  ref_qual = cp_parser_ref_qualifier_opt (parser);
 		  /* Parse the tx-qualifier.  */
@@ -21842,6 +21848,7 @@ cp_parser_ptr_operator (cp_parser* parser,
   enum tree_code code = ERROR_MARK;
   cp_token *token;
   tree attrs = NULL_TREE;
+  tree qual_attrs = NULL_TREE;
 
   /* Assume that it's not a pointer-to-member.  */
   *type = NULL_TREE;
@@ -21871,9 +21878,10 @@ cp_parser_ptr_operator (cp_parser* parser,
 	 enforced during semantic analysis.  */
       if (code == INDIRECT_REF
 	  || cp_parser_allow_gnu_extensions_p (parser))
-	*cv_quals = cp_parser_cv_qualifier_seq_opt (parser);
+	*cv_quals = cp_parser_cv_qualifier_seq_opt (parser, &qual_attrs);
 
       attrs = cp_parser_std_attribute_spec_seq (parser);
+      attrs = chainon (attrs, qual_attrs);
       if (attributes != NULL)
 	*attributes = attrs;
     }
@@ -21915,10 +21923,12 @@ cp_parser_ptr_operator (cp_parser* parser,
 	      parser->object_scope = NULL_TREE;
 	      /* Look for optional c++11 attributes.  */
 	      attrs = cp_parser_std_attribute_spec_seq (parser);
+	      /* Look for the optional cv-qualifier-seq.  */
+	      *cv_quals = cp_parser_cv_qualifier_seq_opt (parser,
+							  &qual_attrs);
+	      attrs = chainon (attrs, qual_attrs);
 	      if (attributes != NULL)
 		*attributes = attrs;
-	      /* Look for the optional cv-qualifier-seq.  */
-	      *cv_quals = cp_parser_cv_qualifier_seq_opt (parser);
 	    }
 	}
       /* If that didn't work we don't have a ptr-operator.  */
@@ -21946,14 +21956,16 @@ cp_parser_ptr_operator (cp_parser* parser,
    Returns a bitmask representing the cv-qualifiers.  */
 
 static cp_cv_quals
-cp_parser_cv_qualifier_seq_opt (cp_parser* parser)
+cp_parser_cv_qualifier_seq_opt (cp_parser* parser, tree *attributes)
 {
   cp_cv_quals cv_quals = TYPE_UNQUALIFIED;
+  tree attr_list = NULL_TREE;
 
   while (true)
     {
       cp_token *token;
-      cp_cv_quals cv_qualifier;
+      cp_cv_quals cv_qualifier = TYPE_UNQUALIFIED;
+      tree attr = NULL_TREE;
 
       /* Peek at the next token.  */
       token = cp_lexer_peek_token (parser->lexer);
@@ -21972,12 +21984,18 @@ cp_parser_cv_qualifier_seq_opt (cp_parser* parser)
 	  cv_qualifier = TYPE_QUAL_RESTRICT;
 	  break;
 
+	case RID_CAPABILITY:
+	  if (attributes)
+	    attr = get_identifier ("cheri capability");
+	  else
+	    error_at (token->location, "unexpected %<__capability%>");
+	  break;
+
 	default:
-	  cv_qualifier = TYPE_UNQUALIFIED;
 	  break;
 	}
 
-      if (!cv_qualifier)
+      if (!cv_qualifier && !attr)
 	break;
 
       if (cv_quals & cv_qualifier)
@@ -21987,13 +22005,25 @@ cp_parser_cv_qualifier_seq_opt (cp_parser* parser)
 	  error_at (&richloc, "duplicate cv-qualifier");
 	  cp_lexer_purge_token (parser->lexer);
 	}
+      else if (attr && attr_list)
+	{
+	  gcc_rich_location richloc (token->location);
+	  richloc.add_fixit_remove ();
+	  error_at (&richloc, "duplicate %<__capability%>");
+	  cp_lexer_purge_token (parser->lexer);
+	}
       else
 	{
 	  cp_lexer_consume_token (parser->lexer);
-	  cv_quals |= cv_qualifier;
+	  if (attr)
+	    attr_list = build_tree_list (attr, NULL_TREE);
+	  else
+	    cv_quals |= cv_qualifier;
 	}
     }
 
+  if (attributes)
+    *attributes = attr_list;
   return cv_quals;
 }
 
@@ -30576,7 +30606,8 @@ set_and_check_decl_spec_loc (cp_decl_specifier_seq *decl_specs,
 	    "constexpr",
 	    "__complex",
 	    "constinit",
-	    "consteval"
+	    "consteval",
+	    "__capability",
 	  };
 	  gcc_rich_location richloc (location);
 	  richloc.add_fixit_remove ();
diff --git a/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_ret_types_hybrid-3.C b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_ret_types_hybrid-3.C
index 4571206f040..74046a00c4c 100644
--- a/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_ret_types_hybrid-3.C
+++ b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_ret_types_hybrid-3.C
@@ -9,16 +9,16 @@ void
 check_return_types_for_alignment_builtin_overloads_cap (size_t a,
         int * __capability i, char * __capability c,  void * __capability v)
 {
-  static_assert (__is_same (decltype (__builtin_align_down (i, a)), int __capability*), "");
-  static_assert (__is_same (decltype (__builtin_align_down (c, a)), char __capability*), "");
-  static_assert (__is_same (decltype (__builtin_align_down (v, a)), void __capability*), "");
+  static_assert (__is_same (decltype (__builtin_align_down (i, a)), int * __capability), "");
+  static_assert (__is_same (decltype (__builtin_align_down (c, a)), char * __capability), "");
+  static_assert (__is_same (decltype (__builtin_align_down (v, a)), void * __capability), "");
   static_assert (__is_same (decltype (__builtin_align_down (128, a)), int), "");
   static_assert (__is_same (decltype (__builtin_align_down ((intptr_t)128, a)), intptr_t), "");
   static_assert (__is_same (decltype (__builtin_align_down ((uintptr_t)128, a)), uintptr_t), "");
 
-  static_assert (__is_same (decltype (__builtin_align_up (i, a)), int __capability*), "");
-  static_assert (__is_same (decltype (__builtin_align_up (c, a)), char __capability*), "");
-  static_assert (__is_same (decltype (__builtin_align_up (v, a)), void __capability*), "");
+  static_assert (__is_same (decltype (__builtin_align_up (i, a)), int * __capability), "");
+  static_assert (__is_same (decltype (__builtin_align_up (c, a)), char * __capability), "");
+  static_assert (__is_same (decltype (__builtin_align_up (v, a)), void * __capability), "");
   static_assert (__is_same (decltype (__builtin_align_up (128, a)), int), "");
   static_assert (__is_same (decltype (__builtin_align_up ((intptr_t)128, a)), intptr_t), "");
   static_assert (__is_same (decltype (__builtin_align_up ((uintptr_t)128, a)), uintptr_t), "");
diff --git a/gcc/testsuite/g++.target/aarch64/morello/cap-keyword-helpers.h b/gcc/testsuite/g++.target/aarch64/morello/cap-keyword-helpers.h
new file mode 100644
index 00000000000..bb4a83f4c41
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/cap-keyword-helpers.h
@@ -0,0 +1,14 @@
+enum {
+  CAP_SIZE = sizeof (void * __capability),
+  PTR_SIZE = sizeof (void *),
+};
+#define CHECK_CAP(e) static_assert (sizeof (e) == CAP_SIZE)
+#define CHECK_PTR(e) static_assert (sizeof (e) == PTR_SIZE)
+
+#ifdef __CHERI__
+#ifdef __CHERI_PURE_CAPABILITY__
+static_assert (CAP_SIZE == PTR_SIZE);
+#else
+static_assert (CAP_SIZE > PTR_SIZE);
+#endif
+#endif
diff --git a/gcc/testsuite/g++.target/aarch64/morello/capability-keyword-errors.C b/gcc/testsuite/g++.target/aarch64/morello/capability-keyword-errors.C
new file mode 100644
index 00000000000..739f5a60af8
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/capability-keyword-errors.C
@@ -0,0 +1,18 @@
+// { dg-do compile }
+__capability int x1; // { dg-error "'__capability' only applies to pointers" }
+int __capability x2; // { dg-error "'__capability' only applies to pointers" }
+int x3 __capability; // { dg-error "expected initializer before '__capability'" }
+int * __capability __capability p1; // { dg-error "duplicate '__capability'" }
+__capability __capability int *p2; // { dg-error "duplicate '__capability'" }
+// { dg-warning "use of '__capability' before the pointer type" "" { target *-*-* } .-1 }
+__capability int **p3; // { dg-error "use of '__capability' is ambiguous" }
+// { dg-warning "use of '__capability' before the pointer type" "" { target *-*-* } .-1 }
+
+int f1() __capability; // { dg-error "unexpected '__capability'" }
+// { dg-error "expected initializer before '__capability'" "" { target *-*-* } .-1 }
+__capability int g1(); // { dg-error "'__capability' only applies to pointers" }
+int __capability g2(); // { dg-error "'__capability' only applies to pointers" }
+
+auto f2() {
+  return new int __capability; // { dg-error "'__capability' only applies to pointers" }
+}
diff --git a/gcc/testsuite/g++.target/aarch64/morello/capability-keyword-valid.C b/gcc/testsuite/g++.target/aarch64/morello/capability-keyword-valid.C
new file mode 100644
index 00000000000..cb156bfef84
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/capability-keyword-valid.C
@@ -0,0 +1,101 @@
+/* { dg-do compile } */
+
+#include "cap-keyword-helpers.h"
+
+int * __capability p1;
+CHECK_CAP (p1);
+
+int * __capability p2, * __capability p3;
+CHECK_CAP (p2);
+CHECK_CAP (p3);
+
+const int * __capability p4;
+CHECK_CAP (p4);
+
+int * const __capability p5 = 0;
+CHECK_CAP (p5);
+
+char *p6, * __capability p7;
+CHECK_PTR (p6);
+CHECK_CAP (p7);
+
+int * __capability * __capability p8;
+CHECK_CAP (p8);
+CHECK_CAP (*p8);
+
+int ** __capability p9;
+CHECK_CAP (p9);
+CHECK_PTR (*p9);
+
+char * __capability return_cap ();
+CHECK_CAP (return_cap ());
+
+void pass_cap (void * __capability arg)
+{
+  CHECK_CAP (arg);
+}
+
+// Check typedef cases.
+typedef int *int_star;
+int_star t1;
+CHECK_PTR (t1);
+
+__capability int_star t2;
+int_star __capability t3;
+CHECK_CAP (t2);
+CHECK_CAP (t3);
+
+int_star * __capability t4;
+CHECK_CAP (t4);
+CHECK_PTR (*t4);
+
+typedef int * __capability T;
+CHECK_CAP (T);
+
+__capability T t5;
+T __capability t6;
+T * __capability t7;
+T *t8;
+CHECK_CAP (t5);
+CHECK_CAP (t6);
+CHECK_CAP (t7);
+CHECK_CAP (*t7);
+CHECK_PTR (t8);
+CHECK_CAP (*t8);
+
+
+struct S1 {
+  int x;
+} * __capability ps;
+CHECK_CAP (ps);
+
+struct S2 {
+  float * __capability p;
+  char * __capability mem_fn ();
+};
+void foo(struct S2 *arg)
+{
+  CHECK_CAP (arg->p);
+  CHECK_CAP (arg->mem_fn ());
+}
+
+int * __capability *do_new()
+{
+  return new int * __capability;
+}
+CHECK_PTR (do_new ());
+CHECK_CAP (*do_new ());
+
+using U1 = int * __capability;
+CHECK_CAP (U1);
+
+template<typename Targ>
+void templ_fn()
+{
+  CHECK_CAP (Targ);
+}
+
+void call_templ_fn ()
+{
+  templ_fn<int * __capability>();
+}
diff --git a/gcc/testsuite/g++.target/aarch64/morello/capability-keyword-warn.C b/gcc/testsuite/g++.target/aarch64/morello/capability-keyword-warn.C
new file mode 100644
index 00000000000..6ddaf669de9
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/capability-keyword-warn.C
@@ -0,0 +1,44 @@
+// { dg-do compile }
+
+#include "cap-keyword-helpers.h"
+
+__capability char *p1; // { dg-warning "use of '__capability' before the pointer type" }
+char __capability *p2; // { dg-warning "use of '__capability' before the pointer type" }
+CHECK_CAP (p1);
+CHECK_CAP (p2);
+
+__capability short *f1(); // { dg-warning "use of '__capability' before the pointer type" }
+CHECK_CAP (f1 ());
+
+struct S1 {
+  __capability long *m1;  // { dg-warning "use of '__capability' before the pointer type" }
+  long __capability * m2; // { dg-warning "use of '__capability' before the pointer type" }
+  __capability double *f1(); // { dg-warning "use of '__capability' before the pointer type" }
+  double __capability *f2(); // { dg-warning "use of '__capability' before the pointer type" }
+};
+S1 s1;
+CHECK_CAP (s1.m1);
+CHECK_CAP (s1.m2);
+CHECK_CAP (s1.f1 ());
+CHECK_CAP (s1.f2 ());
+
+struct s {
+  int x;
+} __capability *ps; // { dg-warning "use of '__capability' before the pointer type is deprecated" }
+CHECK_CAP (ps);
+
+bool * __capability *do_new (int x)
+{
+  if (x)
+    return new __capability bool *; // { dg-warning "use of '__capability' before the pointer type is deprecated" }
+  else
+    return new bool __capability *; // { dg-warning "use of '__capability' before the pointer type is deprecated" }
+}
+CHECK_PTR (do_new (0));
+CHECK_CAP (*do_new (0));
+
+typedef __capability int *T1; // { dg-warning "use of '__capability' before the pointer type is deprecated" }
+CHECK_CAP (T1);
+
+typedef int __capability *T2; // { dg-warning "use of '__capability' before the pointer type is deprecated" }
+CHECK_CAP (T2);
diff --git a/gcc/testsuite/gcc.target/aarch64/capability-keyword-invalid.c b/gcc/testsuite/gcc.target/aarch64/capability-keyword-invalid.c
new file mode 100644
index 00000000000..77c6e8aa065
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/capability-keyword-invalid.c
@@ -0,0 +1,6 @@
+/* { dg-do compile { target { aarch64*-*-* && { ! { aarch64_capability_any } } } } } */
+
+/* Check that we error on non-capability targets.  */
+int * __capability var1; /* { dg-error "'__capability' is not supported on this target" } */
+__capability int * var2; /* { dg-error "'__capability' is not supported on this target" } */
+int __capability * var3; /* { dg-error "'__capability' is not supported on this target" } */
diff --git a/gcc/testsuite/gcc.target/aarch64/capability_attribute_invalid.c b/gcc/testsuite/gcc.target/aarch64/capability_attribute_invalid.c
deleted file mode 100644
index f679c7cb1f2..00000000000
--- a/gcc/testsuite/gcc.target/aarch64/capability_attribute_invalid.c
+++ /dev/null
@@ -1,8 +0,0 @@
-/* { dg-do compile { target { aarch64*-*-* && { ! { aarch64_capability_any } } } } } */
-
-/* Error if Morello not enabled. Currently the macro mapping __capability to __attribute__((__cheri_capability__))
-   is conditionally enabled on having a capability type enabled: targetm.capability_mode (), so in the first case
-   we do ugly-error instead of gracefully-error.  */
-int * __capability var1; /* { dg-error "" } */
-int * __attribute__((__cheri_capability__)) var2; /* { dg-error "'__capability' attribute is not supported for this architecture" } */
-int * __attribute__((cheri_capability)) var3; /* { dg-error "'__capability' attribute is not supported for this architecture" } */
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/capability-keyword-struct.c b/gcc/testsuite/gcc.target/aarch64/morello/capability-keyword-struct.c
new file mode 100644
index 00000000000..0c2454b792e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/morello/capability-keyword-struct.c
@@ -0,0 +1,4 @@
+/* { dg-do compile } */
+struct s {
+  int x;
+} __capability *p; /* { dg-warning "use of '__capability' before the pointer type is deprecated" } */
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/capability_attribute_macro_check.c b/gcc/testsuite/gcc.target/aarch64/morello/capability_attribute_macro_check.c
deleted file mode 100644
index f6913571361..00000000000
--- a/gcc/testsuite/gcc.target/aarch64/morello/capability_attribute_macro_check.c
+++ /dev/null
@@ -1,12 +0,0 @@
-/* { dg-do preprocess { target aarch64*-*-* } } */
-
-/* Test that the __capability macro and __attribute__((__cheri_capability__))
-   produce exactly the same result.  */
-
-int *__capability macrotestvar1;
-int *__attribute__((__cheri_capability__)) macrotestvar2;
-int *__attribute__((cheri_capability)) macrotestvar3;
-
-/* Sadly there's no such thing as a scan-file-times to use here,
-   so just do !__capability instead.  */
-/* { dg-final { scan-file-not capability_attribute_macro_check.i "__capability" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/capability_attribute_errors_1.c b/gcc/testsuite/gcc.target/aarch64/morello/capability_keyword_errors.c
similarity index 63%
rename from gcc/testsuite/gcc.target/aarch64/morello/capability_attribute_errors_1.c
rename to gcc/testsuite/gcc.target/aarch64/morello/capability_keyword_errors.c
index 77f19f7b021..b9f0190a887 100644
--- a/gcc/testsuite/gcc.target/aarch64/morello/capability_attribute_errors_1.c
+++ b/gcc/testsuite/gcc.target/aarch64/morello/capability_keyword_errors.c
@@ -4,7 +4,8 @@
 /* Error on non-pointers.  */
 int __capability var1;  /* { dg-error "'__capability' only applies to pointers" } */
 __capability int var2;  /* { dg-error "'__capability' only applies to pointers" } */
-int var3 __capability;  /* { dg-error "'__capability' type specifier must precede the declarator" } */
+int var3 __capability;  /* { dg-error "expected ';' before '__capability'" } */
+/* { dg-warning "empty declaration" "" { target *-*-* } .-1 } */
 char __capability string1[]  = "abcdef" ;  /* { dg-error "'__capability' only applies to pointers" } */
 void f1 (int __capability x); /* { dg-error "'__capability' only applies to pointers" } */
 void __capability f2 (); /* { dg-error "'__capability' only applies to pointers" } */
@@ -13,9 +14,12 @@ int __capability f3 (); /* { dg-error "'__capability' only applies to pointers"
 typedef int __capability noncapptr; /* { dg-error "'__capability' only applies to pointers" } */
 
 /* Improper ordering: Error cases.  */
-int * var4 __capability ; /* { dg-error "'__capability' type specifier must precede the declarator" } */
-int *var5 __capability; /* { dg-error "'__capability' type specifier must precede the declarator" } */
-int* var6 __capability; /* { dg-error "'__capability' type specifier must precede the declarator" } */
+int * var4 __capability ; /* { dg-error "expected ';' before '__capability'" } */
+/* { dg-warning "empty declaration" "" { target *-*-* } .-1 } */
+int *var5 __capability; /* { dg-error "expected ';' before '__capability'" } */
+/* { dg-warning "empty declaration" "" { target *-*-* } .-1 } */
+int* var6 __capability; /* { dg-error "expected ';' before '__capability'" } */
+/* { dg-warning "empty declaration" "" { target *-*-* } .-1 } */
 int __capability **var7; /* { dg-error "use of '__capability' is ambiguous" } */
 /* { dg-warning "use of '__capability' before the pointer type is deprecated" "" { target *-*-* } .-1 } */
 __capability int ** var8; /* { dg-error "use of '__capability' is ambiguous" } */
@@ -39,16 +43,20 @@ int __capability * __capability * var11; /* { dg-error "use of '__capability' is
 /* { dg-warning "use of '__capability' before the pointer type is deprecated" "" { target *-*-* } .-1 } */
 
 /* Adding attribute to a function. Improper ordering: Error cases. */
-void *f4 __capability (void);   /* { dg-error "'__capability' type specifier must precede the declarator" } */
-void (*f5) __capability (void); /* { dg-error "'__capability' type specifier must precede the declarator" } */
-void* f6 __capability (void);  /* { dg-error "'__capability' type specifier must precede the declarator" } */
-int *f7 __capability (void);   /* { dg-error "'__capability' type specifier must precede the declarator" } */
-int* f8 __capability (void);   /* { dg-error "'__capability' type specifier must precede the declarator" } */
-int* f9 (void) __capability;   /* { dg-error "'__capability' type specifier must precede the declarator" } */
+void *f4 __capability (void);   /* { dg-error "expected ';' before '__capability'" } */
+/* { dg-error "expected identifier or '\\(' before 'void'" "" { target *-*-* } .-1 } */
+void (*f5) __capability (void); /* { dg-error "expected ';' before '__capability'" } */
+/* { dg-error "expected identifier or '\\(' before 'void'" "" { target *-*-* } .-1 } */
+void* f6 __capability (void);  /* { dg-error "expected ';' before '__capability'" } */
+/* { dg-error "expected identifier or '\\(' before 'void'" "" { target *-*-* } .-1 } */
+int *f7 __capability (void);   /* { dg-error "expected ';' before '__capability'" } */
+/* { dg-error "expected identifier or '\\(' before 'void'" "" { target *-*-* } .-1 } */
+int* f8 __capability (void);   /* { dg-error "expected ';' before '__capability'" } */
+/* { dg-error "expected identifier or '\\(' before 'void'" "" { target *-*-* } .-1 } */
 
 /* Adding attribute to a function parameter. Improper ordering: Error cases. */
-void f10 (int* var12 __capability);/* { dg-error "'__capability' type specifier must precede the declarator" } */
-void f11 (int *var13 __capability);/* { dg-error "'__capability' type specifier must precede the declarator" } */
+void f10 (int* var12 __capability);/* { dg-error "expected ';', ',' or '\\)' before '__capability'" } */
+void f11 (int *var13 __capability);/* { dg-error "expected ';', ',' or '\\)' before '__capability'" } */
 void f12 (int __capability ** var14); /* { dg-error "use of '__capability' is ambiguous" } */
 /* { dg-warning "use of '__capability' before the pointer type is deprecated" "" { target *-*-* } .-1 } */
 void f13 (__capability int ** var15);  /* { dg-error "use of '__capability' is ambiguous" } */
@@ -56,21 +64,24 @@ void f13 (__capability int ** var15);  /* { dg-error "use of '__capability' is a
 
 /* Putting int* in a typedef...  */
 typedef int* intptr;
-intptr var16 __capability;  /* { dg-error "'__capability' type specifier must precede the declarator" } */
-intptr* var17 __capability; /* { dg-error "'__capability' type specifier must precede the declarator" } */
+intptr var16 __capability;  /* { dg-error "expected ';' before '__capability'" } */
+/* { dg-warning "empty declaration" "" { target *-*-* } .-1 } */
+intptr* var17 __capability; /* { dg-error "expected ';' before '__capability'" } */
+/* { dg-warning "empty declaration" "" { target *-*-* } .-1 } */
 
 /* Putting int*__capability in a typedef...  */
 typedef int * __capability intptr2;
-intptr2* var18 __capability;   /* { dg-error "'__capability' type specifier must precede the declarator" } */
+intptr2* var18 __capability;   /* { dg-error "expected ';' before '__capability'" } */
+/* { dg-warning "empty declaration" "" { target *-*-* } .-1 } */
 
 /* Try putting pointers in a struct.  */
 struct cheri_object1
 {
-   void *var19 __capability, *var20; /* { dg-error "'__capability' type specifier must precede the declarator" } */
+   void *var19 __capability, *var20; /* { dg-error "expected ':', ',', ';', '\}' or '__attribute__' before '__capability'" } */
 };
 struct cheri_object2
 {
-  void * var19, *var20 __capability; /* { dg-error "'__capability' type specifier must precede the declarator" } */
+  void * var19, *var20 __capability; /* { dg-error "expected ':', ',', ';', '\}' or '__attribute__' before '__capability'" } */
 };
 struct cheri_object3
 {
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/capability_attribute_uses.c b/gcc/testsuite/gcc.target/aarch64/morello/capability_keyword_uses.c
similarity index 86%
rename from gcc/testsuite/gcc.target/aarch64/morello/capability_attribute_uses.c
rename to gcc/testsuite/gcc.target/aarch64/morello/capability_keyword_uses.c
index ee20cf34412..3f80b7602d9 100644
--- a/gcc/testsuite/gcc.target/aarch64/morello/capability_attribute_uses.c
+++ b/gcc/testsuite/gcc.target/aarch64/morello/capability_keyword_uses.c
@@ -81,13 +81,6 @@ struct cheri_object6
   void ** __capability var32;
 };
 
-/* Simple uses of defining the attribute as __attribute__, also with multiple
-   attribute definitions.  */
-char *__attribute__((__cheri_capability__)) attrtestvar1;
-char *__attribute__((cheri_capability)) attrtestvar2;
-char *__attribute__((cheri_capability, used)) attrtestvar3;
-char *__attribute__((__cheri_capability__, __used__)) attrtestvar4;
-
 /* And a quick runtime test.  */
 int main()
 {
@@ -110,10 +103,6 @@ int main()
   printf("%c\n", *test);
   printf("%c\n", *test2);
 
-  /* Simple test of assignments on the __attribute__-defined pointers.  */
-  attrtestvar1 = stringpointer;
-  attrtestvar3 = attrtestvar1;
-
   /* Simple test zero-assignment.  */
   test3 = 0;
 
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/capability_attribute_warnings_1.c b/gcc/testsuite/gcc.target/aarch64/morello/capability_keyword_warnings.c
similarity index 96%
rename from gcc/testsuite/gcc.target/aarch64/morello/capability_attribute_warnings_1.c
rename to gcc/testsuite/gcc.target/aarch64/morello/capability_keyword_warnings.c
index 7acc9b8c7f8..967b8c8fe0c 100644
--- a/gcc/testsuite/gcc.target/aarch64/morello/capability_attribute_warnings_1.c
+++ b/gcc/testsuite/gcc.target/aarch64/morello/capability_keyword_warnings.c
@@ -7,9 +7,9 @@ __capability int *var2; /* { dg-warning "use of '__capability' before the pointe
 __capability int ** __capability var3; /* { dg-warning "use of '__capability' before the pointer type is deprecated" } */
 __capability void *var4, *var5; /* { dg-warning "use of '__capability' before the pointer type is deprecated" } */
 void __capability *var6, *var7; /* { dg-warning "use of '__capability' before the pointer type is deprecated" } */
-void *var8, __capability *var9;   /* { dg-warning "use of '__capability' before the pointer type is deprecated" } */
 __capability int **__capability z2;/* { dg-warning "use of '__capability' before the pointer type is deprecated" } */
 __capability int *__capability z3; /* { dg-warning "use of '__capability' before the pointer type is deprecated" } */
+typeof (__capability int *) x; /* { dg-warning "use of '__capability' before the pointer type is deprecated" } */
 
 /* Adding attribute to a function. Improper ordering: Warning cases. */
 __capability void *f1 (void);/* { dg-warning "use of '__capability' before the pointer type is deprecated" } */

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2022-11-22 12:42 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-11-14 13:24 [gcc(refs/vendors/ARM/heads/morello)] c, cp: Switch to handling __capability as a keyword Alex Coplan
2022-11-22 12:42 Stam Markianos-Wright

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).