On Tue, 10 Nov 2020, Iain Sandoe wrote:

> Hi Richard,
> 
> Richard Biener <rguent...@suse.de> wrote:
> 
> >On Mon, 9 Nov 2020, Iain Sandoe wrote:
> >
> >>Hi,
> >>
> >>I?ve been carrying this patch around on my Darwin branches for a very long
> >>time?
> >>
> >>tested across the Darwin patch and on x86_64-linux-gnu,
> >>OK for master?
> >>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:
> >>
> >>* lto-streamer-out.c (hash_tree): Stream TREE_UNAVAILABLE.
> >>* 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.
> >
> >Why'd you need to stream this in LTO, more specifically only handle
> >it in hashing?  It should be all frontend operation.
> 
> I followed the existing implementation for TREE_DEPRECATED ().
> 
> Presumably, that entry should also be removed - I will remove and re-test (it
> wasn?t
> obvious to me why the entry was present, the deprecation/unavailable stuff
> should
> be done by end of gimplification).

deprecated_flag is overloaded, we likely use this accessor because
it isn't guarded by any tree code check.  We definitely need the bit
for SSA_NAMEs.

> >You're targeting only DECLs can you use a bit from decl_common where decl
> >specific bits exist instead?
> 
> .. except that we are also targeting types.

Ah, I see, using a bit in tree-base is fine then.  Please document
its use in near to the other flags like

   deprecated_flag:

       TREE_DEPRECATED in
           all decls
           all types

so overloads can be added for other tree kinds.

Richard.

> We could use a bit in decl_common for decls and in tree_type_common for types,
> I suppose, but that would then mean that every test for unavailable would grow
> an
> additional check to discriminate.
> 
> (if we do that, then presumably, as a separate patch, we might as well move
> TREE_DEPRECATED in the same way - since otherwise the impl. is different for
> no obvious reason).
>
> thanks
> Iain
> 
> 
> >
> >Thanks,
> >Richard.
> >
> >>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/lto-streamer-out.c | 1 +
> >>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, 1302 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/lto-streamer-out.c b/gcc/lto-streamer-out.c
> >>index 0ca2796da9c..2c164daf3b4 100644
> >>--- a/gcc/lto-streamer-out.c
> >>+++ b/gcc/lto-streamer-out.c
> >>@@ -1212,6 +1212,7 @@ hash_tree (struct streamer_tree_cache_d *cache,
> >>hash_map<tree, hashval_t> *map,
> >>hstate.add_flag (TREE_STATIC (t));
> >>hstate.add_flag (TREE_PROTECTED (t));
> >>hstate.add_flag (TREE_DEPRECATED (t));
> >>+ hstate.add_flag (TREE_UNAVAILABLE (t));
> >>if (code != TREE_BINFO)
> >>hstate.add_flag (TREE_PRIVATE (t));
> >>if (TYPE_P (t))
> >>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..2d074280407 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;
> >>
> >>@@ -1370,6 +1371,13 @@ struct GTY(()) tree_base {
> >>
> >>CALL_EXPR_BY_DESCRIPTOR in
> >>CALL_EXPR
> >>+
> >>+ unavailable_flag:
> >>+
> >>+ TREE_UNAVAILABLE in
> >>+ all decls
> >>+ all types
> >>+
> >>*/
> >>
> >>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
> >
> >-- 
> >Richard Biener <rguent...@suse.de>
> >SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
> >Germany; GF: Felix Imend
> 
> 

-- 
Richard Biener <rguent...@suse.de>
SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
Germany; GF: Felix Imend

Reply via email to