From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from smtp2.wavenetuk.net (unknown [195.26.37.10]) by sourceware.org (Postfix) with ESMTP id 81A373858010 for ; Fri, 27 Nov 2020 20:50:57 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 81A373858010 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=sandoe.co.uk Authentication-Results: sourceware.org; spf=none smtp.mailfrom=iain@sandoe.co.uk Received: from [192.168.1.212] (host81-138-1-83.in-addr.btopenworld.com [81.138.1.83]) by smtp2.wavenetuk.net (Postfix) with ESMTPA id B2A60600136; Fri, 27 Nov 2020 20:50:55 +0000 (GMT) Content-Type: text/plain; charset=utf-8; delsp=yes; format=flowed Mime-Version: 1.0 (Mac OS X Mail 10.3 \(3273\)) Subject: PING^1 Re: [PATCH v2] C-family : Add attribute 'unavailable'. From: Iain Sandoe In-Reply-To: <1DC1B5BE-1FCE-4E55-9F91-96A475D0CA84@sandoe.co.uk> Date: Fri, 27 Nov 2020 20:49:46 +0000 Cc: Jason Merrill , Nathan Sidwell , Joseph Myers Content-Transfer-Encoding: 8bit Message-Id: <0D2814B3-E808-4E4E-A2DB-C3F810E8BB13@sandoe.co.uk> References: <1DC1B5BE-1FCE-4E55-9F91-96A475D0CA84@sandoe.co.uk> To: GCC Patches X-Mailer: Apple Mail (2.3273) X-Spam-Status: No, score=-14.5 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_COUK, KAM_DMARC_STATUS, KAM_LAZY_DOMAIN_SECURITY, KHOP_HELO_FCRDNS, MAY_BE_FORGED, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 27 Nov 2020 20:51:05 -0000 Hi I believe this version addressed Joseph’s and Richard’s comment, but it C++ review. thanks Iain Iain Sandoe wrote: > Joseph Myers 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 % 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 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:: 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:: 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 struct __attribute__ ((unavailable)) S {}; > +S s; > + > +template