diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c index e60fb31d8c8ea16ad1ba7e88de29f12edf9d3d93..d14e9c441b39b0c534c8ecbadb9eda281db30704 100644 --- a/gcc/c-family/c-attribs.c +++ b/gcc/c-family/c-attribs.c @@ -123,6 +123,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 *); @@ -406,6 +408,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, @@ -4122,6 +4126,71 @@ handle_deprecated_attribute (tree *node, tree name, return NULL_TREE; } +/* Handle a "unavailable" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_unavailable_attribute (tree *node, tree name, + tree args, int flags, + bool *no_add_attrs) +{ + tree type = NULL_TREE; + int warn = 0; + tree what = NULL_TREE; + + if (!args) + *no_add_attrs = true; + else if (TREE_CODE (TREE_VALUE (args)) != STRING_CST) + { + error ("the message attached to %<unavailable%> is not a string"); + *no_add_attrs = true; + } + + if (DECL_P (*node)) + { + tree decl = *node; + type = TREE_TYPE (decl); + + if (TREE_CODE (decl) == TYPE_DECL + || TREE_CODE (decl) == PARM_DECL + || VAR_OR_FUNCTION_DECL_P (decl) + || TREE_CODE (decl) == FIELD_DECL + || TREE_CODE (decl) == CONST_DECL + || objc_method_decl (TREE_CODE (decl))) + TREE_UNAVAILABLE (decl) = 1; + else + warn = 1; + } + else if (TYPE_P (*node)) + { + if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) + *node = build_variant_type_copy (*node); + TREE_UNAVAILABLE (*node) = 1; + type = *node; + } + else + warn = 1; + + if (warn) + { + *no_add_attrs = true; + if (type && TYPE_NAME (type)) + { + if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE) + what = TYPE_NAME (*node); + else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL + && DECL_NAME (TYPE_NAME (type))) + what = DECL_NAME (TYPE_NAME (type)); + } + if (what) + warning (OPT_Wattributes, "%qE attribute ignored for %qE", name, what); + else + warning (OPT_Wattributes, "%qE attribute ignored", name); + } + + return NULL_TREE; +} + /* Return the "base" type from TYPE that is suitable to apply attribute vector_size to by stripping arrays, function types, etc. */ static tree diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index 3482d82fae1af730523dc2d3daaddea3df43c2eb..771efa3eadfdcb512166f26377e8c1d25a30514f 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -73,13 +73,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 }; @@ -2644,6 +2647,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 @@ -4892,6 +4899,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 @@ -5094,9 +5102,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, @@ -6233,7 +6246,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 @@ -6363,8 +6376,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 @@ -10814,6 +10833,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 a8a90eae30d54006e83b20cdcc7aa7a582686c6c..d50d0cb7f2df5684bd2d199824db1aae124cc945 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 d9f26d67bd33fad5e68e48a04989deac5ecd4658..5849c5ab23d321a065fb3cdf4085a1a14d1beaa3 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -2558,7 +2558,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; @@ -2843,7 +2845,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 80e6121ce440d27a6ae0d48dd2289b4edd2a6cff..7bbf1342ef89b7bc546d7d765ab25b49c8f2c1ae 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -9506,7 +9506,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 (eliding_temp && DECL_BASE_CONSTRUCTOR_P (fn) && !make_base_init_ok (arg)) @@ -9580,7 +9580,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) suppress_warning (val, OPT_Wunused); } - 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 7138e304937631c5b858066d5b88e0f87ea1eeb6..17876c724ab5938c4d8803fed35ca6250cf5e409 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -5719,6 +5719,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; } @@ -5747,6 +5748,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 f0a7bd24df725fd34240be9608513ffaea408177..435f32bf90914c4455752283890fa54a3c28f7bd 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6549,7 +6549,7 @@ extern void validate_conversion_obstack (void); extern void mark_versions_used (tree); extern int unsafe_return_slot_p (tree); extern bool make_safe_copy_elision (tree, 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 e981eadc6dd84f9711f6afef9e04afd16785a9f0..146979ba96b336a8c7ea87081604b474731bf1f7 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -2418,6 +2418,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) { @@ -11757,20 +11761,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. */ auto ds = make_temp_override (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. */ @@ -14417,6 +14425,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. @@ -14476,11 +14521,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 387d807a5cf226ed99cda341287c28f2581150eb..4a9b399730a9c8d85479224ddd5fb3bd6c3ffb60 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 0c9d2f468a02f2a487f3811f86e98c21e28ecc38..107edcaaccfcaf7bf1fce830eb6a526ea06aedf0 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -1635,6 +1635,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 @@ -5498,14 +5509,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)) @@ -5565,7 +5609,7 @@ cp_warn_deprecated_use_scopes (tree scope) && scope != global_namespace) { if ((TREE_CODE (scope) == NAMESPACE_DECL || OVERLOAD_TYPE_P (scope)) - && cp_warn_deprecated_use (scope)) + && cp_handle_deprecated_or_unavailable (scope)) return; if (TYPE_P (scope)) scope = CP_TYPE_CONTEXT (scope); @@ -5677,7 +5721,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 d3c31be0967090a24f22e60679c8f3d371976bfd..ea71f9ca91a61d1e28420658d83272dd75ce6f33 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -18428,18 +18428,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 @@ -18690,7 +18698,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; } @@ -24351,9 +24361,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 && !cp_parser_error_occurred (parser)) { diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index a46c6d2340dd67556699c6db3b2e8f0c94e62016..cc61b509f8a5552b5c88a29675dd88c37713708b 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -2709,7 +2709,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 @@ -3424,7 +3427,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 5e2c23c063cc0f5dee99a41daf6ca49839368d47..f78dbf238afcbb4b10533bd5768e8b9e7517ac8e 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -2163,7 +2163,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 251a10302b4f7a34fc1468119349956cca5daf25..e9ca48cecb62c23c28e54af9ac2a8f038ab19ae8 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{unavailable} 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 @@ -7402,6 +7415,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 @@ -8461,6 +8490,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 @@ -8938,6 +8978,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 6e4fb626936f9937bcfba576c043ddd1e7fbc36e..9baa46d2243af6d3c682b94499944893c728041d 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -1302,6 +1302,7 @@ objc_add_property_declaration (location_t location, tree decl, TREE_TYPE (property_decl) = p_type; 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); @@ -1439,6 +1440,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 @@ -1717,7 +1719,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 @@ -1751,10 +1753,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; @@ -1804,7 +1806,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); } @@ -1816,17 +1820,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; @@ -4598,6 +4602,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; } } @@ -5023,6 +5029,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)) { @@ -5488,9 +5495,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 @@ -5499,7 +5506,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; @@ -5811,10 +5818,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); } @@ -6986,7 +7000,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; @@ -7096,7 +7112,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; @@ -7127,7 +7145,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); @@ -8154,6 +8174,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; } @@ -8198,6 +8219,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; } } @@ -8251,7 +8273,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 @@ -8276,6 +8300,7 @@ void objc_declare_protocol (tree name, tree attributes) { bool deprecated = false; + bool unavailable = false; #ifdef OBJCPLUS if (current_namespace != global_namespace) { @@ -8294,6 +8319,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); } @@ -8318,6 +8345,8 @@ objc_declare_protocol (tree name, tree attributes) TYPE_ATTRIBUTES (protocol) = attributes; if (deprecated) TREE_DEPRECATED (protocol) = 1; + if (unavailable) + TREE_UNAVAILABLE (protocol) = 1; } } } @@ -8327,6 +8356,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) { @@ -8345,6 +8375,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); } @@ -8384,6 +8416,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; @@ -8913,6 +8947,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 @@ -9644,12 +9680,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 8ad0dcfbbf01e4e573f1e9804e0c104b9f45882d..d1fbd044c27bc245f35c29fd62e8caf5d9de0316 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 0000000000000000000000000000000000000000..862651f6cbf6358ed1203ac855c2725314f46d6c --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/attr-unavailable-1.C @@ -0,0 +1,113 @@ +/* Test __attribute__ ((unavailable)) */ +/* { dg-do compile } */ +/* { dg-options "" } */ + +typedef int INT1 __attribute__((unavailable)); +typedef INT1 INT2 __attribute__ ((__unavailable__)); + +typedef INT1 INT1a; /* { dg-error "'INT1' is unavailable" "" } */ +typedef INT1 INT1b __attribute__ ((unavailable)); + +INT1 should_be_unavailable; /* { dg-error "'INT1' is unavailable" "" } */ +INT1a should_not_be_unavailable; + +INT1 f1(void) __attribute__ ((unavailable)); +INT1 f2(void) { return 0; } /* { dg-error "'INT1' is unavailable" "" } */ + +INT2 f3(void) __attribute__ ((__unavailable__)); +INT2 f4(void) { return 0; } /* { dg-error "'INT2' is unavailable" "" } */ +int f5(INT2 x); /* { dg-error "'INT2' is unavailable" "" } */ +int f6(INT2 x) __attribute__ ((__unavailable__)); + +typedef enum Color {red, green, blue} Color __attribute__((unavailable)); + +int g1; +int g2 __attribute__ ((unavailable)); +int g3 __attribute__ ((__unavailable__)); +Color k; /* { dg-error "'Color' is unavailable" "" } */ + +typedef struct { + int field1; + int field2 __attribute__ ((unavailable)); + int field3; + int field4 __attribute__ ((__unavailable__)); + union { + int field5; + int field6 __attribute__ ((unavailable)); + } u1; + int field7:1; + int field8:1 __attribute__ ((unavailable)); + union { + int field9; + int field10; + } u2 __attribute__ ((unavailable)); +} S1; + +int func1() +{ + INT1 w; /* { dg-error "'INT1' is unavailable" "" } */ + int x __attribute__ ((unavailable)); + int y __attribute__ ((__unavailable__)); + int z; + int (*pf)() = f1; /* { dg-error "'INT1 f1\\(\\)' is unavailable" "" } */ + + z = w + x + y + g1 + g2 + g3; /* { dg-error "'x' is unavailable" "" } */ + /* { dg-error "'y' is unavailable" "y" { target *-*-* } .-1 } */ + /* { dg-error "'g2' is unavailable" "g2" { target *-*-* } .-2 } */ + /* { dg-error "'g3' is unavailable" "g3" { target *-*-* } .-3 } */ + return f1(); /* { dg-error "'INT1 f1\\(\\)' is unavailable" "f1" } */ +} + +int func2(S1 *p) +{ + S1 lp; + + if (p->field1) + return p->field2; /* { dg-error "'S1::field2' is unavailable" "" } */ + else if (lp.field4) /* { dg-error "'S1::field4' is unavailable" "" } */ + return p->field3; + + p->u1.field5 = g1 + p->field7; + p->u2.field9; /* { dg-error "'S1::u2' is unavailable" "" } */ + return p->u1.field6 + p->field8; /* { dg-error "'S1::<unnamed union>::field6' is unavailable" "" } */ + /* { dg-error "'S1::field8' is unavailable" "field8" { target *-*-* } .-1 } */ +} + +struct SS1 { + int x; + INT1 y; /* { dg-error "'INT1' is unavailable" "" } */ +} __attribute__ ((unavailable)); + +struct SS1 *p1; /* { dg-error "'SS1' is unavailable" "" } */ + +struct __attribute__ ((__unavailable__)) SS2 { + int x; + INT1 y; /* { dg-error "'INT1' is unavailable" "" } */ +}; + +struct SS2 *p2; /* { dg-error "'SS2' is unavailable" "" } */ + +#ifdef __cplusplus +class T { + public: + void member1(int) __attribute__ ((unavailable)); + void member2(INT1) __attribute__ ((__unavailable__)); + int member3(T *); + int x; +} __attribute__ ((unavailable)); + +T *p3; // { dg-error "'T' is unavailable" } + +inline void T::member1(int) {} + +int T::member3(T *p) // { dg-error "'T' is unavailable" } +{ + p->member1(1); /* { dg-error "'void T::member1\\(int\\)' is unavailable" "" } */ + (*p).member1(2); /* { dg-error "'void T::member1\\(int\\)' is unavailable" "" } */ + p->member2(1); /* { dg-error "'void T::member2\\(INT1\\)' is unavailable" "" } */ + (*p).member2(2); /* { dg-error "'void T::member2\\(INT1\\)' is unavailable" "" } */ + p->member3(p); + (*p).member3(p); + return f1(); /* { dg-error "'INT1 f1\\(\\)' is unavailable" "" } */ +} +#endif diff --git a/gcc/testsuite/g++.dg/ext/attr-unavailable-2.C b/gcc/testsuite/g++.dg/ext/attr-unavailable-2.C new file mode 100644 index 0000000000000000000000000000000000000000..3de5532817e1aedefae163db57be5b3c9231dbfd --- /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 0000000000000000000000000000000000000000..1f267ea78c4b54192f2d203ee1bf71ff5ba24297 --- /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 0000000000000000000000000000000000000000..b7f352ee3bd285b12db032a4c4ac10762f629668 --- /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 0000000000000000000000000000000000000000..3beea5d22c5ec872d942eede91a001069b1a7f52 --- /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 0000000000000000000000000000000000000000..8a57ea0d88c438e1d7a511a3656e322f8bf09f70 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/attr-unavailable-6.C @@ -0,0 +1,110 @@ +/* Test __attribute__ ((unavailable)) */ +/* { dg-do compile } */ +/* { dg-options "" } */ + +typedef int INT1 __attribute__((unavailable("You can't use INT1"))); +typedef INT1 INT2 __attribute__ ((__unavailable__("You can't use INT2"))); + +typedef INT1 INT1a; /* { dg-error "'INT1' is unavailable: You can't use INT1" "" } */ + +INT1 should_be_unavailable; /* { dg-error "'INT1' is unavailable: You can't use INT1" "" } */ +INT1a should_not_be_unavailable; + +INT1 f1(void) __attribute__ ((unavailable("You can't use f1"))); +INT1 f2(void) { return 0; } /* { dg-error "'INT1' is unavailable: You can't use INT1" "" } */ + +INT2 f3(void) __attribute__ ((__unavailable__("You can't use f3"))); +INT2 f4(void) { return 0; } /* { dg-error "'INT2' is unavailable: You can't use INT2" "" } */ +int f5(INT2 x); /* { dg-error "'INT2' is unavailable" "" } */ +int f6(INT2 x) __attribute__ ((__unavailable__("You can't use f6"))); + +typedef enum Color {red, green, blue} Color __attribute__((unavailable("You can't use Color"))); + +int g1; +int g2 __attribute__ ((unavailable("You can't use g2"))); +int g3 __attribute__ ((__unavailable__("You can't use g3"))); +Color k; /* { dg-error "'Color' is unavailable: You can't use Color" "" } */ + +typedef struct { + int field1; + int field2 __attribute__ ((unavailable("You can't use field2"))); + int field3; + int field4 __attribute__ ((__unavailable__("You can't use field4"))); + union { + int field5; + int field6 __attribute__ ((unavailable("You can't use field6"))); + } u1; + int field7:1; + int field8:1 __attribute__ ((unavailable("You can't use field8"))); + union { + int field9; + int field10; + } u2 __attribute__ ((unavailable("You can't use u2"))); +} S1; + +int func1() +{ + INT1 w; /* { dg-error "'INT1' is unavailable: You can't use INT1" "" } */ + int x __attribute__ ((unavailable("You can't use x"))); + int y __attribute__ ((__unavailable__("You can't use y"))); + int z; + int (*pf)() = f1; /* { dg-error "'INT1 f1\\(\\)' is unavailable: You can't use f1" "" } */ + + z = w + x + y + g1 + g2 + g3; /* { dg-error "'x' is unavailable: You can't use x" "" } */ + /* { dg-error "'y' is unavailable: You can't use y" "y" { target *-*-* } .-1 } */ + /* { dg-error "'g2' is unavailable: You can't use g2" "g2" { target *-*-* } .-2 } */ + /* { dg-error "'g3' is unavailable: You can't use g3" "g3" { target *-*-* } .-3 } */ + return f1(); /* { dg-error "'INT1 f1\\(\\)' is unavailable: You can't use f1" "f1" } */ +} + +int func2(S1 *p) +{ + S1 lp; + + if (p->field1) + return p->field2; /* { dg-error "'S1::field2' is unavailable: You can't use field2" "" } */ + else if (lp.field4) /* { dg-error "'S1::field4' is unavailable: You can't use field4" "" } */ + return p->field3; + + p->u1.field5 = g1 + p->field7; + p->u2.field9; /* { dg-error "'S1::u2' is unavailable: You can't use u2" "" } */ + return p->u1.field6 + p->field8; /* { dg-error "'S1::<unnamed union>::field6' is unavailable: You can't use field6" "" } */ + /* { dg-error "'S1::field8' is unavailable: You can't use field8" "field8" { target *-*-* } .-1 } */ +} + +struct SS1 { + int x; + INT1 y; /* { dg-error "'INT1' is unavailable: You can't use INT1" "" } */ +} __attribute__ ((unavailable("You can't use SS1"))); + +struct SS1 *p1; /* { dg-error "'SS1' is unavailable: You can't use SS1" "" } */ + +struct __attribute__ ((__unavailable__("You can't use SS2"))) SS2 { + int x; + INT1 y; /* { dg-error "'INT1' is unavailable: You can't use INT1" "" } */ +}; + +struct SS2 *p2; /* { dg-error "'SS2' is unavailable: You can't use SS2" "" } */ + +class T { + public: + void member1(int) __attribute__ ((unavailable("You can't use member1"))); + void member2(INT1) __attribute__ ((__unavailable__("You can't use member2"))); + int member3(T *); + int x; +} __attribute__ ((unavailable("You can't use T"))); + +T *p3; // { dg-error "'T' is unavailable: You can't use T" } + +inline void T::member1(int) {} + +int T::member3(T *p) // { dg-error "'T' is unavailable: You can't use T" } +{ + p->member1(1); /* { dg-error "'void T::member1\\(int\\)' is unavailable: You can't use member1" "" } */ + (*p).member1(2); /* { dg-error "'void T::member1\\(int\\)' is unavailable: You can't use member1" "" } */ + p->member2(1); /* { dg-error "'void T::member2\\(INT1\\)' is unavailable: You can't use member2" "" } */ + (*p).member2(2); /* { dg-error "'void T::member2\\(INT1\\)' is unavailable: You can't use member2" "" } */ + p->member3(p); + (*p).member3(p); + return f1(); /* { dg-error "'INT1 f1\\(\\)' is unavailable: You can't use f1" "" } */ +} diff --git a/gcc/testsuite/g++.dg/ext/attr-unavailable-7.C b/gcc/testsuite/g++.dg/ext/attr-unavailable-7.C new file mode 100644 index 0000000000000000000000000000000000000000..c061aa3b6a2e73a0db75fce7663cc79ba254bf33 --- /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 0000000000000000000000000000000000000000..334a2cf72862c51d97cad3da88329fa59869ab54 --- /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 0000000000000000000000000000000000000000..44161336e78156fb8d6be68acd08ec1e8ab11a22 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/attr-unavailable-9.C @@ -0,0 +1,17 @@ +/* Test __attribute__ ((unavailable)) */ +/* { dg-do compile } */ +/* { dg-options "" } */ + +template<typename T> struct __attribute__ ((unavailable)) S {}; +S<int> s; + +template <template <class> class T> struct A { }; +A<S> a; + +template <class T> void f() __attribute__ ((unavailable)); + +int main() +{ + f<int>(); // { dg-error "unavailable" } + void (*p)() = f<char>; // { dg-error "unavailable" } +} diff --git a/gcc/testsuite/gcc.dg/attr-unavailable-1.c b/gcc/testsuite/gcc.dg/attr-unavailable-1.c new file mode 100644 index 0000000000000000000000000000000000000000..768214fcd3ac84c82a338e57add2fb3e1cfcd70b --- /dev/null +++ b/gcc/testsuite/gcc.dg/attr-unavailable-1.c @@ -0,0 +1,88 @@ +/* Test __attribute__ ((unavailable)) */ +/* { dg-do compile } */ +/* { dg-options "" } */ + +typedef int INT1 __attribute__((unavailable)); +typedef INT1 INT2 __attribute__ ((__unavailable__)); + +typedef INT1 INT1a; /* { dg-error "'INT1' is unavailable" "" } */ +typedef INT1 INT1b __attribute__ ((unavailable)); + +INT1 should_be_unavailable; /* { dg-error "'INT1' is unavailable" "" } */ +INT1a should_not_be_unavailable; + +INT1 f1(void) __attribute__ ((unavailable)); +INT1 f2(void) { return 0; } /* { dg-error "'INT1' is unavailable" "" } */ + +INT2 f3(void) __attribute__ ((__unavailable__)); +INT2 f4(void) { return 0; } /* { dg-error "'INT2' is unavailable" "" } */ +int f5(INT2 x); /* { dg-error "'INT2' is unavailable" "" } */ +int f6(INT2 x) __attribute__ ((__unavailable__)); /* { dg-error "'INT2' is unavailable" "" } */ + +typedef enum {red, green, blue} Color __attribute__((unavailable)); + +int g1; +int g2 __attribute__ ((unavailable)); +int g3 __attribute__ ((__unavailable__)); +Color k; /* { dg-error "'Color' is unavailable" "" } */ + +typedef struct { + int field1; + int field2 __attribute__ ((unavailable)); + int field3; + int field4 __attribute__ ((__unavailable__)); + union { + int field5; + int field6 __attribute__ ((unavailable)); + } u1; + int field7:1; + int field8:1 __attribute__ ((unavailable)); + union { + int field9; + int field10; + } u2 __attribute__ ((unavailable)); +} S1; + +int func1() +{ + INT1 w; /* { dg-error "'INT1' is unavailable" "" } */ + int x __attribute__ ((unavailable)); + int y __attribute__ ((__unavailable__)); + int z; + int (*pf)() = f1; /* { dg-error "'f1' is unavailable" "" } */ + + z = w + x + y + g1 + g2 + g3; /* { dg-error "'x' is unavailable" "" } */ + /* { dg-error "'y' is unavailable" "y" { target *-*-* } .-1 } */ + /* { dg-error "'g2' is unavailable" "g2" { target *-*-* } .-2 } */ + /* { dg-error "'g3' is unavailable" "g3" { target *-*-* } .-3 } */ + return f1(); /* { dg-error "'f1' is unavailable" "f1" } */ +} + +int func2(S1 *p) +{ + S1 lp; + + if (p->field1) + return p->field2; /* { dg-error "'field2' is unavailable" "" } */ + else if (lp.field4) /* { dg-error "'field4' is unavailable" "" } */ + return p->field3; + + p->u1.field5 = g1 + p->field7; + p->u2.field9; /* { dg-error "'u2' is unavailable" "" } */ + return p->u1.field6 + p->field8; /* { dg-error "'field6' is unavailable" "" } */ + /* { dg-error "'field8' is unavailable" "field8" { target *-*-* } .-1 } */ +} + +struct SS1 { + int x; + INT1 y; /* { dg-error "'INT1' is unavailable" "" } */ +} __attribute__ ((unavailable)); + +struct SS1 *p1; /* { dg-error "'SS1' is unavailable" "" } */ + +struct __attribute__ ((__unavailable__)) SS2 { + int x; + INT1 y; /* { dg-error "'INT1' is unavailable" "" } */ +}; + +struct SS2 *p2; /* { dg-error "'SS2' is unavailable" "" } */ diff --git a/gcc/testsuite/gcc.dg/attr-unavailable-2.c b/gcc/testsuite/gcc.dg/attr-unavailable-2.c new file mode 100644 index 0000000000000000000000000000000000000000..303f973d5db02b9f8325d506e291f8025b8aa560 --- /dev/null +++ b/gcc/testsuite/gcc.dg/attr-unavailable-2.c @@ -0,0 +1,6 @@ +/* Test __attribute__((unavailable)). Test types without names. */ +/* { dg-do compile } */ +/* { dg-options "" } */ + +struct { int a; } __attribute__((unavailable)) x; /* { dg-error "type is unavailable" } */ +typeof(x) y; /* { dg-error "type is unavailable" } */ diff --git a/gcc/testsuite/gcc.dg/attr-unavailable-3.c b/gcc/testsuite/gcc.dg/attr-unavailable-3.c new file mode 100644 index 0000000000000000000000000000000000000000..7274c193f3fb9b1d31a8ab3bf549b9e148a5de7f --- /dev/null +++ b/gcc/testsuite/gcc.dg/attr-unavailable-3.c @@ -0,0 +1,10 @@ +/* Test __attribute__((unavailable)). */ +/* { dg-do compile } */ +/* { dg-options "" } */ + +void func(void); +void func(void) __attribute__((unavailable)); + +void f(void) { + func(); /* { dg-error "'func' is unavailable" } */ +} diff --git a/gcc/testsuite/gcc.dg/attr-unavailable-4.c b/gcc/testsuite/gcc.dg/attr-unavailable-4.c new file mode 100644 index 0000000000000000000000000000000000000000..9e39c50fec6ea497cb2bd96679aede02f712ca08 --- /dev/null +++ b/gcc/testsuite/gcc.dg/attr-unavailable-4.c @@ -0,0 +1,88 @@ +/* Test __attribute__ ((unavailable("message"))) */ +/* { dg-do compile } */ +/* { dg-options "" } */ + +typedef int INT1 __attribute__((unavailable("You can't use INT1"))); +typedef INT1 INT2 __attribute__ ((__unavailable__("You can't use INT2"))); + +typedef INT1 INT1a; /* { dg-error "'INT1' is unavailable: You can't use INT1" "" } */ +typedef INT1 INT1b __attribute__ ((unavailable("You can't use INT1b"))); + +INT1 should_be_unavailable; /* { dg-error "'INT1' is unavailable: You can't use INT1" "" } */ +INT1a should_not_be_unavailable; + +INT1 f1(void) __attribute__ ((unavailable("You can't use f1"))); +INT1 f2(void) { return 0; } /* { dg-error "'INT1' is unavailable: You can't use INT1" "" } */ + +INT2 f3(void) __attribute__ ((__unavailable__("You can't use f3"))); +INT2 f4(void) { return 0; } /* { dg-error "'INT2' is unavailable: You can't use INT2" "" } */ +int f5(INT2 x); /* { dg-error "'INT2' is unavailable: You can't use INT2" "" } */ +int f6(INT2 x) __attribute__ ((__unavailable__("You can't use f6"))); /* { dg-error "'INT2' is unavailable: You can't use INT2" "" } */ + +typedef enum {red, green, blue} Color __attribute__((unavailable("You can't use Color"))); + +int g1; +int g2 __attribute__ ((unavailable("You can't use g2"))); +int g3 __attribute__ ((__unavailable__("You can't use g3"))); +Color k; /* { dg-error "'Color' is unavailable: You can't use Color" "" } */ + +typedef struct { + int field1; + int field2 __attribute__ ((unavailable("You can't use field2"))); + int field3; + int field4 __attribute__ ((__unavailable__("You can't use field4"))); + union { + int field5; + int field6 __attribute__ ((unavailable("You can't use field6"))); + } u1; + int field7:1; + int field8:1 __attribute__ ((unavailable("You can't use field8"))); + union { + int field9; + int field10; + } u2 __attribute__ ((unavailable("You can't use u2"))); +} S1; + +int func1() +{ + INT1 w; /* { dg-error "'INT1' is unavailable: You can't use INT1" "" } */ + int x __attribute__ ((unavailable("Avoid x"))); + int y __attribute__ ((__unavailable__("Bad y"))); + int z; + int (*pf)() = f1; /* { dg-error "'f1' is unavailable: You can't use f1" "" } */ + + z = w + x + y + g1 + g2 + g3; /* { dg-error "'x' is unavailable: Avoid x" "" } */ + /* { dg-error "'y' is unavailable: Bad y" "y" { target *-*-* } .-1 } */ + /* { dg-error "'g2' is unavailable: You can't use g2" "g2" { target *-*-* } .-2 } */ + /* { dg-error "'g3' is unavailable: You can't use g3" "g3" { target *-*-* } .-3 } */ + return f1(); /* { dg-error "'f1' is unavailable: You can't use f1" "" } */ +} + +int func2(S1 *p) +{ + S1 lp; + + if (p->field1) + return p->field2; /* { dg-error "'field2' is unavailable: You can't use field2" "" } */ + else if (lp.field4) /* { dg-error "'field4' is unavailable: You can't use field4" "" } */ + return p->field3; + + p->u1.field5 = g1 + p->field7; + p->u2.field9; /* { dg-error "'u2' is unavailable: You can't use u2" "" } */ + return p->u1.field6 + p->field8; /* { dg-error "'field6' is unavailable: You can't use field6" "" } */ + /* { dg-error "'field8' is unavailable: You can't use field8" "field8" { target *-*-* } .-1 } */ +} + +struct SS1 { + int x; + INT1 y; /* { dg-error "'INT1' is unavailable: You can't use INT1" "" } */ +} __attribute__ ((unavailable("You can't use SS1"))); + +struct SS1 *p1; /* { dg-error "'SS1' is unavailable: You can't use SS1" "" } */ + +struct __attribute__ ((__unavailable__("You can't use SS2"))) SS2 { + int x; + INT1 y; /* { dg-error "'INT1' is unavailable: You can't use INT1" "" } */ +}; + +struct SS2 *p2; /* { dg-error "'SS2' is unavailable: You can't use SS2" "" } */ diff --git a/gcc/testsuite/gcc.dg/attr-unavailable-5.c b/gcc/testsuite/gcc.dg/attr-unavailable-5.c new file mode 100644 index 0000000000000000000000000000000000000000..051f960c5cf93d234e0abb272da7b09e2f6016a1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/attr-unavailable-5.c @@ -0,0 +1,6 @@ +/* Test __attribute__((unavailable)). Test types without names. */ +/* { dg-do compile } */ +/* { dg-options "" } */ + +struct { int a; } __attribute__((unavailable ("Do not use"))) x; /* { dg-error "type is unavailable" } */ +typeof(x) y; /* { dg-error "type is unavailable: Do not use" } */ diff --git a/gcc/testsuite/gcc.dg/attr-unavailable-6.c b/gcc/testsuite/gcc.dg/attr-unavailable-6.c new file mode 100644 index 0000000000000000000000000000000000000000..f5f4560c73507c1d9a39b6fb66faf0d98f1fa655 --- /dev/null +++ b/gcc/testsuite/gcc.dg/attr-unavailable-6.c @@ -0,0 +1,11 @@ +/* Test __attribute__((unavailable)). Test merging with multiple + declarations. */ +/* { dg-do compile } */ +/* { dg-options "" } */ + +void func(void); +void func(void) __attribute__((unavailable ("Do not use"))); + +void f(void) { + func(); /* { dg-error "'func' is unavailable: Do not use" } */ +} diff --git a/gcc/testsuite/obj-c++.dg/attributes/method-unavailable-1.mm b/gcc/testsuite/obj-c++.dg/attributes/method-unavailable-1.mm new file mode 100644 index 0000000000000000000000000000000000000000..e5708c202c07668d6ce120d36e9b23fe569b44a0 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/attributes/method-unavailable-1.mm @@ -0,0 +1,34 @@ +/* Test __attribute__ ((unavailable)) */ +/* { dg-do compile } */ +/* { dg-options "" } */ + +#include <objc/objc.h> + +@interface MyClass +{ + Class isa; +} ++ (int) method; +- (int) method; ++ (int) unavailableClassMethod __attribute__((unavailable)); +- (int) unavailableInstanceMethod __attribute__((unavailable)); +@end + +/* Test that deprecation warnings are produced, but not if the + receiver is of type 'id'. */ +void foo (void) +{ + Class c; + id object; + MyClass *another_object; + + [c method]; + [object method]; + [c unavailableClassMethod]; + [object unavailableInstanceMethod]; + + [object method]; + [another_object method]; + [MyClass unavailableClassMethod]; /* { dg-error "is unavailable" } */ + [another_object unavailableInstanceMethod]; /* { dg-error "is unavailable" } */ +} diff --git a/gcc/testsuite/obj-c++.dg/attributes/method-unavailable-2.mm b/gcc/testsuite/obj-c++.dg/attributes/method-unavailable-2.mm new file mode 100644 index 0000000000000000000000000000000000000000..68ea46d254309cdecff081daa9357a74e6d3f5ff --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/attributes/method-unavailable-2.mm @@ -0,0 +1,24 @@ +/* Test __attribute__ ((unavailable)) */ +/* { dg-do compile } */ +/* { dg-options "" } */ + +#include <objc/objc.h> + +@interface MyClass +{ + Class isa; +} ++ (int) unavailableClassMethod: (id)firstObject, ... __attribute__((sentinel)) __attribute__((unavailable)); +- (int) unavailableInstanceMethod: (id)firstobject, ... __attribute__((sentinel)) __attribute__((unavailable)); +@end + +/* Test that unavailability errors are produced even if the method is + also marked with another attribute too (this is to test the + processing of multiple attributes). */ +void foo (void) +{ + MyClass *object = nil; + + [MyClass unavailableClassMethod: object, nil]; /* { dg-error "is unavailable" } */ + [object unavailableInstanceMethod: object, nil]; /* { dg-error "is unavailable" } */ +} diff --git a/gcc/testsuite/obj-c++.dg/attributes/method-unavailable-3.mm b/gcc/testsuite/obj-c++.dg/attributes/method-unavailable-3.mm new file mode 100644 index 0000000000000000000000000000000000000000..9e55ae11e1fd10ea9a699a7456d2c6f928bdc85c --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/attributes/method-unavailable-3.mm @@ -0,0 +1,22 @@ +/* Test __attribute__ ((unavailable)) */ +/* { dg-do compile } */ +/* { dg-options "" } */ + +#include <objc/objc.h> + +/* Test that __attribute__ ((__unavailable__)) works as well as __attribute__ ((unavailable)). */ +@interface MyClass +{ + Class isa; +} ++ (int) unavailableClassMethod: (id)firstObject, ... __attribute__((__unavailable__)); +- (int) unavailableInstanceMethod: (id)firstobject, ... __attribute__((__unavailable__)); +@end + +void foo (void) +{ + MyClass *object = nil; + + [MyClass unavailableClassMethod: object, nil]; /* { dg-error "is unavailable" } */ + [object unavailableInstanceMethod: object, nil]; /* { dg-error "is unavailable" } */ +} diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-unavailable-1.mm b/gcc/testsuite/obj-c++.dg/property/at-property-unavailable-1.mm new file mode 100644 index 0000000000000000000000000000000000000000..6bb4755220d41f23c5c67265786e2a36c9afe184 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-unavailable-1.mm @@ -0,0 +1,38 @@ +/* Test __attribute__ ((unavailable)) */ +/* { dg-do compile } */ +/* { dg-options "" } */ + +/* Test that properties can be unavailable. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +@interface MyRootClass +{ + Class isa; + int a; +} +@property int a __attribute__((unavailable)); ++ (id) initialize; ++ (id) alloc; +- (id) init; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +@synthesize a; +@end + +int main (void) +{ + MyRootClass *object = [[MyRootClass alloc] init]; + + object.a = 40; /* { dg-error "is unavailable" } */ + if (object.a != 40) /* { dg-error "is unavailable" } */ + abort (); + + return (0); +} diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-unavailable-2.mm b/gcc/testsuite/obj-c++.dg/property/at-property-unavailable-2.mm new file mode 100644 index 0000000000000000000000000000000000000000..5edc1626c89790d2e0e6c5328faf0d1da7f2055d --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-unavailable-2.mm @@ -0,0 +1,26 @@ +/* Test __attribute__ ((unavailable)) */ +/* { dg-do compile } */ +/* { dg-options "" } */ + +/* Test that unavailability errors are produced when a setter/getter of + a @property is used directly. */ + +#include <objc/objc.h> + +@interface MyClass +{ + Class isa; + int variable; +} +@property (assign, nonatomic) int property __attribute__ ((unavailable)); +@end + +void foo (void) +{ + MyClass *object = nil; + + if ([object property] > 0) /* { dg-error "is unavailable" } */ + { + [object setProperty: 43]; /* { dg-error "is unavailable" } */ + } +} diff --git a/gcc/testsuite/obj-c++.dg/property/dotsyntax-unavailable-1.mm b/gcc/testsuite/obj-c++.dg/property/dotsyntax-unavailable-1.mm new file mode 100644 index 0000000000000000000000000000000000000000..e2ef2a5b23b36b04941ffb8ee0f49f08a1cf8091 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/dotsyntax-unavailable-1.mm @@ -0,0 +1,42 @@ +/* Test __attribute__ ((unavailable)) */ +/* { dg-do compile } */ +/* { dg-options "" } */ + +/* Test the 'dot syntax' with unavailable methods. */ + +#include <objc/objc.h> + +@interface MyClass +{ + Class isa; +} ++ (int) classCount __attribute__ ((unavailable)); ++ (void) setClassCount: (int)value __attribute__ ((unavailable)); + +- (int) count __attribute__ ((unavailable)); +- (void) setCount: (int)value __attribute__ ((unavailable)); + +- (int) classCount2; +- (void) setClassCount2: (int)value; + +- (int) count2; +- (void) setCount2: (int)value; +@end + +void foo (void) +{ + MyClass *object = nil; + + + if (object.count > 0) /* { dg-error "is unavailable" } */ + object.count = 20; /* { dg-error "is unavailable" } */ + + if (MyClass.classCount < -7) /* { dg-error "is unavailable" } */ + MyClass.classCount = 11; /* { dg-error "is unavailable" } */ + + if (object.classCount2 > 0) + object.classCount2 = 19; + + if (object.count2 < -7) + object.count2 = 74; +} diff --git a/gcc/testsuite/objc.dg/attributes/method-unavailable-1.m b/gcc/testsuite/objc.dg/attributes/method-unavailable-1.m new file mode 100644 index 0000000000000000000000000000000000000000..7a3de6b245dc013c68472ea1476ace4e64b062a4 --- /dev/null +++ b/gcc/testsuite/objc.dg/attributes/method-unavailable-1.m @@ -0,0 +1,34 @@ +/* Test __attribute__ ((unavailable)) */ +/* { dg-do compile } */ +/* { dg-options "" } */ + +#include <objc/objc.h> + +@interface MyClass +{ + Class isa; +} ++ (int) method; +- (int) method; ++ (int) unavailableClassMethod __attribute__((unavailable)); +- (int) unavailableInstanceMethod __attribute__((unavailable)); +@end + +/* Test that unavailability errors are produced, but not if the + receiver is of type 'id'. */ +void foo (void) +{ + Class c; + id object; + MyClass *another_object; + + [c method]; + [object method]; + [c unavailableClassMethod]; + [object unavailableInstanceMethod]; + + [object method]; + [another_object method]; + [MyClass unavailableClassMethod]; /* { dg-error "is unavailable" } */ + [another_object unavailableInstanceMethod]; /* { dg-error "is unavailable" } */ +} diff --git a/gcc/testsuite/objc.dg/attributes/method-unavailable-2.m b/gcc/testsuite/objc.dg/attributes/method-unavailable-2.m new file mode 100644 index 0000000000000000000000000000000000000000..68ea46d254309cdecff081daa9357a74e6d3f5ff --- /dev/null +++ b/gcc/testsuite/objc.dg/attributes/method-unavailable-2.m @@ -0,0 +1,24 @@ +/* Test __attribute__ ((unavailable)) */ +/* { dg-do compile } */ +/* { dg-options "" } */ + +#include <objc/objc.h> + +@interface MyClass +{ + Class isa; +} ++ (int) unavailableClassMethod: (id)firstObject, ... __attribute__((sentinel)) __attribute__((unavailable)); +- (int) unavailableInstanceMethod: (id)firstobject, ... __attribute__((sentinel)) __attribute__((unavailable)); +@end + +/* Test that unavailability errors are produced even if the method is + also marked with another attribute too (this is to test the + processing of multiple attributes). */ +void foo (void) +{ + MyClass *object = nil; + + [MyClass unavailableClassMethod: object, nil]; /* { dg-error "is unavailable" } */ + [object unavailableInstanceMethod: object, nil]; /* { dg-error "is unavailable" } */ +} diff --git a/gcc/testsuite/objc.dg/attributes/method-unavailable-3.m b/gcc/testsuite/objc.dg/attributes/method-unavailable-3.m new file mode 100644 index 0000000000000000000000000000000000000000..9e55ae11e1fd10ea9a699a7456d2c6f928bdc85c --- /dev/null +++ b/gcc/testsuite/objc.dg/attributes/method-unavailable-3.m @@ -0,0 +1,22 @@ +/* Test __attribute__ ((unavailable)) */ +/* { dg-do compile } */ +/* { dg-options "" } */ + +#include <objc/objc.h> + +/* Test that __attribute__ ((__unavailable__)) works as well as __attribute__ ((unavailable)). */ +@interface MyClass +{ + Class isa; +} ++ (int) unavailableClassMethod: (id)firstObject, ... __attribute__((__unavailable__)); +- (int) unavailableInstanceMethod: (id)firstobject, ... __attribute__((__unavailable__)); +@end + +void foo (void) +{ + MyClass *object = nil; + + [MyClass unavailableClassMethod: object, nil]; /* { dg-error "is unavailable" } */ + [object unavailableInstanceMethod: object, nil]; /* { dg-error "is unavailable" } */ +} diff --git a/gcc/testsuite/objc.dg/property/at-property-unavailable-1.m b/gcc/testsuite/objc.dg/property/at-property-unavailable-1.m new file mode 100644 index 0000000000000000000000000000000000000000..c33e1b6f4660904f1882ed9f71e6214466a9f957 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-unavailable-1.m @@ -0,0 +1,39 @@ +/* Test __attribute__ ((unavailable)) */ +/* { dg-do compile } */ +/* { dg-options "" } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ + +/* Test that properties can be unavailable. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +@interface MyRootClass +{ + Class isa; + int a; +} +@property int a __attribute__((unavailable)); ++ (id) initialize; ++ (id) alloc; +- (id) init; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +@synthesize a; +@end + +int main (void) +{ + MyRootClass *object = [[MyRootClass alloc] init]; + + object.a = 40; /* { dg-error "is unavailable" } */ + if (object.a != 40) /* { dg-error "is unavailable" } */ + abort (); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/property/at-property-unavailable-2.m b/gcc/testsuite/objc.dg/property/at-property-unavailable-2.m new file mode 100644 index 0000000000000000000000000000000000000000..5edc1626c89790d2e0e6c5328faf0d1da7f2055d --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-unavailable-2.m @@ -0,0 +1,26 @@ +/* Test __attribute__ ((unavailable)) */ +/* { dg-do compile } */ +/* { dg-options "" } */ + +/* Test that unavailability errors are produced when a setter/getter of + a @property is used directly. */ + +#include <objc/objc.h> + +@interface MyClass +{ + Class isa; + int variable; +} +@property (assign, nonatomic) int property __attribute__ ((unavailable)); +@end + +void foo (void) +{ + MyClass *object = nil; + + if ([object property] > 0) /* { dg-error "is unavailable" } */ + { + [object setProperty: 43]; /* { dg-error "is unavailable" } */ + } +} diff --git a/gcc/testsuite/objc.dg/property/dotsyntax-unavailable-1.m b/gcc/testsuite/objc.dg/property/dotsyntax-unavailable-1.m new file mode 100644 index 0000000000000000000000000000000000000000..e2ef2a5b23b36b04941ffb8ee0f49f08a1cf8091 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/dotsyntax-unavailable-1.m @@ -0,0 +1,42 @@ +/* Test __attribute__ ((unavailable)) */ +/* { dg-do compile } */ +/* { dg-options "" } */ + +/* Test the 'dot syntax' with unavailable methods. */ + +#include <objc/objc.h> + +@interface MyClass +{ + Class isa; +} ++ (int) classCount __attribute__ ((unavailable)); ++ (void) setClassCount: (int)value __attribute__ ((unavailable)); + +- (int) count __attribute__ ((unavailable)); +- (void) setCount: (int)value __attribute__ ((unavailable)); + +- (int) classCount2; +- (void) setClassCount2: (int)value; + +- (int) count2; +- (void) setCount2: (int)value; +@end + +void foo (void) +{ + MyClass *object = nil; + + + if (object.count > 0) /* { dg-error "is unavailable" } */ + object.count = 20; /* { dg-error "is unavailable" } */ + + if (MyClass.classCount < -7) /* { dg-error "is unavailable" } */ + MyClass.classCount = 11; /* { dg-error "is unavailable" } */ + + if (object.classCount2 > 0) + object.classCount2 = 19; + + if (object.count2 < -7) + object.count2 = 74; +} diff --git a/gcc/tree-core.h b/gcc/tree-core.h index 239a3a3f80b971bf1450a038aa03ecca01d189e0..445a09f93fb997cadf2cd6746e83f60b9dc94541 100644 --- a/gcc/tree-core.h +++ b/gcc/tree-core.h @@ -1038,7 +1038,8 @@ struct GTY(()) tree_base { unsigned user_align : 1; unsigned nameless_flag : 1; unsigned atomic_flag : 1; - unsigned spare0 : 3; + unsigned unavailable_flag : 1; + unsigned spare0 : 2; unsigned spare1 : 8; @@ -1360,6 +1361,12 @@ struct GTY(()) tree_base { SSA_NAME_POINTS_TO_READONLY_MEMORY in SSA_NAME + unavailable_flag: + + TREE_UNAVAILABLE in + all decls + all types + visited: TREE_VISITED in @@ -1407,6 +1414,7 @@ struct GTY(()) tree_base { CALL_EXPR_BY_DESCRIPTOR in CALL_EXPR + */ struct GTY(()) tree_typed { diff --git a/gcc/tree.c b/gcc/tree.c index 4c7e03b0f2582bc8d9892fa63924017def4bc897..03a424a663a4406703fd4ebd01a92f15d3344751 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -12154,6 +12154,78 @@ warn_deprecated_use (tree node, tree attr) return w; } +/* Error out with an identifier which was marked 'unavailable'. */ +void +error_unavailable_use (tree node, tree attr) +{ + escaped_string msg; + + if (node == 0) + return; + + if (!attr) + { + if (DECL_P (node)) + attr = DECL_ATTRIBUTES (node); + else if (TYPE_P (node)) + { + tree decl = TYPE_STUB_DECL (node); + if (decl) + attr = lookup_attribute ("unavailable", + TYPE_ATTRIBUTES (TREE_TYPE (decl))); + } + } + + if (attr) + attr = lookup_attribute ("unavailable", attr); + + if (attr) + msg.escape (TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr)))); + + if (DECL_P (node)) + { + auto_diagnostic_group d; + if (msg) + error ("%qD is unavailable: %s", node, (const char *) msg); + else + error ("%qD is unavailable", node); + inform (DECL_SOURCE_LOCATION (node), "declared here"); + } + else if (TYPE_P (node)) + { + tree what = NULL_TREE; + tree decl = TYPE_STUB_DECL (node); + + if (TYPE_NAME (node)) + { + if (TREE_CODE (TYPE_NAME (node)) == IDENTIFIER_NODE) + what = TYPE_NAME (node); + else if (TREE_CODE (TYPE_NAME (node)) == TYPE_DECL + && DECL_NAME (TYPE_NAME (node))) + what = DECL_NAME (TYPE_NAME (node)); + } + + auto_diagnostic_group d; + if (what) + { + if (msg) + error ("%qE is unavailable: %s", what, (const char *) msg); + else + error ("%qE is unavailable", what); + } + else + { + if (msg) + error ("type is unavailable: %s", (const char *) msg); + else + error ("type is unavailable"); + } + + if (decl) + inform (DECL_SOURCE_LOCATION (decl), "declared here"); + } +} + /* Return true if REF has a COMPONENT_REF with a bit-field field declaration somewhere in it. */ diff --git a/gcc/tree.h b/gcc/tree.h index c32193219efce626fedbe9cc5b7860bc1c535d29..2c8973f34e22de2ff87e5fae1284f00503a89653 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -956,6 +956,11 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int, #define TREE_DEPRECATED(NODE) \ ((NODE)->base.deprecated_flag) +/* Nonzero in a _DECL if the use of the name is defined as an + unavailable feature by __attribute__((unavailable)). */ +#define TREE_UNAVAILABLE(NODE) \ + ((NODE)->base.u.bits.unavailable_flag) + /* Nonzero indicates an IDENTIFIER_NODE that names an anonymous aggregate, (as created by anon_aggr_name_format). */ #define IDENTIFIER_ANON_P(NODE) \ @@ -5207,6 +5212,7 @@ extern const_tree strip_invariant_refs (const_tree); extern tree lhd_gcc_personality (void); extern void assign_assembler_name_if_needed (tree); extern bool warn_deprecated_use (tree, tree); +extern void error_unavailable_use (tree, tree); extern tree cache_integer_cst (tree, bool might_duplicate = false); extern const char *combined_fn_name (combined_fn);