From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from smtp1.wavenetuk.net (smtp.wavenetuk.net [195.26.36.10]) by sourceware.org (Postfix) with ESMTP id A204D385042C for ; Tue, 10 Nov 2020 11:21:53 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org A204D385042C 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 smtp1.wavenetuk.net (Postfix) with ESMTPA id 895D41202AD8; Tue, 10 Nov 2020 11:21:52 +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: Re: [PATCH] C-family : Add attribute 'unavailable'. From: Iain Sandoe In-Reply-To: Date: Tue, 10 Nov 2020 11:20:32 +0000 Cc: GCC-patches@gcc.gnu.org, Jason Merrill , Joseph Myers Content-Transfer-Encoding: 8bit Message-Id: <8F49B2BF-2BFA-45EB-B780-75F76AD271E0@sandoe.co.uk> References: To: Richard Biener X-Mailer: Apple Mail (2.3273) X-Spam-Status: No, score=-16.1 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_COUK, KAM_DMARC_STATUS, KAM_LAZY_DOMAIN_SECURITY, KHOP_HELO_FCRDNS, 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: Tue, 10 Nov 2020 11:22:01 -0000 Hi Richard, Richard Biener 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). > 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. 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 % 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/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 *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::> 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