public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Iain Sandoe <iain@sandoe.co.uk>
To: GCC Patches <GCC-patches@gcc.gnu.org>
Cc: Jason Merrill <jason@redhat.com>, Nathan Sidwell <nathan@acm.org>,
	Joseph Myers <joseph@codesourcery.com>
Subject: PING^1 Re: [PATCH v2] C-family : Add attribute 'unavailable'.
Date: Fri, 27 Nov 2020 20:49:46 +0000	[thread overview]
Message-ID: <0D2814B3-E808-4E4E-A2DB-C3F810E8BB13@sandoe.co.uk> (raw)
In-Reply-To: <1DC1B5BE-1FCE-4E55-9F91-96A475D0CA84@sandoe.co.uk>

Hi

I believe this version addressed Joseph’s and Richard’s comment, but it
C++ review.

thanks
Iain



Iain Sandoe <iain@sandoe.co.uk> wrote:

> Joseph Myers <joseph@codesourcery.com> wrote:
>
>> This patch seems to be missing documentation for the new attribute in
>> extend.texi.
>
> Apologies, for that omission, revised patch includes the documentation and
> also addresses Richi’s comments.
>
> documentation patch tested with “make pdf” and visual inspection of the  
> output.
>
> OK now?
> thanks
> Iain
>
> —— commit message.
>
> If an interface is marked 'deprecated' then, presumably, at some point it
> will be withdrawn and no longer available.  The 'unavailable' attribute
> makes it possible to mark up interfaces to indicate this status.  It is  
> used
> quite extensively in some codebases where a single set of headers can be  
> used
> to permit code generation for multiple system versions.
>
> From a configuration perspective, it also allows a compile test to  
> determine
> that an interface is missing - rather than requiring a link test.
>
> The implementation follows the pattern of attribute deprecated, but  
> produces
> an error (where deprecation produces a warning).
>
> This attribute has been implemented in clang for some years.
>
> gcc/c-family/ChangeLog:
>
> 	* c-attribs.c (handle_unavailable_attribute): New.
>
> gcc/c/ChangeLog:
>
> 	* c-decl.c (enum deprecated_states): Add unavailable state.
> 	(merge_decls): Copy unavailability.
> 	(quals_from_declspecs): Handle unavailable case.
> 	(start_decl): Amend the logic handling suppression of nested
> 	deprecation states to include unavailability.
> 	(smallest_type_quals_location): Amend comment.
> 	(grokdeclarator): Handle the unavailable deprecation state.
> 	(declspecs_add_type): Set TREE_UNAVAILABLE from the decl specs.
> 	* c-tree.h (struct c_declspecs): Add unavailable_p.
> 	* c-typeck.c (build_component_ref): Handle unavailability.
> 	(build_external_ref): Likewise.
>
> gcc/cp/ChangeLog:
>
> 	* call.c (build_over_call): Handle unavailable state in addition to
> 	deprecation.
> 	* class.c (type_build_ctor_call): Likewise.
> 	(type_build_dtor_call): Likewise.
> 	* cp-tree.h: Rename cp_warn_deprecated_use to
> 	cp_handle_deprecated_or_unavailable.
> 	* decl.c (duplicate_decls): Merge unavailability.
> 	(grokdeclarator): Handle unavailability in addition to deprecation.
> 	(type_is_unavailable): New.
> 	(grokparms): Handle unavailability in addition to deprecation.
> 	* decl.h (enum deprecated_states): Add
> 	UNAVAILABLE_DEPRECATED_SUPPRESS.
> 	* decl2.c (cplus_decl_attributes): Propagate unavailability to
> 	templates.
> 	(cp_warn_deprecated_use): Rename to ...
> 	(cp_handle_deprecated_or_unavailable): ... this and amend to handle
> 	the unavailable case. It remains a warning in the case of deprecation
> 	but becomes an error in the case of unavailability.
> 	(cp_warn_deprecated_use_scopes): Handle unavailability.
> 	(mark_used): Likewise.
> 	* parser.c (cp_parser_template_name): Likewise.
> 	(cp_parser_template_argument): Likewise.
> 	(cp_parser_parameter_declaration_list): Likewise.
> 	* typeck.c (build_class_member_access_expr): Likewise.
> 	(finish_class_member_access_expr): Likewise.
> 	* typeck2.c (build_functional_cast_1): Likewise.
>
> gcc/ChangeLog:
>
> 	* doc/extend.texi: Document unavailable attribute.
> 	* print-tree.c (print_node): Handle unavailable attribute.
> 	* tree-core.h (struct tree_base): Add a bit to carry unavailability.
> 	* tree.c (error_unavailable_use): New.
> 	* tree.h (TREE_UNAVAILABLE): New.
> 	(error_unavailable_use): New.
>
> gcc/objc/ChangeLog:
>
> 	* objc-act.c (objc_add_property_declaration): Register unavailable
> 	attribute.
> 	(maybe_make_artificial_property_decl): Set available.
> 	(objc_maybe_build_component_ref): Generalise to the method prototype
> 	to count availability.
> 	(objc_build_class_component_ref): Likewise.
> 	(build_private_template): Likewise.
> 	(objc_decl_method_attributes): Handle unavailable attribute.
> 	(lookup_method_in_hash_lists): Amend comments.
> 	(objc_finish_message_expr): Handle unavailability in addition to
> 	deprecation.
> 	(start_class): Likewise.
> 	(finish_class): Likewise.
> 	(lookup_protocol): Likewise.
> 	(objc_declare_protocol): Likewise.
> 	(start_protocol): Register unavailable attribute.
> 	(really_start_method): Likewise.
> 	(objc_gimplify_property_ref): Emit error on encountering an
> 	unavailable entity (and a warning for a deprecated one).
>
> gcc/testsuite/ChangeLog:
>
> 	* g++.dg/ext/attr-unavailable-1.C: New test.
> 	* g++.dg/ext/attr-unavailable-2.C: New test.
> 	* g++.dg/ext/attr-unavailable-3.C: New test.
> 	* g++.dg/ext/attr-unavailable-4.C: New test.
> 	* g++.dg/ext/attr-unavailable-5.C: New test.
> 	* g++.dg/ext/attr-unavailable-6.C: New test.
> 	* g++.dg/ext/attr-unavailable-7.C: New test.
> 	* g++.dg/ext/attr-unavailable-8.C: New test.
> 	* g++.dg/ext/attr-unavailable-9.C: New test.
> 	* gcc.dg/attr-unavailable-1.c: New test.
> 	* gcc.dg/attr-unavailable-2.c: New test.
> 	* gcc.dg/attr-unavailable-3.c: New test.
> 	* gcc.dg/attr-unavailable-4.c: New test.
> 	* gcc.dg/attr-unavailable-5.c: New test.
> 	* gcc.dg/attr-unavailable-6.c: New test.
> 	* obj-c++.dg/attributes/method-unavailable-1.mm: New test.
> 	* obj-c++.dg/attributes/method-unavailable-2.mm: New test.
> 	* obj-c++.dg/attributes/method-unavailable-3.mm: New test.
> 	* obj-c++.dg/property/at-property-unavailable-1.mm: New test.
> 	* obj-c++.dg/property/at-property-unavailable-2.mm: New test.
> 	* obj-c++.dg/property/dotsyntax-unavailable-1.mm: New test.
> 	* objc.dg/attributes/method-unavailable-1.m: New test.
> 	* objc.dg/attributes/method-unavailable-2.m: New test.
> 	* objc.dg/attributes/method-unavailable-3.m: New test.
> 	* objc.dg/property/at-property-unavailable-1.m: New test.
> 	* objc.dg/property/at-property-unavailable-2.m: New test.
> 	* objc.dg/property/dotsyntax-unavailable-1.m: New test.
> ---
> gcc/c-family/c-attribs.c                      |  69 +++++++++++
> gcc/c/c-decl.c                                |  39 ++++--
> gcc/c/c-tree.h                                |   2 +
> gcc/c/c-typeck.c                              |   8 +-
> gcc/cp/call.c                                 |   4 +-
> gcc/cp/class.c                                |   2 +
> gcc/cp/cp-tree.h                              |   2 +-
> gcc/cp/decl.c                                 |  66 ++++++++--
> gcc/cp/decl.h                                 |   3 +-
> gcc/cp/decl2.c                                |  58 +++++++--
> gcc/cp/parser.c                               |  32 +++--
> gcc/cp/typeck.c                               |   9 +-
> gcc/cp/typeck2.c                              |   2 +-
> gcc/doc/extend.texi                           |  46 +++++++
> gcc/objc/objc-act.c                           |  81 +++++++++----
> gcc/print-tree.c                              |   2 +
> gcc/testsuite/g++.dg/ext/attr-unavailable-1.C | 113 ++++++++++++++++++
> gcc/testsuite/g++.dg/ext/attr-unavailable-2.C |  10 ++
> gcc/testsuite/g++.dg/ext/attr-unavailable-3.C |  14 +++
> gcc/testsuite/g++.dg/ext/attr-unavailable-4.C |  11 ++
> gcc/testsuite/g++.dg/ext/attr-unavailable-5.C |   6 +
> gcc/testsuite/g++.dg/ext/attr-unavailable-6.C | 110 +++++++++++++++++
> gcc/testsuite/g++.dg/ext/attr-unavailable-7.C |  19 +++
> gcc/testsuite/g++.dg/ext/attr-unavailable-8.C |  17 +++
> gcc/testsuite/g++.dg/ext/attr-unavailable-9.C |  17 +++
> gcc/testsuite/gcc.dg/attr-unavailable-1.c     |  88 ++++++++++++++
> gcc/testsuite/gcc.dg/attr-unavailable-2.c     |   6 +
> gcc/testsuite/gcc.dg/attr-unavailable-3.c     |  10 ++
> gcc/testsuite/gcc.dg/attr-unavailable-4.c     |  88 ++++++++++++++
> gcc/testsuite/gcc.dg/attr-unavailable-5.c     |   6 +
> gcc/testsuite/gcc.dg/attr-unavailable-6.c     |  11 ++
> .../attributes/method-unavailable-1.mm        |  34 ++++++
> .../attributes/method-unavailable-2.mm        |  24 ++++
> .../attributes/method-unavailable-3.mm        |  22 ++++
> .../property/at-property-unavailable-1.mm     |  38 ++++++
> .../property/at-property-unavailable-2.mm     |  26 ++++
> .../property/dotsyntax-unavailable-1.mm       |  42 +++++++
> .../objc.dg/attributes/method-unavailable-1.m |  34 ++++++
> .../objc.dg/attributes/method-unavailable-2.m |  24 ++++
> .../objc.dg/attributes/method-unavailable-3.m |  22 ++++
> .../property/at-property-unavailable-1.m      |  38 ++++++
> .../property/at-property-unavailable-2.m      |  26 ++++
> .../property/dotsyntax-unavailable-1.m        |  42 +++++++
> gcc/tree-core.h                               |  10 +-
> gcc/tree.c                                    |  72 +++++++++++
> gcc/tree.h                                    |   6 +
> 46 files changed, 1347 insertions(+), 64 deletions(-)
> create mode 100644 gcc/testsuite/g++.dg/ext/attr-unavailable-1.C
> create mode 100644 gcc/testsuite/g++.dg/ext/attr-unavailable-2.C
> create mode 100644 gcc/testsuite/g++.dg/ext/attr-unavailable-3.C
> create mode 100644 gcc/testsuite/g++.dg/ext/attr-unavailable-4.C
> create mode 100644 gcc/testsuite/g++.dg/ext/attr-unavailable-5.C
> create mode 100644 gcc/testsuite/g++.dg/ext/attr-unavailable-6.C
> create mode 100644 gcc/testsuite/g++.dg/ext/attr-unavailable-7.C
> create mode 100644 gcc/testsuite/g++.dg/ext/attr-unavailable-8.C
> create mode 100644 gcc/testsuite/g++.dg/ext/attr-unavailable-9.C
> create mode 100644 gcc/testsuite/gcc.dg/attr-unavailable-1.c
> create mode 100644 gcc/testsuite/gcc.dg/attr-unavailable-2.c
> create mode 100644 gcc/testsuite/gcc.dg/attr-unavailable-3.c
> create mode 100644 gcc/testsuite/gcc.dg/attr-unavailable-4.c
> create mode 100644 gcc/testsuite/gcc.dg/attr-unavailable-5.c
> create mode 100644 gcc/testsuite/gcc.dg/attr-unavailable-6.c
> create mode 100644  
> gcc/testsuite/obj-c++.dg/attributes/method-unavailable-1.mm
> create mode 100644  
> gcc/testsuite/obj-c++.dg/attributes/method-unavailable-2.mm
> create mode 100644  
> gcc/testsuite/obj-c++.dg/attributes/method-unavailable-3.mm
> create mode 100644  
> gcc/testsuite/obj-c++.dg/property/at-property-unavailable-1.mm
> create mode 100644  
> gcc/testsuite/obj-c++.dg/property/at-property-unavailable-2.mm
> create mode 100644  
> gcc/testsuite/obj-c++.dg/property/dotsyntax-unavailable-1.mm
> create mode 100644 gcc/testsuite/objc.dg/attributes/method-unavailable-1.m
> create mode 100644 gcc/testsuite/objc.dg/attributes/method-unavailable-2.m
> create mode 100644 gcc/testsuite/objc.dg/attributes/method-unavailable-3.m
> create mode 100644  
> gcc/testsuite/objc.dg/property/at-property-unavailable-1.m
> create mode 100644  
> gcc/testsuite/objc.dg/property/at-property-unavailable-2.m
> create mode 100644 gcc/testsuite/objc.dg/property/dotsyntax-unavailable-1.m
>
> diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
> index f1680820ecd..067dfabe0a4 100644
> --- a/gcc/c-family/c-attribs.c
> +++ b/gcc/c-family/c-attribs.c
> @@ -120,6 +120,8 @@ static tree handle_pure_attribute (tree *, tree,  
> tree, int, bool *);
> static tree handle_tm_attribute (tree *, tree, tree, int, bool *);
> static tree handle_tm_wrap_attribute (tree *, tree, tree, int, bool *);
> static tree handle_novops_attribute (tree *, tree, tree, int, bool *);
> +static tree handle_unavailable_attribute (tree *, tree, tree, int,
> +					  bool *);
> static tree handle_vector_size_attribute (tree *, tree, tree, int,
> 					  bool *) ATTRIBUTE_NONNULL(3);
> static tree handle_nonnull_attribute (tree *, tree, tree, int, bool *);
> @@ -391,6 +393,8 @@ const struct attribute_spec  
> c_common_attribute_table[] =
> 			      handle_novops_attribute, NULL },
>   { "deprecated",             0, 1, false, false, false, false,
> 			      handle_deprecated_attribute, NULL },
> +  { "unavailable",            0, 1, false, false, false, false,
> +			      handle_unavailable_attribute, NULL },
>   { "vector_size",	      1, 1, false, true, false, true,
> 			      handle_vector_size_attribute, NULL },
>   { "visibility",	      1, 1, false, false, false, false,
> @@ -3737,6 +3741,71 @@ handle_deprecated_attribute (tree *node, tree name,
>   return NULL_TREE;
> }
>
> +/* Handle a "unavailable" attribute; arguments as in
> +   struct attribute_spec.handler.  */
> +
> +static tree
> +handle_unavailable_attribute (tree *node, tree name,
> +			     tree args, int flags,
> +			     bool *no_add_attrs)
> +{
> +  tree type = NULL_TREE;
> +  int warn = 0;
> +  tree what = NULL_TREE;
> +
> +  if (!args)
> +    *no_add_attrs = true;
> +  else if (TREE_CODE (TREE_VALUE (args)) != STRING_CST)
> +    {
> +      error ("the message attached to %<unavailable%> is not a string");
> +      *no_add_attrs = true;
> +    }
> +
> +  if (DECL_P (*node))
> +    {
> +      tree decl = *node;
> +      type = TREE_TYPE (decl);
> +
> +      if (TREE_CODE (decl) == TYPE_DECL
> +	  || TREE_CODE (decl) == PARM_DECL
> +	  || VAR_OR_FUNCTION_DECL_P (decl)
> +	  || TREE_CODE (decl) == FIELD_DECL
> +	  || TREE_CODE (decl) == CONST_DECL
> +	  || objc_method_decl (TREE_CODE (decl)))
> +	TREE_UNAVAILABLE (decl) = 1;
> +      else
> +	warn = 1;
> +    }
> +  else if (TYPE_P (*node))
> +    {
> +      if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
> +	*node = build_variant_type_copy (*node);
> +      TREE_UNAVAILABLE (*node) = 1;
> +      type = *node;
> +    }
> +  else
> +    warn = 1;
> +
> +  if (warn)
> +    {
> +      *no_add_attrs = true;
> +      if (type && TYPE_NAME (type))
> +	{
> +	  if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
> +	    what = TYPE_NAME (*node);
> +	  else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
> +		   && DECL_NAME (TYPE_NAME (type)))
> +	    what = DECL_NAME (TYPE_NAME (type));
> +	}
> +      if (what)
> +	warning (OPT_Wattributes, "%qE attribute ignored for %qE", name, what);
> +      else
> +	warning (OPT_Wattributes, "%qE attribute ignored", name);
> +    }
> +
> +  return NULL_TREE;
> +}
> +
> /* Return the "base" type from TYPE that is suitable to apply attribute
>    vector_size to by stripping arrays, function types, etc.  */
> static tree
> diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
> index f19c82c81dd..27c6f13e8f2 100644
> --- a/gcc/c/c-decl.c
> +++ b/gcc/c/c-decl.c
> @@ -70,13 +70,16 @@ enum decl_context
>   TYPENAME};			/* Typename (inside cast or sizeof)  */
>
> /* States indicating how grokdeclarator() should handle declspecs marked
> -   with __attribute__((deprecated)).  An object declared as
> -   __attribute__((deprecated)) suppresses warnings of uses of other
> -   deprecated items.  */
> +   with __attribute__((deprecated)) or __attribute__((unavailable)).
> +   An object declared as __attribute__((unavailable)) should suppress
> +   any reports of being declared  with unavailable or deprecated items.
> +   An object declared as __attribute__((deprecated)) should suppress
> +   warnings of uses of other deprecated items.  */
>
> enum deprecated_states {
>   DEPRECATED_NORMAL,
> -  DEPRECATED_SUPPRESS
> +  DEPRECATED_SUPPRESS,
> +  UNAVAILABLE_DEPRECATED_SUPPRESS
> };
>
>
> @@ -2630,6 +2633,10 @@ merge_decls (tree newdecl, tree olddecl, tree  
> newtype, tree oldtype)
>   if (TREE_DEPRECATED (newdecl))
>     TREE_DEPRECATED (olddecl) = 1;
>
> +  /* Merge unavailability.  */
> +  if (TREE_UNAVAILABLE (newdecl))
> +    TREE_UNAVAILABLE (olddecl) = 1;
> +
>   /* If a decl is in a system header and the other isn't, keep the one on the
>      system header. Otherwise, keep source location of definition rather than
>      declaration and of prototype rather than non-prototype unless that
> @@ -4868,6 +4875,7 @@ quals_from_declspecs (const struct c_declspecs  
> *specs)
> 	      && !specs->typedef_p
> 	      && !specs->explicit_signed_p
> 	      && !specs->deprecated_p
> +	      && !specs->unavailable_p
> 	      && !specs->long_p
> 	      && !specs->long_long_p
> 	      && !specs->short_p
> @@ -5070,9 +5078,14 @@ start_decl (struct c_declarator *declarator,  
> struct c_declspecs *declspecs,
>   tree expr = NULL_TREE;
>   enum deprecated_states deprecated_state = DEPRECATED_NORMAL;
>
> -  /* An object declared as __attribute__((deprecated)) suppresses
> +  /* An object declared as __attribute__((unavailable)) suppresses
> +     warnings and errors from __attribute__((deprecated/unavailable))
> +     components.
> +     An object declared as __attribute__((deprecated)) suppresses
>      warnings of uses of other deprecated items.  */
> -  if (lookup_attribute ("deprecated", attributes))
> +  if (lookup_attribute ("unavailable", attributes))
> +    deprecated_state = UNAVAILABLE_DEPRECATED_SUPPRESS;
> +  else if (lookup_attribute ("deprecated", attributes))
>     deprecated_state = DEPRECATED_SUPPRESS;
>
>   decl = grokdeclarator (declarator, declspecs,
> @@ -6190,7 +6203,7 @@ smallest_type_quals_location (const location_t  
> *locations,
>      set to indicate whether operands in *EXPR can be used in constant
>      expressions.
>    DEPRECATED_STATE is a deprecated_states value indicating whether
> -   deprecation warnings should be suppressed.
> +   deprecation/unavailability warnings should be suppressed.
>
>    In the TYPENAME case, DECLARATOR is really an absolute declarator.
>    It may also be so in the PARM case, for a prototype where the
> @@ -6320,8 +6333,14 @@ grokdeclarator (const struct c_declarator  
> *declarator,
>   if (decl_context == NORMAL && !funcdef_flag && current_scope->parm_flag)
>     decl_context = PARM;
>
> -  if (declspecs->deprecated_p && deprecated_state != DEPRECATED_SUPPRESS)
> -    warn_deprecated_use (declspecs->type, declspecs->decl_attr);
> +  if (deprecated_state != UNAVAILABLE_DEPRECATED_SUPPRESS)
> +    {
> +      if (declspecs->unavailable_p)
> +	error_unavailable_use (declspecs->type, declspecs->decl_attr);
> +      else if (declspecs->deprecated_p
> +		&& deprecated_state != DEPRECATED_SUPPRESS)
> +	warn_deprecated_use (declspecs->type, declspecs->decl_attr);
> +    }
>
>   if ((decl_context == NORMAL || decl_context == FIELD)
>       && current_scope == file_scope
> @@ -10753,6 +10772,8 @@ declspecs_add_type (location_t loc, struct  
> c_declspecs *specs,
>   specs->typespec_kind = spec.kind;
>   if (TREE_DEPRECATED (type))
>     specs->deprecated_p = true;
> +  if (TREE_UNAVAILABLE (type))
> +    specs->unavailable_p = true;
>
>   /* Handle type specifier keywords.  */
>   if (TREE_CODE (type) == IDENTIFIER_NODE
> diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
> index 1f783db7dbc..292874cc317 100644
> --- a/gcc/c/c-tree.h
> +++ b/gcc/c/c-tree.h
> @@ -370,6 +370,8 @@ struct c_declspecs {
>   BOOL_BITFIELD explicit_signed_p : 1;
>   /* Whether the specifiers include a deprecated typedef.  */
>   BOOL_BITFIELD deprecated_p : 1;
> +  /* Whether the specifiers include an unavailable typedef.  */
> +  BOOL_BITFIELD unavailable_p : 1;
>   /* Whether the type defaulted to "int" because there were no type
>      specifiers.  */
>   BOOL_BITFIELD default_int_p : 1;
> diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
> index 96840377d90..16b6f776214 100644
> --- a/gcc/c/c-typeck.c
> +++ b/gcc/c/c-typeck.c
> @@ -2504,7 +2504,9 @@ build_component_ref (location_t loc, tree datum,  
> tree component,
> 	      || (use_datum_quals && TREE_THIS_VOLATILE (datum)))
> 	    TREE_THIS_VOLATILE (ref) = 1;
>
> -	  if (TREE_DEPRECATED (subdatum))
> +	  if (TREE_UNAVAILABLE (subdatum))
> +	    error_unavailable_use (subdatum, NULL_TREE);
> +	  else if (TREE_DEPRECATED (subdatum))
> 	    warn_deprecated_use (subdatum, NULL_TREE);
>
> 	  datum = ref;
> @@ -2789,7 +2791,9 @@ build_external_ref (location_t loc, tree id, bool  
> fun, tree *type)
>   if (TREE_TYPE (ref) == error_mark_node)
>     return error_mark_node;
>
> -  if (TREE_DEPRECATED (ref))
> +  if (TREE_UNAVAILABLE (ref))
> +    error_unavailable_use (ref, NULL_TREE);
> +  else if (TREE_DEPRECATED (ref))
>     warn_deprecated_use (ref, NULL_TREE);
>
>   /* Recursive call does not count as usage.  */
> diff --git a/gcc/cp/call.c b/gcc/cp/call.c
> index 9861be1f856..3df6c48e237 100644
> --- a/gcc/cp/call.c
> +++ b/gcc/cp/call.c
> @@ -9078,7 +9078,7 @@ build_over_call (struct z_candidate *cand, int  
> flags, tsubst_flags_t complain)
> 	  already_used = true;
> 	}
>       else
> -	cp_warn_deprecated_use (fn, complain);
> +	cp_handle_deprecated_or_unavailable (fn, complain);
>
>       /* If we're creating a temp and we already have one, don't create a
> 	 new one.  If we're not creating a temp but we get one, use
> @@ -9148,7 +9148,7 @@ build_over_call (struct z_candidate *cand, int  
> flags, tsubst_flags_t complain)
>           TREE_NO_WARNING (val) = 1;
> 	}
>
> -      cp_warn_deprecated_use (fn, complain);
> +      cp_handle_deprecated_or_unavailable (fn, complain);
>
>       return val;
>     }
> diff --git a/gcc/cp/class.c b/gcc/cp/class.c
> index c03737294eb..f594d473325 100644
> --- a/gcc/cp/class.c
> +++ b/gcc/cp/class.c
> @@ -5678,6 +5678,7 @@ type_build_ctor_call (tree t)
>       tree fn = *iter;
>       if (!DECL_ARTIFICIAL (fn)
> 	  || TREE_DEPRECATED (fn)
> +	  || TREE_UNAVAILABLE (fn)
> 	  || DECL_DELETED_FN (fn))
> 	return true;
>     }
> @@ -5706,6 +5707,7 @@ type_build_dtor_call (tree t)
>       tree fn = *iter;
>       if (!DECL_ARTIFICIAL (fn)
> 	  || TREE_DEPRECATED (fn)
> +	  || TREE_UNAVAILABLE (fn)
> 	  || DECL_DELETED_FN (fn))
> 	return true;
>     }
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 052291c40fe..7912cf511ed 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -6303,7 +6303,7 @@ extern bool is_list_ctor			(tree);
> extern void validate_conversion_obstack		(void);
> extern void mark_versions_used			(tree);
> extern bool unsafe_return_slot_p		(tree);
> -extern bool cp_warn_deprecated_use		(tree, tsubst_flags_t =  
> tf_warning_or_error);
> +extern bool cp_handle_deprecated_or_unavailable (tree, tsubst_flags_t =  
> tf_warning_or_error);
> extern void cp_warn_deprecated_use_scopes	(tree);
> extern tree get_function_version_dispatcher	(tree);
>
> diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
> index 62648841ac3..bdd290f6d02 100644
> --- a/gcc/cp/decl.c
> +++ b/gcc/cp/decl.c
> @@ -2350,6 +2350,10 @@ duplicate_decls (tree newdecl, tree olddecl, bool  
> hiding, bool was_hidden)
>       if (TREE_DEPRECATED (newdecl))
> 	TREE_DEPRECATED (olddecl) = 1;
>
> +      /* Merge unavailability.  */
> +      if (TREE_UNAVAILABLE (newdecl))
> +	TREE_UNAVAILABLE (olddecl) = 1;
> +
>       /* Preserve function specific target and optimization options */
>       if (TREE_CODE (newdecl) == FUNCTION_DECL)
> 	{
> @@ -11398,20 +11402,24 @@ grokdeclarator (const cp_declarator *declarator,
>   if (attrlist && *attrlist == error_mark_node)
>     *attrlist = NULL_TREE;
>
> -  /* An object declared as __attribute__((deprecated)) suppresses
> -     warnings of uses of other deprecated items.  */
> +  /* An object declared as __attribute__((unavailable)) suppresses
> +     any reports of being declared with unavailable or deprecated
> +     items.  An object declared as __attribute__((deprecated))
> +     suppresses warnings of uses of other deprecated items.  */
>   temp_override<deprecated_states> ds (deprecated_state);
> -  if (attrlist && lookup_attribute ("deprecated", *attrlist))
> +  if (attrlist && lookup_attribute ("unavailable", *attrlist))
> +    deprecated_state = UNAVAILABLE_DEPRECATED_SUPPRESS;
> +  else if (attrlist && lookup_attribute ("deprecated", *attrlist))
>     deprecated_state = DEPRECATED_SUPPRESS;
>
> -  cp_warn_deprecated_use (type);
> +  cp_handle_deprecated_or_unavailable (type);
>   if (type && TREE_CODE (type) == TYPE_DECL)
>     {
>       cp_warn_deprecated_use_scopes (CP_DECL_CONTEXT (type));
>       typedef_decl = type;
>       type = TREE_TYPE (typedef_decl);
>       if (DECL_ARTIFICIAL (typedef_decl))
> -	cp_warn_deprecated_use (type);
> +	cp_handle_deprecated_or_unavailable (type);
>     }
>   /* No type at all: default to `int', and set DEFAULTED_INT
>      because it was not a user-defined typedef.  */
> @@ -14027,6 +14035,43 @@ type_is_deprecated (tree type)
>   return NULL_TREE;
> }
>
> +/* Returns an unavailable type used within TYPE, or NULL_TREE if none.  */
> +
> +static tree
> +type_is_unavailable (tree type)
> +{
> +  enum tree_code code;
> +  if (TREE_UNAVAILABLE (type))
> +    return type;
> +  if (TYPE_NAME (type))
> +    {
> +      if (TREE_UNAVAILABLE (TYPE_NAME (type)))
> +	return type;
> +      else
> +	{
> +	  cp_warn_deprecated_use_scopes (CP_DECL_CONTEXT (TYPE_NAME (type)));
> +	  return NULL_TREE;
> +	}
> +    }
> +
> +  /* Do warn about using typedefs to a deprecated class.  */
> +  if (OVERLOAD_TYPE_P (type) && type != TYPE_MAIN_VARIANT (type))
> +    return type_is_deprecated (TYPE_MAIN_VARIANT (type));
> +
> +  code = TREE_CODE (type);
> +
> +  if (code == POINTER_TYPE || code == REFERENCE_TYPE
> +      || code == OFFSET_TYPE || code == FUNCTION_TYPE
> +      || code == METHOD_TYPE || code == ARRAY_TYPE)
> +    return type_is_unavailable (TREE_TYPE (type));
> +
> +  if (TYPE_PTRMEMFUNC_P (type))
> +    return type_is_unavailable
> +      (TREE_TYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (type))));
> +
> +  return NULL_TREE;
> +}
> +
> /* Decode the list of parameter types for a function type.
>    Given the list of things declared inside the parens,
>    return a list of types.
> @@ -14086,11 +14131,18 @@ grokparms (tree parmlist, tree *parms)
>
>       if (type != error_mark_node)
> 	{
> -	  if (deprecated_state != DEPRECATED_SUPPRESS)
> +	  if (deprecated_state != UNAVAILABLE_DEPRECATED_SUPPRESS)
> +	    {
> +	      tree unavailtype = type_is_unavailable (type);
> +	      if (unavailtype)
> +		cp_handle_deprecated_or_unavailable (unavailtype);
> +	    }
> +	  if (deprecated_state != DEPRECATED_SUPPRESS
> +	      && deprecated_state != UNAVAILABLE_DEPRECATED_SUPPRESS)
> 	    {
> 	      tree deptype = type_is_deprecated (type);
> 	      if (deptype)
> -		cp_warn_deprecated_use (deptype);
> +		cp_handle_deprecated_or_unavailable (deptype);
> 	    }
>
> 	  /* [dcl.fct] "A parameter with volatile-qualified type is
> diff --git a/gcc/cp/decl.h b/gcc/cp/decl.h
> index 3252dd8a011..475a00d8a2f 100644
> --- a/gcc/cp/decl.h
> +++ b/gcc/cp/decl.h
> @@ -44,7 +44,8 @@ extern void name_unnamed_type (tree, tree);
>
> enum deprecated_states {
>   DEPRECATED_NORMAL,
> -  DEPRECATED_SUPPRESS
> +  DEPRECATED_SUPPRESS,
> +  UNAVAILABLE_DEPRECATED_SUPPRESS
> };
>
> extern enum deprecated_states deprecated_state;
> diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
> index 1bc7b7e0197..590f8a3c157 100644
> --- a/gcc/cp/decl2.c
> +++ b/gcc/cp/decl2.c
> @@ -1608,6 +1608,17 @@ cplus_decl_attributes (tree *decl, tree  
> attributes, int flags)
> 	if (*decl == pattern)
> 	  TREE_DEPRECATED (tmpl) = true;
>       }
> +
> +  /* Likewise, propagate unavailability out to the template.  */
> +  if (TREE_UNAVAILABLE (*decl))
> +    if (tree ti = get_template_info (*decl))
> +      {
> +	tree tmpl = TI_TEMPLATE (ti);
> +	tree pattern = (TYPE_P (*decl) ? TREE_TYPE (tmpl)
> +			: DECL_TEMPLATE_RESULT (tmpl));
> +	if (*decl == pattern)
> +	  TREE_UNAVAILABLE (tmpl) = true;
> +      }
> }
>
> /* Walks through the namespace- or function-scope anonymous union
> @@ -5389,14 +5400,47 @@ maybe_instantiate_decl (tree decl)
>     }
> }
>
> -/* Maybe warn if DECL is deprecated, subject to COMPLAIN.  Returns  
> whether or
> -   not a warning was emitted.  */
> +/* Error if the DECL is unavailable (unless this is currently suppressed).
> +   Maybe warn if DECL is deprecated, subject to COMPLAIN.  Returns true if
> +   an error or warning was emitted.  */
>
> bool
> -cp_warn_deprecated_use (tree decl, tsubst_flags_t complain)
> +cp_handle_deprecated_or_unavailable (tree decl, tsubst_flags_t complain)
> {
> -  if (!(complain & tf_warning) || !decl
> -      || deprecated_state == DEPRECATED_SUPPRESS)
> +  if (!decl)
> +    return false;
> +
> +  if ((complain & tf_error)
> +      && deprecated_state != UNAVAILABLE_DEPRECATED_SUPPRESS)
> +    {
> +      if (TREE_UNAVAILABLE (decl))
> +	{
> +	  error_unavailable_use (decl, NULL_TREE);
> +	  return true;
> +	}
> +      else
> +	{
> +	  /* Perhaps this is an unavailable typedef.  */
> +	  if (TYPE_P (decl)
> +	      && TYPE_NAME (decl)
> +	      && TREE_UNAVAILABLE (TYPE_NAME (decl)))
> +	    {
> +	      decl = TYPE_NAME (decl);
> +	      /* Don't error within members of a unavailable type.  */
> +	      if (TYPE_P (decl)
> +		  && currently_open_class (decl))
> +		return false;
> +
> +	      error_unavailable_use (decl, NULL_TREE);
> +	      return true;
> +	    }
> +	}
> +      /* Carry on to consider deprecatedness.  */
> +    }
> +
> +  if (!(complain & tf_warning)
> +      || deprecated_state == DEPRECATED_SUPPRESS
> +      || deprecated_state == UNAVAILABLE_DEPRECATED_SUPPRESS)
>     return false;
>
>   if (!TREE_DEPRECATED (decl))
> @@ -5455,7 +5499,7 @@ cp_warn_deprecated_use_scopes (tree scope)
> 	 && scope != error_mark_node
> 	 && scope != global_namespace)
>     {
> -      if (cp_warn_deprecated_use (scope))
> +      if (cp_handle_deprecated_or_unavailable (scope))
> 	return;
>       if (TYPE_P (scope))
> 	scope = CP_TYPE_CONTEXT (scope);
> @@ -5567,7 +5611,7 @@ mark_used (tree decl, tsubst_flags_t complain)
>       TREE_USED (decl) = true;
>     }
>
> -  cp_warn_deprecated_use (decl, complain);
> +  cp_handle_deprecated_or_unavailable (decl, complain);
>
>   /* We can only check DECL_ODR_USED on variables or functions with
>      DECL_LANG_SPECIFIC set, and these are also the only decls that we
> diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
> index 323d7424a83..00595c0365b 100644
> --- a/gcc/cp/parser.c
> +++ b/gcc/cp/parser.c
> @@ -17170,18 +17170,26 @@ cp_parser_template_name (cp_parser* parser,
>   /* If DECL is a template, then the name was a template-name.  */
>   if (TREE_CODE (decl) == TEMPLATE_DECL)
>     {
> -      if (TREE_DEPRECATED (decl)
> -	  && deprecated_state != DEPRECATED_SUPPRESS)
> +      if ((TREE_DEPRECATED (decl) || TREE_UNAVAILABLE (decl))
> +	  && deprecated_state != UNAVAILABLE_DEPRECATED_SUPPRESS)
> 	{
> 	  tree d = DECL_TEMPLATE_RESULT (decl);
> 	  tree attr;
> 	  if (TREE_CODE (d) == TYPE_DECL)
> -	    attr = lookup_attribute ("deprecated",
> -				     TYPE_ATTRIBUTES (TREE_TYPE (d)));
> +	    attr = TYPE_ATTRIBUTES (TREE_TYPE (d));
> 	  else
> -	    attr = lookup_attribute ("deprecated",
> -				     DECL_ATTRIBUTES (d));
> -	  warn_deprecated_use (decl, attr);
> +	    attr = DECL_ATTRIBUTES (d);
> +	  if (TREE_UNAVAILABLE (decl))
> +	    {
> +	      attr = lookup_attribute ("unavailable", attr);
> +	      error_unavailable_use (decl, attr);
> +	    }
> +	  else if (TREE_DEPRECATED (decl)
> +		   && deprecated_state != DEPRECATED_SUPPRESS)
> +	    {
> +	      attr = lookup_attribute ("deprecated", attr);
> +	      warn_deprecated_use (decl, attr);
> +	    }
> 	}
>     }
>   else
> @@ -17432,7 +17440,9 @@ cp_parser_template_argument (cp_parser* parser)
>     }
>   if (cp_parser_parse_definitely (parser))
>     {
> -      if (TREE_DEPRECATED (argument))
> +      if (TREE_UNAVAILABLE (argument))
> +	error_unavailable_use (argument, NULL_TREE);
> +      else if (TREE_DEPRECATED (argument))
> 	warn_deprecated_use (argument, NULL_TREE);
>       return argument;
>     }
> @@ -22930,9 +22940,9 @@ cp_parser_parameter_declaration_list (cp_parser*  
> parser, cp_parser_flags flags)
> 					   /*template_parm_p=*/false,
> 					   &parenthesized_p);
>
> -      /* We don't know yet if the enclosing context is deprecated, so wait
> -	 and warn in grokparms if appropriate.  */
> -      deprecated_state = DEPRECATED_SUPPRESS;
> +      /* We don't know yet if the enclosing context is unavailable or  
> deprecated,
> +	 so wait and deal with it in grokparms if appropriate.  */
> +      deprecated_state = UNAVAILABLE_DEPRECATED_SUPPRESS;
>
>       if (parameter)
> 	{
> diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
> index 08e0c80f9b0..7d1e2fd27a6 100644
> --- a/gcc/cp/typeck.c
> +++ b/gcc/cp/typeck.c
> @@ -2514,7 +2514,10 @@ build_class_member_access_expr (cp_expr object,  
> tree member,
>       member_scope = DECL_CLASS_CONTEXT (member);
>       if (!mark_used (member, complain) && !(complain & tf_error))
> 	return error_mark_node;
> -      if (TREE_DEPRECATED (member))
> +
> +      if (TREE_UNAVAILABLE (member))
> +	error_unavailable_use (member, NULL_TREE);
> +      else if (TREE_DEPRECATED (member))
> 	warn_deprecated_use (member, NULL_TREE);
>     }
>   else
> @@ -3217,7 +3220,9 @@ finish_class_member_access_expr (cp_expr object,  
> tree name, bool template_p,
> 	}
>     }
>
> -  if (TREE_DEPRECATED (member))
> +  if (TREE_UNAVAILABLE (member))
> +    error_unavailable_use (member, NULL_TREE);
> +  else if (TREE_DEPRECATED (member))
>     warn_deprecated_use (member, NULL_TREE);
>
>   if (template_p)
> diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
> index 445e2a211c8..4d014dac88f 100644
> --- a/gcc/cp/typeck2.c
> +++ b/gcc/cp/typeck2.c
> @@ -2293,7 +2293,7 @@ build_functional_cast_1 (location_t loc, tree exp,  
> tree parms,
>       type = TREE_TYPE (exp);
>
>       if (DECL_ARTIFICIAL (exp))
> -	cp_warn_deprecated_use (type);
> +	cp_handle_deprecated_or_unavailable (type);
>     }
>   else
>     type = exp;
> diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
> index 5f1e3bf8a2e..a6b5867808a 100644
> --- a/gcc/doc/extend.texi
> +++ b/gcc/doc/extend.texi
> @@ -2865,6 +2865,19 @@ types (@pxref{Variable Attributes}, @pxref{Type  
> Attributes}.)
> The message attached to the attribute is affected by the setting of
> the @option{-fmessage-length} option.
>
> +@item unavailable
> +@itemx unavailable (@var{msg})
> +@cindex @code{unavailable} function attribute
> +The @code{deprecated} attribute results in an error if the function
> +is used anywhere in the source file.  This is useful when identifying
> +functions that have been removed from a particular variation of an
> +interface.  Other than emitting an error rather than a warning, the
> +@code{unavailable} attribute behaves in the same manner as
> +@code{deprecated}.
> +
> +The @code{unavailable} attribute can also be used for variables and
> +types (@pxref{Variable Attributes}, @pxref{Type Attributes}.)
> +
> @item error ("@var{message}")
> @itemx warning ("@var{message}")
> @cindex @code{error} function attribute
> @@ -7223,6 +7236,22 @@ types (@pxref{Common Function Attributes},
> The message attached to the attribute is affected by the setting of
> the @option{-fmessage-length} option.
>
> +@item unavailable
> +@itemx unavailable (@var{msg})
> +@cindex @code{unavailable} variable attribute
> +The @code{unavailable} attribute indicates that the variable so marked
> +is not available, if it is used anywhere in the source file.  It behaves
> +in the same manner as the @code{deprecated} attribute except that the
> +compiler will emit an error rather than a warning.
> +
> +It is expected that items marked as @code{deprecated} will eventually be
> +withdrawn from interfaces, and then become unavailable.  This attribute
> +allows for marking them appropriately.
> +
> +The @code{unavailable} attribute can also be used for functions and
> +types (@pxref{Common Function Attributes},
> +@pxref{Common Type Attributes}).
> +
> @item mode (@var{mode})
> @cindex @code{mode} variable attribute
> This attribute specifies the data type for the declaration---whichever
> @@ -8249,6 +8278,17 @@ variables (@pxref{Function Attributes},  
> @pxref{Variable Attributes}.)
> The message attached to the attribute is affected by the setting of
> the @option{-fmessage-length} option.
>
> +@item unavailable
> +@itemx unavailable (@var{msg})
> +@cindex @code{unavailable} type attribute
> +The @code{unavailable} attribute behaves in the same manner as the
> +@code{deprecated} one, but emits an error rather than a warning.  It is
> +used to indicate that a (perhaps previously @code{deprecated}) type is
> +no longer usable.
> +
> +The @code{unavailable} attribute can also be used for functions and
> +variables (@pxref{Function Attributes}, @pxref{Variable Attributes}.)
> +
> @item designated_init
> @cindex @code{designated_init} type attribute
> This attribute may only be applied to structure types.  It indicates
> @@ -8716,6 +8756,12 @@ of the deprecated enumerator, to enable users to  
> easily find further
> information about why the enumerator is deprecated, or what they should
> do instead.  Note that the warnings only occurs for uses.
>
> +@item unavailable
> +@cindex @code{unavailable} enumerator attribute
> +The @code{unavailable} attribute results in an error if the enumerator
> +is used anywhere in the source file.  In other respects it behaves in the
> +same manner as the @code{deprecated} attribute.
> +
> @end table
>
> @node Statement Attributes
> diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c
> index b9ed32d51d0..fc247220a62 100644
> --- a/gcc/objc/objc-act.c
> +++ b/gcc/objc/objc-act.c
> @@ -1275,6 +1275,7 @@ objc_add_property_declaration (location_t location,  
> tree decl,
>   TREE_TYPE (property_decl) = TREE_TYPE (decl);
>   DECL_SOURCE_LOCATION (property_decl) = DECL_SOURCE_LOCATION (decl);
>   TREE_DEPRECATED (property_decl) = TREE_DEPRECATED (decl);
> +  TREE_UNAVAILABLE (property_decl) = TREE_UNAVAILABLE (decl);
>
>   /* Add property-specific information.  */
>   PROPERTY_NAME (property_decl) = DECL_NAME (decl);
> @@ -1390,6 +1391,7 @@ maybe_make_artificial_property_decl (tree  
> interface, tree implementation,
>       TREE_TYPE (property_decl) = type;
>       DECL_SOURCE_LOCATION (property_decl) = input_location;
>       TREE_DEPRECATED (property_decl) = 0;
> +      TREE_UNAVAILABLE (property_decl) = 0;
>       DECL_ARTIFICIAL (property_decl) = 1;
>
>       /* Add property-specific information.  Note that one of
> @@ -1668,7 +1670,7 @@ objc_maybe_build_component_ref (tree object, tree  
> property_ident)
>     {
>       tree expression;
>       tree getter_call;
> -      tree deprecated_method_prototype = NULL_TREE;
> +      tree method_prototype_avail = NULL_TREE;
>
>       /* We have an additional nasty problem here; if this
> 	 PROPERTY_REF needs to become a 'getter', then the conversion
> @@ -1702,10 +1704,10 @@ objc_maybe_build_component_ref (tree object, tree  
> property_ident)
> 	      is deprecated, but record the fact that the getter is
> 	      deprecated by setting PROPERTY_REF_DEPRECATED_GETTER to
> 	      the method prototype.  */
> -	   &deprecated_method_prototype);
> +	   &method_prototype_avail);
>
>       expression = build4 (PROPERTY_REF, TREE_TYPE(x), object, x, getter_call,
> -			   deprecated_method_prototype);
> +			   method_prototype_avail);
>       SET_EXPR_LOCATION (expression, input_location);
>       TREE_SIDE_EFFECTS (expression) = 1;
>
> @@ -1755,7 +1757,9 @@ objc_build_class_component_ref (tree class_name,  
> tree property_ident)
>     }
>   else
>     {
> -      if (TREE_DEPRECATED (rtype))
> +      if (TREE_UNAVAILABLE (rtype))
> +	error ("class %qE is unavailable", class_name);
> +      else if (TREE_DEPRECATED (rtype))
> 	warning (OPT_Wdeprecated_declarations, "class %qE is deprecated", class_name);
>     }
>
> @@ -1767,17 +1771,17 @@ objc_build_class_component_ref (tree class_name,  
> tree property_ident)
>     {
>       tree expression;
>       tree getter_call;
> -      tree deprecated_method_prototype = NULL_TREE;
> +      tree method_prototype_avail = NULL_TREE;
>
>       if (PROPERTY_HAS_NO_GETTER (x))
> 	getter_call = NULL_TREE;
>       else
> 	getter_call = objc_finish_message_expr
> 	  (object, PROPERTY_GETTER_NAME (x), NULL_TREE,
> -	   &deprecated_method_prototype);
> +	   &method_prototype_avail);
>
>       expression = build4 (PROPERTY_REF, TREE_TYPE(x), object, x, getter_call,
> -			   deprecated_method_prototype);
> +			   method_prototype_avail);
>       SET_EXPR_LOCATION (expression, input_location);
>       TREE_SIDE_EFFECTS (expression) = 1;
>
> @@ -4548,6 +4552,8 @@ build_private_template (tree klass)
>       /* Copy the attributes from the class to the type.  */
>       if (TREE_DEPRECATED (klass))
> 	TREE_DEPRECATED (record) = 1;
> +      if (TREE_UNAVAILABLE (klass))
> +	TREE_UNAVAILABLE (record) = 1;
>     }
> }
>
> @@ -4973,6 +4979,7 @@ objc_decl_method_attributes (tree *node, tree  
> attributes, int flags)
> 	  tree name = TREE_PURPOSE (attribute);
>
> 	  if (is_attribute_p  ("deprecated", name)
> +	      || is_attribute_p ("unavailable", name)
> 	      || is_attribute_p ("sentinel", name)
> 	      || is_attribute_p ("noreturn", name))
> 	    {
> @@ -5438,9 +5445,9 @@ lookup_method_in_hash_lists (tree sel_name, int  
> is_class)
>    C++ template functions, it is called from 'build_expr_from_tree'
>    (in decl2.c) after RECEIVER and METHOD_PARAMS have been expanded.
>
> -   If the DEPRECATED_METHOD_PROTOTYPE argument is NULL, then we warn
> +   If the method_prototype_avail argument is NULL, then we warn
>    if the method being used is deprecated.  If it is not NULL, instead
> -   of deprecating, we set *DEPRECATED_METHOD_PROTOTYPE to the method
> +   of deprecating, we set *method_prototype_avail to the method
>    prototype that was used and is deprecated.  This is useful for
>    getter calls that are always generated when compiling dot-syntax
>    expressions, even if they may not be used.  In that case, we don't
> @@ -5449,7 +5456,7 @@ lookup_method_in_hash_lists (tree sel_name, int  
> is_class)
>    used.  */
> tree
> objc_finish_message_expr (tree receiver, tree sel_name, tree method_params,
> -			  tree *deprecated_method_prototype)
> +			  tree *method_prototype_avail)
> {
>   tree method_prototype = NULL_TREE, rprotos = NULL_TREE, rtype;
>   tree retval, class_tree;
> @@ -5761,10 +5768,17 @@ objc_finish_message_expr (tree receiver, tree  
> sel_name, tree method_params,
> 	 In practice this makes sense since casting an object to 'id'
> 	 is often used precisely to turn off warnings associated with
> 	 the object being of a particular class.  */
> -      if (TREE_DEPRECATED (method_prototype) && rtype != NULL_TREE)
> +      if (TREE_UNAVAILABLE (method_prototype) && rtype != NULL_TREE)
> 	{
> -	  if (deprecated_method_prototype)
> -	    *deprecated_method_prototype = method_prototype;
> +	  if (method_prototype_avail)
> +	    *method_prototype_avail = method_prototype;
> +	  else
> +	    error_unavailable_use (method_prototype, NULL_TREE);
> +	}
> +      else if (TREE_DEPRECATED (method_prototype) && rtype != NULL_TREE)
> +	{
> +	  if (method_prototype_avail)
> +	    *method_prototype_avail = method_prototype;
> 	  else
> 	    warn_deprecated_use (method_prototype, NULL_TREE);
> 	}
> @@ -6936,7 +6950,9 @@ start_class (enum tree_code code, tree class_name,  
> tree super_name,
> 	}
>       else
> 	{
> -	  if (TREE_DEPRECATED (super_interface))
> +	  if (TREE_UNAVAILABLE (super_interface))
> +	    error ("class %qE is not available", super);
> +	  else if (TREE_DEPRECATED (super_interface))
> 	    warning (OPT_Wdeprecated_declarations, "class %qE is deprecated",
> 		     super);
> 	  super_name = super;
> @@ -7040,7 +7056,9 @@ start_class (enum tree_code code, tree class_name,  
> tree super_name,
> 	      /* TODO: Document what the objc_exception attribute is/does.  */
> 	      /* We handle the 'deprecated', 'visibility' and (undocumented)
> 		 'objc_exception' attributes.  */
> -	      if (is_attribute_p  ("deprecated", name))
> +	      if (is_attribute_p  ("unavailable", name))
> +		TREE_UNAVAILABLE (klass) = 1;
> +	      else if (is_attribute_p  ("deprecated", name))
> 		TREE_DEPRECATED (klass) = 1;
> 	      else if (is_attribute_p  ("objc_exception", name))
> 		CLASS_HAS_EXCEPTION_ATTR (klass) = 1;
> @@ -7069,7 +7087,9 @@ start_class (enum tree_code code, tree class_name,  
> tree super_name,
> 	  }
> 	else
> 	  {
> -	    if (TREE_DEPRECATED (class_category_is_assoc_with))
> +	    if (TREE_UNAVAILABLE (class_category_is_assoc_with))
> +	      error ("class %qE is unavailable", class_name);
> +	    else if (TREE_DEPRECATED (class_category_is_assoc_with))
> 	      warning (OPT_Wdeprecated_declarations, "class %qE is deprecated",
> 		       class_name);
>
> @@ -8096,6 +8116,7 @@ finish_class (tree klass)
> 		else
> 		  objc_add_method (objc_interface_context, getter_decl, false, false);
> 		TREE_DEPRECATED (getter_decl) = TREE_DEPRECATED (x);
> +		TREE_UNAVAILABLE (getter_decl) = TREE_UNAVAILABLE (x);
> 		METHOD_PROPERTY_CONTEXT (getter_decl) = x;
> 	      }
>
> @@ -8140,6 +8161,7 @@ finish_class (tree klass)
> 		    else
> 		      objc_add_method (objc_interface_context, setter_decl, false, false);
> 		    TREE_DEPRECATED (setter_decl) = TREE_DEPRECATED (x);
> +		    TREE_UNAVAILABLE (setter_decl) = TREE_UNAVAILABLE (x);
> 		    METHOD_PROPERTY_CONTEXT (setter_decl) = x;
> 		  }
> 	      }
> @@ -8193,7 +8215,9 @@ lookup_protocol (tree ident, bool  
> warn_if_deprecated, bool definition_required)
>   for (chain = protocol_chain; chain; chain = TREE_CHAIN (chain))
>     if (ident == PROTOCOL_NAME (chain))
>       {
> -	if (warn_if_deprecated && TREE_DEPRECATED (chain))
> +	if (TREE_UNAVAILABLE (chain))
> +	  error ("protocol %qE is unavailable", PROTOCOL_NAME (chain));
> +	else if (warn_if_deprecated && TREE_DEPRECATED (chain))
> 	  {
> 	    /* It would be nice to use warn_deprecated_use() here, but
> 	       we are using TREE_CHAIN (which is supposed to be the
> @@ -8218,6 +8242,7 @@ void
> objc_declare_protocol (tree name, tree attributes)
> {
>   bool deprecated = false;
> +  bool unavailable = false;
>
> #ifdef OBJCPLUS
>   if (current_namespace != global_namespace) {
> @@ -8236,6 +8261,8 @@ objc_declare_protocol (tree name, tree attributes)
>
> 	  if (is_attribute_p  ("deprecated", name))
> 	    deprecated = true;
> +	  else if (is_attribute_p  ("unavailable", name))
> +	    unavailable = true;
> 	  else
> 	    warning (OPT_Wattributes, "%qE attribute directive ignored", name);
> 	}
> @@ -8260,6 +8287,8 @@ objc_declare_protocol (tree name, tree attributes)
> 	  TYPE_ATTRIBUTES (protocol) = attributes;
> 	  if (deprecated)
> 	    TREE_DEPRECATED (protocol) = 1;
> +	  if (unavailable)
> +	    TREE_UNAVAILABLE (protocol) = 1;
> 	}
>     }
> }
> @@ -8269,6 +8298,7 @@ start_protocol (enum tree_code code, tree name,  
> tree list, tree attributes)
> {
>   tree protocol;
>   bool deprecated = false;
> +  bool unavailable = false;
>
> #ifdef OBJCPLUS
>   if (current_namespace != global_namespace) {
> @@ -8287,6 +8317,8 @@ start_protocol (enum tree_code code, tree name,  
> tree list, tree attributes)
>
> 	  if (is_attribute_p  ("deprecated", name))
> 	    deprecated = true;
> +	  else if (is_attribute_p  ("unavailable", name))
> +	    unavailable = true;
> 	  else
> 	    warning (OPT_Wattributes, "%qE attribute directive ignored", name);
> 	}
> @@ -8326,6 +8358,8 @@ start_protocol (enum tree_code code, tree name,  
> tree list, tree attributes)
>       TYPE_ATTRIBUTES (protocol) = attributes;
>       if (deprecated)
> 	TREE_DEPRECATED (protocol) = 1;
> +      if (unavailable)
> +	TREE_UNAVAILABLE (protocol) = 1;
>     }
>
>   return protocol;
> @@ -8855,6 +8889,8 @@ really_start_method (tree method,
> 		 warnings are produced), but just in case.  */
> 	      if (TREE_DEPRECATED (proto))
> 		TREE_DEPRECATED (method) = 1;
> +	      if (TREE_UNAVAILABLE (proto))
> +		TREE_UNAVAILABLE (method) = 1;
>
> 	      /* If the method in the @interface was marked as
> 		 'noreturn', mark the function implementing the method
> @@ -9586,12 +9622,17 @@ objc_gimplify_property_ref (tree *expr_p)
>       return;
>     }
>
> +  /* FIXME, this should be a label indicating availability in general.  */
>   if (PROPERTY_REF_DEPRECATED_GETTER (*expr_p))
>     {
> -      /* PROPERTY_REF_DEPRECATED_GETTER contains the method prototype
> +      if (TREE_UNAVAILABLE (PROPERTY_REF_DEPRECATED_GETTER (*expr_p)))
> +	error_unavailable_use (PROPERTY_REF_DEPRECATED_GETTER (*expr_p),
> +			       NULL_TREE);
> +      else
> +	/* PROPERTY_REF_DEPRECATED_GETTER contains the method prototype
> 	 that is deprecated.  */
> -      warn_deprecated_use (PROPERTY_REF_DEPRECATED_GETTER (*expr_p),
> -			   NULL_TREE);
> +	warn_deprecated_use (PROPERTY_REF_DEPRECATED_GETTER (*expr_p),
> +			     NULL_TREE);
>     }
>
>   call_exp = getter;
> diff --git a/gcc/print-tree.c b/gcc/print-tree.c
> index 17c88f81770..1443d3f5c39 100644
> --- a/gcc/print-tree.c
> +++ b/gcc/print-tree.c
> @@ -364,6 +364,8 @@ print_node (FILE *file, const char *prefix, tree  
> node, int indent,
>     fputs (code == CALL_EXPR ? " must-tail-call" : " static", file);
>   if (TREE_DEPRECATED (node))
>     fputs (" deprecated", file);
> +  if (TREE_UNAVAILABLE (node))
> +    fputs (" unavailable", file);
>   if (TREE_VISITED (node))
>     fputs (" visited", file);
>
> diff --git a/gcc/testsuite/g++.dg/ext/attr-unavailable-1.C  
> b/gcc/testsuite/g++.dg/ext/attr-unavailable-1.C
> new file mode 100644
> index 00000000000..862651f6cbf
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/ext/attr-unavailable-1.C
> @@ -0,0 +1,113 @@
> +/* Test __attribute__ ((unavailable)) */
> +/* { dg-do compile } */
> +/* { dg-options "" } */
> +
> +typedef int INT1 __attribute__((unavailable));
> +typedef INT1 INT2 __attribute__ ((__unavailable__));
> +
> +typedef INT1 INT1a; 			/* { dg-error "'INT1' is unavailable" "" } */
> +typedef INT1 INT1b __attribute__ ((unavailable));
> +
> +INT1 should_be_unavailable; 		/* { dg-error "'INT1' is  
> unavailable" "" } */
> +INT1a should_not_be_unavailable;
> +
> +INT1 f1(void) __attribute__ ((unavailable));
> +INT1 f2(void) { return 0; }		/* { dg-error "'INT1' is unavailable" "" } */
> +
> +INT2 f3(void) __attribute__ ((__unavailable__));
> +INT2 f4(void) { return 0; }		/* { dg-error "'INT2' is unavailable" "" } */
> +int f5(INT2 x);				/* { dg-error "'INT2' is unavailable" "" } */
> +int f6(INT2 x) __attribute__ ((__unavailable__));
> +
> +typedef enum Color {red, green, blue} Color __attribute__((unavailable));
> +
> +int g1;
> +int g2 __attribute__ ((unavailable));
> +int g3 __attribute__ ((__unavailable__));
> +Color k;				/* { dg-error "'Color' is unavailable" "" } */
> +
> +typedef struct {
> +  int field1;
> +  int field2 __attribute__ ((unavailable));
> +  int field3;
> +  int field4 __attribute__ ((__unavailable__));
> +  union {
> +    int field5;
> +    int field6 __attribute__ ((unavailable));
> +  } u1;
> +  int field7:1;
> +  int field8:1 __attribute__ ((unavailable));
> +  union {
> +    int field9;
> +    int field10;
> +  } u2 __attribute__ ((unavailable));
> +} S1;
> +
> +int func1()
> +{
> +   INT1 w;				/* { dg-error "'INT1' is unavailable" "" } */
> +   int x __attribute__ ((unavailable));
> +   int y __attribute__ ((__unavailable__));
> +   int z;
> +   int (*pf)() = f1;			/* { dg-error "'INT1 f1\\(\\)' is  
> unavailable" "" } */
> +
> +   z = w + x + y + g1 + g2 + g3;	/* { dg-error "'x' is unavailable"  
> "" } */
> +					/* { dg-error "'y' is unavailable" "y" { target *-*-* } .-1 } */
> +					/* { dg-error "'g2' is unavailable" "g2" { target *-*-* } .-2 } */
> +					/* { dg-error "'g3' is unavailable" "g3" { target *-*-* } .-3 } */
> +   return f1(); 			/* { dg-error "'INT1 f1\\(\\)' is  
> unavailable" "f1" } */
> +}
> +
> +int func2(S1 *p)
> +{
> +  S1 lp;
> +
> +  if (p->field1)
> +     return p->field2;			/* { dg-error "'S1::field2'  
> is unavailable" "" } */
> +  else if (lp.field4)			/* { dg-error "'S1::field4'  
> is unavailable" "" } */
> +     return p->field3;
> +
> +  p->u1.field5 = g1 + p->field7;
> +  p->u2.field9;				/* { dg-error "'S1::u2' is unavailable" "" } */
> +  return p->u1.field6 + p->field8;	/* { dg-error "'S1::<unnamed  
> union>::field6' is unavailable" "" } */
> +					/* { dg-error "'S1::field8' is  
> unavailable" "field8" { target *-*-* } .-1 } */
> +}
> +
> +struct SS1 {
> +  int x;
> +  INT1 y; 				/* { dg-error "'INT1' is unavailable" "" } */
> +} __attribute__ ((unavailable));
> +
> +struct SS1 *p1;				/* { dg-error "'SS1' is unavailable" "" } */
> +
> +struct __attribute__ ((__unavailable__)) SS2 {
> +  int x;
> +  INT1 y; 				/* { dg-error "'INT1' is unavailable" "" } */
> +};
> +
> +struct SS2 *p2;				/* { dg-error "'SS2' is unavailable" "" } */
> +
> +#ifdef __cplusplus
> +class T {
> +  public:
> +    void member1(int) __attribute__ ((unavailable));
> +    void member2(INT1) __attribute__ ((__unavailable__));
> +    int member3(T *);
> +    int x;
> +} __attribute__ ((unavailable));
> +
> +T *p3;				// { dg-error "'T' is unavailable" }
> +
> +inline void T::member1(int) {}
> +
> +int T::member3(T *p)		// { dg-error "'T' is unavailable" }
> +{
> +  p->member1(1);			/* { dg-error "'void  
> T::member1\\(int\\)' is unavailable" "" } */
> +  (*p).member1(2);			/* { dg-error "'void  
> T::member1\\(int\\)' is unavailable" "" } */
> +  p->member2(1);			/* { dg-error "'void  
> T::member2\\(INT1\\)' is unavailable" "" } */
> +  (*p).member2(2);			/* { dg-error "'void  
> T::member2\\(INT1\\)' is unavailable" "" } */
> +  p->member3(p);
> +  (*p).member3(p);
> +  return f1(); 				/* { dg-error "'INT1 f1\\(\\)' is unavailable" "" } */
> +}
> +#endif
> diff --git a/gcc/testsuite/g++.dg/ext/attr-unavailable-2.C  
> b/gcc/testsuite/g++.dg/ext/attr-unavailable-2.C
> new file mode 100644
> index 00000000000..3de5532817e
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/ext/attr-unavailable-2.C
> @@ -0,0 +1,10 @@
> +/* Test __attribute__ ((unavailable)) */
> +/* { dg-do compile } */
> +/* { dg-options "" } */
> +
> +void func(void);
> +void func(void) __attribute__((unavailable));
> +
> +void f(void) {
> +  func(); /* { dg-error "'void func\\(\\)' is unavailable" } */
> +}
> diff --git a/gcc/testsuite/g++.dg/ext/attr-unavailable-3.C  
> b/gcc/testsuite/g++.dg/ext/attr-unavailable-3.C
> new file mode 100644
> index 00000000000..1f267ea78c4
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/ext/attr-unavailable-3.C
> @@ -0,0 +1,14 @@
> +/* Check operator with __attribute__((unavailable)) */
> +/* { dg-do compile } */
> +/* { dg-options "" } */
> +
> +struct Foo
> +{
> +  operator int() __attribute__((unavailable));
> +};
> +
> +void g(void)
> +{
> +  Foo f;
> +  (int)f; // { dg-error "'Foo::operator int\\(\\)' is unavailable" }
> +}
> diff --git a/gcc/testsuite/g++.dg/ext/attr-unavailable-4.C  
> b/gcc/testsuite/g++.dg/ext/attr-unavailable-4.C
> new file mode 100644
> index 00000000000..b7f352ee3bd
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/ext/attr-unavailable-4.C
> @@ -0,0 +1,11 @@
> +/* Test __attribute__ ((unavailable)) */
> +/* { dg-do compile } */
> +/* { dg-options "" } */
> +
> +struct B {
> +    virtual int foo() __attribute__((unavailable));
> +};
> +
> +int main(void) {
> +  ((B*)0)->foo(); 		// { dg-error "unavailable" }
> +}
> diff --git a/gcc/testsuite/g++.dg/ext/attr-unavailable-5.C  
> b/gcc/testsuite/g++.dg/ext/attr-unavailable-5.C
> new file mode 100644
> index 00000000000..3beea5d22c5
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/ext/attr-unavailable-5.C
> @@ -0,0 +1,6 @@
> +/* Test __attribute__ ((unavailable)) */
> +/* { dg-do compile } */
> +/* { dg-options "" } */
> +
> +struct Foo { int i; } __attribute__ ((unavailable));
> +void foo() { Foo f; }		// { dg-error "unavailable" }
> diff --git a/gcc/testsuite/g++.dg/ext/attr-unavailable-6.C  
> b/gcc/testsuite/g++.dg/ext/attr-unavailable-6.C
> new file mode 100644
> index 00000000000..8a57ea0d88c
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/ext/attr-unavailable-6.C
> @@ -0,0 +1,110 @@
> +/* Test __attribute__ ((unavailable)) */
> +/* { dg-do compile } */
> +/* { dg-options "" } */
> +
> +typedef int INT1 __attribute__((unavailable("You can't use INT1")));
> +typedef INT1 INT2 __attribute__ ((__unavailable__("You can't use INT2")));
> +
> +typedef INT1 INT1a; 			/* { dg-error "'INT1' is  
> unavailable: You can't use INT1" "" } */
> +
> +INT1 should_be_unavailable; 		/* { dg-error "'INT1' is  
> unavailable: You can't use INT1" "" } */
> +INT1a should_not_be_unavailable;
> +
> +INT1 f1(void) __attribute__ ((unavailable("You can't use f1")));
> +INT1 f2(void) { return 0; }		/* { dg-error "'INT1' is  
> unavailable: You can't use INT1" "" } */
> +
> +INT2 f3(void) __attribute__ ((__unavailable__("You can't use f3")));
> +INT2 f4(void) { return 0; }		/* { dg-error "'INT2' is  
> unavailable: You can't use INT2" "" } */
> +int f5(INT2 x);				/* { dg-error "'INT2' is unavailable" "" } */
> +int f6(INT2 x) __attribute__ ((__unavailable__("You can't use f6")));
> +
> +typedef enum Color {red, green, blue} Color  
> __attribute__((unavailable("You can't use Color")));
> +
> +int g1;
> +int g2 __attribute__ ((unavailable("You can't use g2")));
> +int g3 __attribute__ ((__unavailable__("You can't use g3")));
> +Color k;				/* { dg-error "'Color' is  
> unavailable: You can't use Color" "" } */
> +
> +typedef struct {
> +  int field1;
> +  int field2 __attribute__ ((unavailable("You can't use field2")));
> +  int field3;
> +  int field4 __attribute__ ((__unavailable__("You can't use field4")));
> +  union {
> +    int field5;
> +    int field6 __attribute__ ((unavailable("You can't use field6")));
> +  } u1;
> +  int field7:1;
> +  int field8:1 __attribute__ ((unavailable("You can't use field8")));
> +  union {
> +    int field9;
> +    int field10;
> +  } u2 __attribute__ ((unavailable("You can't use u2")));
> +} S1;
> +
> +int func1()
> +{
> +   INT1 w;				/* { dg-error "'INT1' is  
> unavailable: You can't use INT1" "" } */
> +   int x __attribute__ ((unavailable("You can't use x")));
> +   int y __attribute__ ((__unavailable__("You can't use y")));
> +   int z;
> +   int (*pf)() = f1;			/* { dg-error "'INT1 f1\\(\\)' is  
> unavailable: You can't use f1" "" } */
> +
> +   z = w + x + y + g1 + g2 + g3;	/* { dg-error "'x' is unavailable:  
> You can't use x" "" } */
> +					/* { dg-error "'y' is unavailable:  
> You can't use y" "y" { target *-*-* } .-1 } */
> +					/* { dg-error "'g2' is unavailable:  
> You can't use g2" "g2" { target *-*-* } .-2 } */
> +					/* { dg-error "'g3' is unavailable:  
> You can't use g3" "g3" { target *-*-* } .-3 } */
> +   return f1(); 			/* { dg-error "'INT1 f1\\(\\)' is  
> unavailable: You can't use f1" "f1" } */
> +}
> +
> +int func2(S1 *p)
> +{
> +  S1 lp;
> +
> +  if (p->field1)
> +     return p->field2;			/* { dg-error "'S1::field2'  
> is unavailable: You can't use field2" "" } */
> +  else if (lp.field4)			/* { dg-error "'S1::field4'  
> is unavailable: You can't use field4" "" } */
> +     return p->field3;
> +
> +  p->u1.field5 = g1 + p->field7;
> +  p->u2.field9;				/* { dg-error "'S1::u2' is  
> unavailable: You can't use u2" "" } */
> +  return p->u1.field6 + p->field8;	/* { dg-error "'S1::<unnamed  
> union>::field6' is unavailable: You can't use field6" "" } */
> +					/* { dg-error "'S1::field8' is  
> unavailable: You can't use field8" "field8" { target *-*-* } .-1 } */
> +}
> +
> +struct SS1 {
> +  int x;
> +  INT1 y; 				/* { dg-error "'INT1' is  
> unavailable: You can't use INT1" "" } */
> +} __attribute__ ((unavailable("You can't use SS1")));
> +
> +struct SS1 *p1;				/* { dg-error "'SS1' is  
> unavailable: You can't use SS1" "" } */
> +
> +struct __attribute__ ((__unavailable__("You can't use SS2"))) SS2 {
> +  int x;
> +  INT1 y; 				/* { dg-error "'INT1' is  
> unavailable: You can't use INT1" "" } */
> +};
> +
> +struct SS2 *p2;				/* { dg-error "'SS2' is  
> unavailable: You can't use SS2" "" } */
> +
> +class T {
> +  public:
> +    void member1(int) __attribute__ ((unavailable("You can't use  
> member1")));
> +    void member2(INT1) __attribute__ ((__unavailable__("You can't use  
> member2")));
> +    int member3(T *);
> +    int x;
> +} __attribute__ ((unavailable("You can't use T")));
> +
> +T *p3;				// { dg-error "'T' is unavailable: You can't use T" }
> +
> +inline void T::member1(int) {}
> +
> +int T::member3(T *p)		// { dg-error "'T' is unavailable: You  
> can't use T" }
> +{
> +  p->member1(1);			/* { dg-error "'void  
> T::member1\\(int\\)' is unavailable: You can't use member1" "" } */
> +  (*p).member1(2);			/* { dg-error "'void  
> T::member1\\(int\\)' is unavailable: You can't use member1" "" } */
> +  p->member2(1);			/* { dg-error "'void  
> T::member2\\(INT1\\)' is unavailable: You can't use member2" "" } */
> +  (*p).member2(2);			/* { dg-error "'void  
> T::member2\\(INT1\\)' is unavailable: You can't use member2" "" } */
> +  p->member3(p);
> +  (*p).member3(p);
> +  return f1(); 				/* { dg-error "'INT1  
> f1\\(\\)' is unavailable: You can't use f1" "" } */
> +}
> diff --git a/gcc/testsuite/g++.dg/ext/attr-unavailable-7.C  
> b/gcc/testsuite/g++.dg/ext/attr-unavailable-7.C
> new file mode 100644
> index 00000000000..c061aa3b6a2
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/ext/attr-unavailable-7.C
> @@ -0,0 +1,19 @@
> +/* Test __attribute__ ((unavailable)) */
> +/* { dg-do compile } */
> +/* { dg-options "" } */
> +
> +int g_nn;
> +int& g_n __attribute__((unavailable)) = g_nn;
> +
> +void f()
> +{
> +  int f_nn;
> +  int& f_n __attribute__((unavailable)) = f_nn;
> +  f_n = 1;    // { dg-error "'f_n' is unavailable" }
> +}
> +
> +int main()
> +{
> +  g_n = 1;    // { dg-error "'g_n' is unavailable" }
> +  f();
> +}
> diff --git a/gcc/testsuite/g++.dg/ext/attr-unavailable-8.C  
> b/gcc/testsuite/g++.dg/ext/attr-unavailable-8.C
> new file mode 100644
> index 00000000000..334a2cf7286
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/ext/attr-unavailable-8.C
> @@ -0,0 +1,17 @@
> +/* Test __attribute__ ((unavailable)) */
> +/* { dg-do compile } */
> +/* { dg-options "" } */
> +
> +class ToBeunavailable {
> +} __attribute__ ((unavailable ("unavailable!")));
> +
> +typedef ToBeunavailable NotToBeunavailable; // { dg-error  
> "'ToBeunavailable' is unavailable" }
> +
> +int main() {
> +
> +  ToBeunavailable();    // { dg-error "'ToBeunavailable' is unavailable" }
> +  ToBeunavailable x;    // { dg-error "'ToBeunavailable' is unavailable" }
> +
> +  NotToBeunavailable();
> +  NotToBeunavailable y;
> +}
> diff --git a/gcc/testsuite/g++.dg/ext/attr-unavailable-9.C  
> b/gcc/testsuite/g++.dg/ext/attr-unavailable-9.C
> new file mode 100644
> index 00000000000..44161336e78
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/ext/attr-unavailable-9.C
> @@ -0,0 +1,17 @@
> +/* Test __attribute__ ((unavailable)) */
> +/* { dg-do compile } */
> +/* { dg-options "" } */
> +
> +template<typename T> struct __attribute__ ((unavailable)) S {};
> +S<int> s;
> +
> +template <template <class> class T> struct A { };
> +A<S> a;
> +
> +template <class T> void f() __attribute__ ((unavailable));
> +
> +int main()
> +{
> +  f<int>();			// { dg-error "unavailable" }
> +  void (*p)() = f<char>;	// { dg-error "unavailable" }
> +}
> diff --git a/gcc/testsuite/gcc.dg/attr-unavailable-1.c  
> b/gcc/testsuite/gcc.dg/attr-unavailable-1.c
> new file mode 100644
> index 00000000000..768214fcd3a
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/attr-unavailable-1.c
> @@ -0,0 +1,88 @@
> +/* Test __attribute__ ((unavailable)) */
> +/* { dg-do compile } */
> +/* { dg-options "" } */
> +
> +typedef int INT1 __attribute__((unavailable));
> +typedef INT1 INT2 __attribute__ ((__unavailable__));
> +
> +typedef INT1 INT1a; 			/* { dg-error "'INT1' is unavailable" "" } */
> +typedef INT1 INT1b __attribute__ ((unavailable));
> +
> +INT1 should_be_unavailable; 		/* { dg-error "'INT1' is  
> unavailable" "" } */
> +INT1a should_not_be_unavailable;
> +
> +INT1 f1(void) __attribute__ ((unavailable));
> +INT1 f2(void) { return 0; }		/* { dg-error "'INT1' is unavailable" "" } */
> +
> +INT2 f3(void) __attribute__ ((__unavailable__));
> +INT2 f4(void) { return 0; }		/* { dg-error "'INT2' is unavailable" "" } */
> +int f5(INT2 x);				/* { dg-error "'INT2' is unavailable" "" } */
> +int f6(INT2 x) __attribute__ ((__unavailable__)); /* { dg-error "'INT2'  
> is unavailable" "" } */
> +
> +typedef enum {red, green, blue} Color __attribute__((unavailable));
> +
> +int g1;
> +int g2 __attribute__ ((unavailable));
> +int g3 __attribute__ ((__unavailable__));
> +Color k;				/* { dg-error "'Color' is unavailable" "" } */
> +
> +typedef struct {
> +  int field1;
> +  int field2 __attribute__ ((unavailable));
> +  int field3;
> +  int field4 __attribute__ ((__unavailable__));
> +  union {
> +    int field5;
> +    int field6 __attribute__ ((unavailable));
> +  } u1;
> +  int field7:1;
> +  int field8:1 __attribute__ ((unavailable));
> +  union {
> +    int field9;
> +    int field10;
> +  } u2 __attribute__ ((unavailable));
> +} S1;
> +
> +int func1()
> +{
> +   INT1 w;				/* { dg-error "'INT1' is unavailable" "" } */
> +   int x __attribute__ ((unavailable));
> +   int y __attribute__ ((__unavailable__));
> +   int z;
> +   int (*pf)() = f1;			/* { dg-error "'f1' is unavailable" "" } */
> +
> +   z = w + x + y + g1 + g2 + g3;	/* { dg-error "'x' is unavailable"  
> "" } */
> +					/* { dg-error "'y' is unavailable" "y" { target *-*-* } .-1 } */
> +					/* { dg-error "'g2' is unavailable" "g2" { target *-*-* } .-2 } */
> +					/* { dg-error "'g3' is unavailable" "g3" { target *-*-* } .-3 } */
> +   return f1(); 			/* { dg-error "'f1' is unavailable" "f1" } */
> +}
> +
> +int func2(S1 *p)
> +{
> +  S1 lp;
> +
> +  if (p->field1)
> +     return p->field2;			/* { dg-error "'field2' is unavailable" "" } */
> +  else if (lp.field4)			/* { dg-error "'field4' is unavailable" "" } */
> +     return p->field3;
> +
> +  p->u1.field5 = g1 + p->field7;
> +  p->u2.field9;				/* { dg-error "'u2' is unavailable" "" } */
> +  return p->u1.field6 + p->field8;	/* { dg-error "'field6' is  
> unavailable" "" } */
> +					/* { dg-error "'field8' is  
> unavailable" "field8" { target *-*-* } .-1 } */
> +}
> +
> +struct SS1 {
> +  int x;
> +  INT1 y; 				/* { dg-error "'INT1' is unavailable" "" } */
> +} __attribute__ ((unavailable));
> +
> +struct SS1 *p1;				/* { dg-error "'SS1' is unavailable" "" } */
> +
> +struct __attribute__ ((__unavailable__)) SS2 {
> +  int x;
> +  INT1 y; 				/* { dg-error "'INT1' is unavailable" "" } */
> +};
> +
> +struct SS2 *p2;				/* { dg-error "'SS2' is unavailable" "" } */
> diff --git a/gcc/testsuite/gcc.dg/attr-unavailable-2.c  
> b/gcc/testsuite/gcc.dg/attr-unavailable-2.c
> new file mode 100644
> index 00000000000..303f973d5db
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/attr-unavailable-2.c
> @@ -0,0 +1,6 @@
> +/* Test __attribute__((unavailable)).  Test types without names.  */
> +/* { dg-do compile } */
> +/* { dg-options "" } */
> +
> +struct { int a; } __attribute__((unavailable)) x; /* { dg-error "type is  
> unavailable" } */
> +typeof(x) y; /* { dg-error "type is unavailable" } */
> diff --git a/gcc/testsuite/gcc.dg/attr-unavailable-3.c  
> b/gcc/testsuite/gcc.dg/attr-unavailable-3.c
> new file mode 100644
> index 00000000000..7274c193f3f
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/attr-unavailable-3.c
> @@ -0,0 +1,10 @@
> +/* Test __attribute__((unavailable)). */
> +/* { dg-do compile } */
> +/* { dg-options "" } */
> +
> +void func(void);
> +void func(void) __attribute__((unavailable));
> +
> +void f(void) {
> +  func(); /* { dg-error "'func' is unavailable" } */
> +}
> diff --git a/gcc/testsuite/gcc.dg/attr-unavailable-4.c  
> b/gcc/testsuite/gcc.dg/attr-unavailable-4.c
> new file mode 100644
> index 00000000000..9e39c50fec6
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/attr-unavailable-4.c
> @@ -0,0 +1,88 @@
> +/* Test __attribute__ ((unavailable("message"))) */
> +/* { dg-do compile } */
> +/* { dg-options "" } */
> +
> +typedef int INT1 __attribute__((unavailable("You can't use INT1")));
> +typedef INT1 INT2 __attribute__ ((__unavailable__("You can't use INT2")));
> +
> +typedef INT1 INT1a; 			/* { dg-error "'INT1' is  
> unavailable: You can't use INT1" "" } */
> +typedef INT1 INT1b __attribute__ ((unavailable("You can't use INT1b")));
> +
> +INT1 should_be_unavailable; 		/* { dg-error "'INT1' is  
> unavailable: You can't use INT1" "" } */
> +INT1a should_not_be_unavailable;
> +
> +INT1 f1(void) __attribute__ ((unavailable("You can't use f1")));
> +INT1 f2(void) { return 0; }		/* { dg-error "'INT1' is  
> unavailable: You can't use INT1" "" } */
> +
> +INT2 f3(void) __attribute__ ((__unavailable__("You can't use f3")));
> +INT2 f4(void) { return 0; }		/* { dg-error "'INT2' is  
> unavailable: You can't use INT2" "" } */
> +int f5(INT2 x);				/* { dg-error "'INT2' is  
> unavailable: You can't use INT2" "" } */
> +int f6(INT2 x) __attribute__ ((__unavailable__("You can't use f6"))); /*  
> { dg-error "'INT2' is unavailable: You can't use INT2" "" } */
> +
> +typedef enum {red, green, blue} Color __attribute__((unavailable("You  
> can't use Color")));
> +
> +int g1;
> +int g2 __attribute__ ((unavailable("You can't use g2")));
> +int g3 __attribute__ ((__unavailable__("You can't use g3")));
> +Color k;				/* { dg-error "'Color' is  
> unavailable: You can't use Color" "" } */
> +
> +typedef struct {
> +  int field1;
> +  int field2 __attribute__ ((unavailable("You can't use field2")));
> +  int field3;
> +  int field4 __attribute__ ((__unavailable__("You can't use field4")));
> +  union {
> +    int field5;
> +    int field6 __attribute__ ((unavailable("You can't use field6")));
> +  } u1;
> +  int field7:1;
> +  int field8:1 __attribute__ ((unavailable("You can't use field8")));
> +  union {
> +    int field9;
> +    int field10;
> +  } u2 __attribute__ ((unavailable("You can't use u2")));
> +} S1;
> +
> +int func1()
> +{
> +   INT1 w;				/* { dg-error "'INT1' is  
> unavailable: You can't use INT1" "" } */
> +   int x __attribute__ ((unavailable("Avoid x")));
> +   int y __attribute__ ((__unavailable__("Bad y")));
> +   int z;
> +   int (*pf)() = f1;			/* { dg-error "'f1' is unavailable:  
> You can't use f1" "" } */
> +
> +   z = w + x + y + g1 + g2 + g3;	/* { dg-error "'x' is unavailable:  
> Avoid x" "" } */
> +					/* { dg-error "'y' is unavailable:  
> Bad y" "y" { target *-*-* } .-1  } */
> +					/* { dg-error "'g2' is unavailable:  
> You can't use g2" "g2" { target *-*-* } .-2  }  */
> +					/* { dg-error "'g3' is unavailable:  
> You can't use g3" "g3" { target *-*-* } .-3  } */
> +   return f1(); 			/* { dg-error "'f1' is unavailable:  
> You can't use f1" "" } */
> +}
> +
> +int func2(S1 *p)
> +{
> +  S1 lp;
> +
> +  if (p->field1)
> +     return p->field2;			/* { dg-error "'field2' is  
> unavailable: You can't use field2" "" } */
> +  else if (lp.field4)			/* { dg-error "'field4' is  
> unavailable: You can't use field4" "" } */
> +     return p->field3;
> +
> +  p->u1.field5 = g1 + p->field7;
> +  p->u2.field9;				/* { dg-error "'u2' is  
> unavailable: You can't use u2" "" } */
> +  return p->u1.field6 + p->field8;	/* { dg-error "'field6' is  
> unavailable: You can't use field6" "" } */
> +					/* { dg-error "'field8' is  
> unavailable: You can't use field8" "field8" { target *-*-* } .-1 } */
> +}
> +
> +struct SS1 {
> +  int x;
> +  INT1 y; 				/* { dg-error "'INT1' is  
> unavailable: You can't use INT1" "" } */
> +} __attribute__ ((unavailable("You can't use SS1")));
> +
> +struct SS1 *p1;				/* { dg-error "'SS1' is  
> unavailable: You can't use SS1" "" } */
> +
> +struct __attribute__ ((__unavailable__("You can't use SS2"))) SS2 {
> +  int x;
> +  INT1 y; 				/* { dg-error "'INT1' is  
> unavailable: You can't use INT1" "" } */
> +};
> +
> +struct SS2 *p2;				/* { dg-error "'SS2' is  
> unavailable: You can't use SS2" "" } */
> diff --git a/gcc/testsuite/gcc.dg/attr-unavailable-5.c  
> b/gcc/testsuite/gcc.dg/attr-unavailable-5.c
> new file mode 100644
> index 00000000000..051f960c5cf
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/attr-unavailable-5.c
> @@ -0,0 +1,6 @@
> +/* Test __attribute__((unavailable)).  Test types without names.  */
> +/* { dg-do compile } */
> +/* { dg-options "" } */
> +
> +struct { int a; } __attribute__((unavailable ("Do not use"))) x; /* {  
> dg-error "type is unavailable" } */
> +typeof(x) y; /* { dg-error "type is unavailable: Do not use" } */
> diff --git a/gcc/testsuite/gcc.dg/attr-unavailable-6.c  
> b/gcc/testsuite/gcc.dg/attr-unavailable-6.c
> new file mode 100644
> index 00000000000..f5f4560c735
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/attr-unavailable-6.c
> @@ -0,0 +1,11 @@
> +/* Test __attribute__((unavailable)).  Test merging with multiple
> +   declarations. */
> +/* { dg-do compile } */
> +/* { dg-options "" } */
> +
> +void func(void);
> +void func(void) __attribute__((unavailable ("Do not use")));
> +
> +void f(void) {
> +  func(); /* { dg-error "'func' is unavailable: Do not use" } */
> +}
> diff --git a/gcc/testsuite/obj-c++.dg/attributes/method-unavailable-1.mm  
> b/gcc/testsuite/obj-c++.dg/attributes/method-unavailable-1.mm
> new file mode 100644
> index 00000000000..e5708c202c0
> --- /dev/null
> +++ b/gcc/testsuite/obj-c++.dg/attributes/method-unavailable-1.mm
> @@ -0,0 +1,34 @@
> +/* Test __attribute__ ((unavailable)) */
> +/* { dg-do compile } */
> +/* { dg-options "" } */
> +
> +#include <objc/objc.h>
> +
> +@interface MyClass
> +{
> +  Class isa;
> +}
> ++ (int) method;
> +- (int) method;
> ++ (int) unavailableClassMethod __attribute__((unavailable));
> +- (int) unavailableInstanceMethod __attribute__((unavailable));
> +@end
> +
> +/* Test that deprecation warnings are produced, but not if the
> +   receiver is of type 'id'.  */
> +void foo (void)
> +{
> +  Class c;
> +  id object;
> +  MyClass *another_object;
> +
> +  [c method];
> +  [object method];
> +  [c unavailableClassMethod];
> +  [object unavailableInstanceMethod];
> +
> +  [object method];
> +  [another_object method];
> +  [MyClass unavailableClassMethod];           /* { dg-error "is  
> unavailable" } */
> +  [another_object unavailableInstanceMethod]; /* { dg-error "is  
> unavailable" } */
> +}
> diff --git a/gcc/testsuite/obj-c++.dg/attributes/method-unavailable-2.mm  
> b/gcc/testsuite/obj-c++.dg/attributes/method-unavailable-2.mm
> new file mode 100644
> index 00000000000..68ea46d2543
> --- /dev/null
> +++ b/gcc/testsuite/obj-c++.dg/attributes/method-unavailable-2.mm
> @@ -0,0 +1,24 @@
> +/* Test __attribute__ ((unavailable)) */
> +/* { dg-do compile } */
> +/* { dg-options "" } */
> +
> +#include <objc/objc.h>
> +
> +@interface MyClass
> +{
> +  Class isa;
> +}
> ++ (int) unavailableClassMethod: (id)firstObject, ...     
> __attribute__((sentinel)) __attribute__((unavailable));
> +- (int) unavailableInstanceMethod: (id)firstobject, ...  
> __attribute__((sentinel)) __attribute__((unavailable));
> +@end
> +
> +/* Test that unavailability errors are produced even if the method is
> +   also marked with another attribute too (this is to test the
> +   processing of multiple attributes).  */
> +void foo (void)
> +{
> +  MyClass *object = nil;
> +
> +  [MyClass unavailableClassMethod: object, nil];           /* { dg-error  
> "is unavailable" } */
> +  [object unavailableInstanceMethod: object, nil];         /* { dg-error  
> "is unavailable" } */
> +}
> diff --git a/gcc/testsuite/obj-c++.dg/attributes/method-unavailable-3.mm  
> b/gcc/testsuite/obj-c++.dg/attributes/method-unavailable-3.mm
> new file mode 100644
> index 00000000000..9e55ae11e1f
> --- /dev/null
> +++ b/gcc/testsuite/obj-c++.dg/attributes/method-unavailable-3.mm
> @@ -0,0 +1,22 @@
> +/* Test __attribute__ ((unavailable)) */
> +/* { dg-do compile } */
> +/* { dg-options "" } */
> +
> +#include <objc/objc.h>
> +
> +/* Test that __attribute__ ((__unavailable__)) works as well as  
> __attribute__ ((unavailable)).  */
> +@interface MyClass
> +{
> +  Class isa;
> +}
> ++ (int) unavailableClassMethod: (id)firstObject, ...     
> __attribute__((__unavailable__));
> +- (int) unavailableInstanceMethod: (id)firstobject, ...  
> __attribute__((__unavailable__));
> +@end
> +
> +void foo (void)
> +{
> +  MyClass *object = nil;
> +
> +  [MyClass unavailableClassMethod: object, nil];           /* { dg-error  
> "is unavailable" } */
> +  [object unavailableInstanceMethod: object, nil];         /* { dg-error  
> "is unavailable" } */
> +}
> diff --git  
> a/gcc/testsuite/obj-c++.dg/property/at-property-unavailable-1.mm  
> b/gcc/testsuite/obj-c++.dg/property/at-property-unavailable-1.mm
> new file mode 100644
> index 00000000000..6bb4755220d
> --- /dev/null
> +++ b/gcc/testsuite/obj-c++.dg/property/at-property-unavailable-1.mm
> @@ -0,0 +1,38 @@
> +/* Test __attribute__ ((unavailable)) */
> +/* { dg-do compile } */
> +/* { dg-options "" } */
> +
> +/* Test that properties can be unavailable.  */
> +
> +#include <stdlib.h>
> +#include <objc/objc.h>
> +#include <objc/runtime.h>
> +
> +@interface MyRootClass
> +{
> +  Class isa;
> +  int a;
> +}
> +@property int a __attribute__((unavailable));
> ++ (id) initialize;
> ++ (id) alloc;
> +- (id) init;
> +@end
> +
> +@implementation MyRootClass
> ++ (id) initialize { return self; }
> ++ (id) alloc { return class_createInstance (self, 0); }
> +- (id) init { return self; }
> +@synthesize a;
> +@end
> +
> +int main (void)
> +{
> +  MyRootClass *object = [[MyRootClass alloc] init];
> +
> +  object.a = 40;      /* { dg-error "is unavailable" } */
> +  if (object.a != 40) /* { dg-error "is unavailable" } */
> +    abort ();
> +
> +  return (0);
> +}
> diff --git  
> a/gcc/testsuite/obj-c++.dg/property/at-property-unavailable-2.mm  
> b/gcc/testsuite/obj-c++.dg/property/at-property-unavailable-2.mm
> new file mode 100644
> index 00000000000..5edc1626c89
> --- /dev/null
> +++ b/gcc/testsuite/obj-c++.dg/property/at-property-unavailable-2.mm
> @@ -0,0 +1,26 @@
> +/* Test __attribute__ ((unavailable)) */
> +/* { dg-do compile } */
> +/* { dg-options "" } */
> +
> +/* Test that unavailability errors are produced when a setter/getter of
> +   a @property is used directly.  */
> +
> +#include <objc/objc.h>
> +
> +@interface MyClass
> +{
> +  Class isa;
> +  int variable;
> +}
> +@property (assign, nonatomic) int property __attribute__ ((unavailable));
> +@end
> +
> +void foo (void)
> +{
> +  MyClass *object = nil;
> +
> +  if ([object property] > 0)  /* { dg-error "is unavailable" } */
> +    {
> +      [object setProperty: 43]; /* { dg-error "is unavailable" } */
> +    }
> +}
> diff --git a/gcc/testsuite/obj-c++.dg/property/dotsyntax-unavailable-1.mm  
> b/gcc/testsuite/obj-c++.dg/property/dotsyntax-unavailable-1.mm
> new file mode 100644
> index 00000000000..e2ef2a5b23b
> --- /dev/null
> +++ b/gcc/testsuite/obj-c++.dg/property/dotsyntax-unavailable-1.mm
> @@ -0,0 +1,42 @@
> +/* Test __attribute__ ((unavailable)) */
> +/* { dg-do compile } */
> +/* { dg-options "" } */
> +
> +/* Test the 'dot syntax' with unavailable methods.  */
> +
> +#include <objc/objc.h>
> +
> +@interface MyClass
> +{
> +  Class isa;
> +}
> ++ (int) classCount __attribute__ ((unavailable));
> ++ (void) setClassCount: (int)value __attribute__ ((unavailable));
> +
> +- (int) count __attribute__ ((unavailable));
> +- (void) setCount: (int)value __attribute__ ((unavailable));
> +
> +- (int) classCount2;
> +- (void) setClassCount2: (int)value;
> +
> +- (int) count2;
> +- (void) setCount2: (int)value;
> +@end
> +
> +void foo (void)
> +{
> +  MyClass *object = nil;
> +
> +
> +  if (object.count > 0)  /* { dg-error "is unavailable" } */
> +    object.count = 20;  /* { dg-error "is unavailable" } */
> +
> +  if (MyClass.classCount < -7)   /* { dg-error "is unavailable" } */
> +    MyClass.classCount = 11;  /* { dg-error "is unavailable" } */
> +
> +  if (object.classCount2 > 0)
> +    object.classCount2 = 19;
> +
> +  if (object.count2 < -7)
> +    object.count2 = 74;
> +}
> diff --git a/gcc/testsuite/objc.dg/attributes/method-unavailable-1.m  
> b/gcc/testsuite/objc.dg/attributes/method-unavailable-1.m
> new file mode 100644
> index 00000000000..7a3de6b245d
> --- /dev/null
> +++ b/gcc/testsuite/objc.dg/attributes/method-unavailable-1.m
> @@ -0,0 +1,34 @@
> +/* Test __attribute__ ((unavailable)) */
> +/* { dg-do compile } */
> +/* { dg-options "" } */
> +
> +#include <objc/objc.h>
> +
> +@interface MyClass
> +{
> +  Class isa;
> +}
> ++ (int) method;
> +- (int) method;
> ++ (int) unavailableClassMethod __attribute__((unavailable));
> +- (int) unavailableInstanceMethod __attribute__((unavailable));
> +@end
> +
> +/* Test that unavailability errors are produced, but not if the
> +   receiver is of type 'id'.  */
> +void foo (void)
> +{
> +  Class c;
> +  id object;
> +  MyClass *another_object;
> +
> +  [c method];
> +  [object method];
> +  [c unavailableClassMethod];
> +  [object unavailableInstanceMethod];
> +
> +  [object method];
> +  [another_object method];
> +  [MyClass unavailableClassMethod];           /* { dg-error "is  
> unavailable" } */
> +  [another_object unavailableInstanceMethod]; /* { dg-error "is  
> unavailable" } */
> +}
> diff --git a/gcc/testsuite/objc.dg/attributes/method-unavailable-2.m  
> b/gcc/testsuite/objc.dg/attributes/method-unavailable-2.m
> new file mode 100644
> index 00000000000..68ea46d2543
> --- /dev/null
> +++ b/gcc/testsuite/objc.dg/attributes/method-unavailable-2.m
> @@ -0,0 +1,24 @@
> +/* Test __attribute__ ((unavailable)) */
> +/* { dg-do compile } */
> +/* { dg-options "" } */
> +
> +#include <objc/objc.h>
> +
> +@interface MyClass
> +{
> +  Class isa;
> +}
> ++ (int) unavailableClassMethod: (id)firstObject, ...     
> __attribute__((sentinel)) __attribute__((unavailable));
> +- (int) unavailableInstanceMethod: (id)firstobject, ...  
> __attribute__((sentinel)) __attribute__((unavailable));
> +@end
> +
> +/* Test that unavailability errors are produced even if the method is
> +   also marked with another attribute too (this is to test the
> +   processing of multiple attributes).  */
> +void foo (void)
> +{
> +  MyClass *object = nil;
> +
> +  [MyClass unavailableClassMethod: object, nil];           /* { dg-error  
> "is unavailable" } */
> +  [object unavailableInstanceMethod: object, nil];         /* { dg-error  
> "is unavailable" } */
> +}
> diff --git a/gcc/testsuite/objc.dg/attributes/method-unavailable-3.m  
> b/gcc/testsuite/objc.dg/attributes/method-unavailable-3.m
> new file mode 100644
> index 00000000000..9e55ae11e1f
> --- /dev/null
> +++ b/gcc/testsuite/objc.dg/attributes/method-unavailable-3.m
> @@ -0,0 +1,22 @@
> +/* Test __attribute__ ((unavailable)) */
> +/* { dg-do compile } */
> +/* { dg-options "" } */
> +
> +#include <objc/objc.h>
> +
> +/* Test that __attribute__ ((__unavailable__)) works as well as  
> __attribute__ ((unavailable)).  */
> +@interface MyClass
> +{
> +  Class isa;
> +}
> ++ (int) unavailableClassMethod: (id)firstObject, ...     
> __attribute__((__unavailable__));
> +- (int) unavailableInstanceMethod: (id)firstobject, ...  
> __attribute__((__unavailable__));
> +@end
> +
> +void foo (void)
> +{
> +  MyClass *object = nil;
> +
> +  [MyClass unavailableClassMethod: object, nil];           /* { dg-error  
> "is unavailable" } */
> +  [object unavailableInstanceMethod: object, nil];         /* { dg-error  
> "is unavailable" } */
> +}
> diff --git a/gcc/testsuite/objc.dg/property/at-property-unavailable-1.m  
> b/gcc/testsuite/objc.dg/property/at-property-unavailable-1.m
> new file mode 100644
> index 00000000000..855ccc6b028
> --- /dev/null
> +++ b/gcc/testsuite/objc.dg/property/at-property-unavailable-1.m
> @@ -0,0 +1,38 @@
> +/* Test __attribute__ ((unavailable)) */
> +/* { dg-do compile } */
> +/* { dg-options "" } */
> +
> +/* Test that properties can be unavailable.  */
> +
> +#include <stdlib.h>
> +#include <objc/objc.h>
> +#include <objc/runtime.h>
> +
> +@interface MyRootClass
> +{
> +  Class isa;
> +  int a;
> +}
> +@property int a __attribute__((unavailable));
> ++ (id) initialize;
> ++ (id) alloc;
> +- (id) init;
> +@end
> +
> +@implementation MyRootClass
> ++ (id) initialize { return self; }
> ++ (id) alloc { return class_createInstance (self, 0); }
> +- (id) init { return self; }
> +@synthesize a;
> +@end
> +
> +int main (void)
> +{
> +  MyRootClass *object = [[MyRootClass alloc] init];
> +
> +  object.a = 40;      /* { dg-error "is unavailable" } */
> +  if (object.a != 40) /* { dg-error "is unavailable" } */
> +    abort ();
> +
> +  return 0;
> +}
> diff --git a/gcc/testsuite/objc.dg/property/at-property-unavailable-2.m  
> b/gcc/testsuite/objc.dg/property/at-property-unavailable-2.m
> new file mode 100644
> index 00000000000..5edc1626c89
> --- /dev/null
> +++ b/gcc/testsuite/objc.dg/property/at-property-unavailable-2.m
> @@ -0,0 +1,26 @@
> +/* Test __attribute__ ((unavailable)) */
> +/* { dg-do compile } */
> +/* { dg-options "" } */
> +
> +/* Test that unavailability errors are produced when a setter/getter of
> +   a @property is used directly.  */
> +
> +#include <objc/objc.h>
> +
> +@interface MyClass
> +{
> +  Class isa;
> +  int variable;
> +}
> +@property (assign, nonatomic) int property __attribute__ ((unavailable));
> +@end
> +
> +void foo (void)
> +{
> +  MyClass *object = nil;
> +
> +  if ([object property] > 0)  /* { dg-error "is unavailable" } */
> +    {
> +      [object setProperty: 43]; /* { dg-error "is unavailable" } */
> +    }
> +}
> diff --git a/gcc/testsuite/objc.dg/property/dotsyntax-unavailable-1.m  
> b/gcc/testsuite/objc.dg/property/dotsyntax-unavailable-1.m
> new file mode 100644
> index 00000000000..e2ef2a5b23b
> --- /dev/null
> +++ b/gcc/testsuite/objc.dg/property/dotsyntax-unavailable-1.m
> @@ -0,0 +1,42 @@
> +/* Test __attribute__ ((unavailable)) */
> +/* { dg-do compile } */
> +/* { dg-options "" } */
> +
> +/* Test the 'dot syntax' with unavailable methods.  */
> +
> +#include <objc/objc.h>
> +
> +@interface MyClass
> +{
> +  Class isa;
> +}
> ++ (int) classCount __attribute__ ((unavailable));
> ++ (void) setClassCount: (int)value __attribute__ ((unavailable));
> +
> +- (int) count __attribute__ ((unavailable));
> +- (void) setCount: (int)value __attribute__ ((unavailable));
> +
> +- (int) classCount2;
> +- (void) setClassCount2: (int)value;
> +
> +- (int) count2;
> +- (void) setCount2: (int)value;
> +@end
> +
> +void foo (void)
> +{
> +  MyClass *object = nil;
> +
> +
> +  if (object.count > 0)  /* { dg-error "is unavailable" } */
> +    object.count = 20;  /* { dg-error "is unavailable" } */
> +
> +  if (MyClass.classCount < -7)   /* { dg-error "is unavailable" } */
> +    MyClass.classCount = 11;  /* { dg-error "is unavailable" } */
> +
> +  if (object.classCount2 > 0)
> +    object.classCount2 = 19;
> +
> +  if (object.count2 < -7)
> +    object.count2 = 74;
> +}
> diff --git a/gcc/tree-core.h b/gcc/tree-core.h
> index c9280a8d3b1..97b3cdd7bd9 100644
> --- a/gcc/tree-core.h
> +++ b/gcc/tree-core.h
> @@ -1001,7 +1001,8 @@ struct GTY(()) tree_base {
>       unsigned user_align : 1;
>       unsigned nameless_flag : 1;
>       unsigned atomic_flag : 1;
> -      unsigned spare0 : 3;
> +      unsigned unavailable_flag : 1;
> +      unsigned spare0 : 2;
>
>       unsigned spare1 : 8;
>
> @@ -1323,6 +1324,12 @@ struct GTY(()) tree_base {
>        SSA_NAME_POINTS_TO_READONLY_MEMORY in
> 	   SSA_NAME
>
> +   unavailable_flag:
> +
> +       TREE_UNAVAILABLE in
> +	   all decls
> +	   all types
> +
>    visited:
>
>        TREE_VISITED in
> @@ -1370,6 +1377,7 @@ struct GTY(()) tree_base {
>
>        CALL_EXPR_BY_DESCRIPTOR in
>            CALL_EXPR
> +
> */
>
> struct GTY(()) tree_typed {
> diff --git a/gcc/tree.c b/gcc/tree.c
> index 9260772b846..ea3f87650dd 100644
> --- a/gcc/tree.c
> +++ b/gcc/tree.c
> @@ -13162,6 +13162,78 @@ warn_deprecated_use (tree node, tree attr)
>   return w;
> }
>
> +/* Error out with an identifier which was marked 'unavailable'. */
> +void
> +error_unavailable_use (tree node, tree attr)
> +{
> +  escaped_string msg;
> +
> +  if (node == 0)
> +    return;
> +
> +  if (!attr)
> +    {
> +      if (DECL_P (node))
> +	attr = DECL_ATTRIBUTES (node);
> +      else if (TYPE_P (node))
> +	{
> +	  tree decl = TYPE_STUB_DECL (node);
> +	  if (decl)
> +	    attr = lookup_attribute ("unavailable",
> +				     TYPE_ATTRIBUTES (TREE_TYPE (decl)));
> +	}
> +    }
> +
> +  if (attr)
> +    attr = lookup_attribute ("unavailable", attr);
> +
> +  if (attr)
> +    msg.escape (TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr))));
> +
> +  if (DECL_P (node))
> +    {
> +      auto_diagnostic_group d;
> +      if (msg)
> +	error ("%qD is unavailable: %s", node, (const char *) msg);
> +      else
> +	error ("%qD is unavailable", node);
> +      inform (DECL_SOURCE_LOCATION (node), "declared here");
> +    }
> +  else if (TYPE_P (node))
> +    {
> +      tree what = NULL_TREE;
> +      tree decl = TYPE_STUB_DECL (node);
> +
> +      if (TYPE_NAME (node))
> +	{
> +	  if (TREE_CODE (TYPE_NAME (node)) == IDENTIFIER_NODE)
> +	    what = TYPE_NAME (node);
> +	  else if (TREE_CODE (TYPE_NAME (node)) == TYPE_DECL
> +		   && DECL_NAME (TYPE_NAME (node)))
> +	    what = DECL_NAME (TYPE_NAME (node));
> +	}
> +
> +      auto_diagnostic_group d;
> +      if (what)
> +	{
> +	  if (msg)
> +	    error ("%qE is unavailable: %s", what, (const char *) msg);
> +	  else
> +	    error ("%qE is unavailable", what);
> +	}
> +      else
> +	{
> +	  if (msg)
> +	    error ("type is unavailable: %s", (const char *) msg);
> +	  else
> +	    error ("type is unavailable");
> +	}
> +
> +      if (decl)
> +	inform (DECL_SOURCE_LOCATION (decl), "declared here");
> +    }
> +}
> +
> /* Return true if REF has a COMPONENT_REF with a bit-field field  
> declaration
>    somewhere in it.  */
>
> diff --git a/gcc/tree.h b/gcc/tree.h
> index f8f0a606439..e8a9c90f234 100644
> --- a/gcc/tree.h
> +++ b/gcc/tree.h
> @@ -952,6 +952,11 @@ extern void omp_clause_range_check_failed  
> (const_tree, const char *, int,
> #define TREE_DEPRECATED(NODE) \
>   ((NODE)->base.deprecated_flag)
>
> +/* Nonzero in a _DECL if the use of the name is defined as an
> +   unavailable feature by __attribute__((unavailable)).  */
> +#define TREE_UNAVAILABLE(NODE) \
> +  ((NODE)->base.u.bits.unavailable_flag)
> +
> /* Nonzero indicates an IDENTIFIER_NODE that names an anonymous
>    aggregate, (as created by anon_aggr_name_format).  */
> #define IDENTIFIER_ANON_P(NODE) \
> @@ -5120,6 +5125,7 @@ extern const_tree strip_invariant_refs (const_tree);
> extern tree lhd_gcc_personality (void);
> extern void assign_assembler_name_if_needed (tree);
> extern bool warn_deprecated_use (tree, tree);
> +extern void error_unavailable_use (tree, tree);
> extern void cache_integer_cst (tree);
> extern const char *combined_fn_name (combined_fn);
>
> -- 
> 2.24.1



  reply	other threads:[~2020-11-27 20:50 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <D12096AB-DAFD-4B69-B448-DAC32A851B40@sandoe.co.uk>
2020-11-10  7:54 ` [PATCH] " Richard Biener
2020-11-10 11:20   ` Iain Sandoe
2020-11-10 11:58     ` Richard Biener
2020-11-10 15:33 ` Joseph Myers
2020-11-10 19:38   ` [PATCH v2] " Iain Sandoe
2020-11-27 20:49     ` Iain Sandoe [this message]
2020-11-30 13:27       ` PING^1 " Nathan Sidwell
2020-11-29 23:00     ` Martin Sebor
2020-11-30  1:56       ` Iain Sandoe
2020-11-30 17:04         ` Martin Sebor
2020-12-01 21:07           ` Iain Sandoe
2020-12-21 19:58             ` Iain Sandoe
2021-01-04 20:19               ` Joseph Myers

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=0D2814B3-E808-4E4E-A2DB-C3F810E8BB13@sandoe.co.uk \
    --to=iain@sandoe.co.uk \
    --cc=GCC-patches@gcc.gnu.org \
    --cc=jason@redhat.com \
    --cc=joseph@codesourcery.com \
    --cc=nathan@acm.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).