aboutsummaryrefslogtreecommitdiff
path: root/gcc/objc
diff options
context:
space:
mode:
authorIain Sandoe <iain@sandoe.co.uk>2020-11-08 09:04:07 +0000
committerIain Sandoe <iain@sandoe.co.uk>2021-09-01 15:09:38 +0100
commit8433baadec88e5f31fa141b6d78094e91256079d (patch)
treebbe8d1332389ecdee6c6849b903c0aa5d12c978d /gcc/objc
parent21b4d0ef543d68187d258415b51d0d6676af89fd (diff)
downloadgcc-8433baadec88e5f31fa141b6d78094e91256079d.zip
gcc-8433baadec88e5f31fa141b6d78094e91256079d.tar.gz
gcc-8433baadec88e5f31fa141b6d78094e91256079d.tar.bz2
C-family: Add attribute 'unavailable'.
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. Signed-off-by: Iain Sandoe <iain@sandoe.co.uk> gcc/c-family/ChangeLog: * c-attribs.c (handle_unavailable_attribute): New. gcc/c/ChangeLog: * c-decl.c (enum deprecated_states): Add unavailable state. (merge_decls): Copy unavailability. (quals_from_declspecs): Handle unavailable case. (start_decl): Amend the logic handling suppression of nested deprecation states to include unavailability. (smallest_type_quals_location): Amend comment. (grokdeclarator): Handle the unavailable deprecation state. (declspecs_add_type): Set TREE_UNAVAILABLE from the decl specs. * c-tree.h (struct c_declspecs): Add unavailable_p. * c-typeck.c (build_component_ref): Handle unavailability. (build_external_ref): Likewise. gcc/cp/ChangeLog: * call.c (build_over_call): Handle unavailable state in addition to deprecation. * class.c (type_build_ctor_call): Likewise. (type_build_dtor_call): Likewise. * cp-tree.h: Rename cp_warn_deprecated_use to cp_handle_deprecated_or_unavailable. * decl.c (duplicate_decls): Merge unavailability. (grokdeclarator): Handle unavailability in addition to deprecation. (type_is_unavailable): New. (grokparms): Handle unavailability in addition to deprecation. * decl.h (enum deprecated_states): Add UNAVAILABLE_DEPRECATED_SUPPRESS. * decl2.c (cplus_decl_attributes): Propagate unavailability to templates. (cp_warn_deprecated_use): Rename to ... (cp_handle_deprecated_or_unavailable): ... this and amend to handle the unavailable case. It remains a warning in the case of deprecation but becomes an error in the case of unavailability. (cp_warn_deprecated_use_scopes): Handle unavailability. (mark_used): Likewise. * parser.c (cp_parser_template_name): Likewise. (cp_parser_template_argument): Likewise. (cp_parser_parameter_declaration_list): Likewise. * typeck.c (build_class_member_access_expr): Likewise. (finish_class_member_access_expr): Likewise. * typeck2.c (build_functional_cast_1): Likewise. gcc/ChangeLog: * doc/extend.texi: Document unavailable attribute. * print-tree.c (print_node): Handle unavailable attribute. * tree-core.h (struct tree_base): Add a bit to carry unavailability. * tree.c (error_unavailable_use): New. * tree.h (TREE_UNAVAILABLE): New. (error_unavailable_use): New. gcc/objc/ChangeLog: * objc-act.c (objc_add_property_declaration): Register unavailable attribute. (maybe_make_artificial_property_decl): Set available. (objc_maybe_build_component_ref): Generalise to the method prototype to count availability. (objc_build_class_component_ref): Likewise. (build_private_template): Likewise. (objc_decl_method_attributes): Handle unavailable attribute. (lookup_method_in_hash_lists): Amend comments. (objc_finish_message_expr): Handle unavailability in addition to deprecation. (start_class): Likewise. (finish_class): Likewise. (lookup_protocol): Likewise. (objc_declare_protocol): Likewise. (start_protocol): Register unavailable attribute. (really_start_method): Likewise. (objc_gimplify_property_ref): Emit error on encountering an unavailable entity (and a warning for a deprecated one). gcc/testsuite/ChangeLog: * g++.dg/ext/attr-unavailable-1.C: New test. * g++.dg/ext/attr-unavailable-2.C: New test. * g++.dg/ext/attr-unavailable-3.C: New test. * g++.dg/ext/attr-unavailable-4.C: New test. * g++.dg/ext/attr-unavailable-5.C: New test. * g++.dg/ext/attr-unavailable-6.C: New test. * g++.dg/ext/attr-unavailable-7.C: New test. * g++.dg/ext/attr-unavailable-8.C: New test. * g++.dg/ext/attr-unavailable-9.C: New test. * gcc.dg/attr-unavailable-1.c: New test. * gcc.dg/attr-unavailable-2.c: New test. * gcc.dg/attr-unavailable-3.c: New test. * gcc.dg/attr-unavailable-4.c: New test. * gcc.dg/attr-unavailable-5.c: New test. * gcc.dg/attr-unavailable-6.c: New test. * obj-c++.dg/attributes/method-unavailable-1.mm: New test. * obj-c++.dg/attributes/method-unavailable-2.mm: New test. * obj-c++.dg/attributes/method-unavailable-3.mm: New test. * obj-c++.dg/property/at-property-unavailable-1.mm: New test. * obj-c++.dg/property/at-property-unavailable-2.mm: New test. * obj-c++.dg/property/dotsyntax-unavailable-1.mm: New test. * objc.dg/attributes/method-unavailable-1.m: New test. * objc.dg/attributes/method-unavailable-2.m: New test. * objc.dg/attributes/method-unavailable-3.m: New test. * objc.dg/property/at-property-unavailable-1.m: New test. * objc.dg/property/at-property-unavailable-2.m: New test. * objc.dg/property/dotsyntax-unavailable-1.m: New test.
Diffstat (limited to 'gcc/objc')
-rw-r--r--gcc/objc/objc-act.c81
1 files changed, 61 insertions, 20 deletions
diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c
index 6e4fb62..9baa46d 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;