gcc/objc/ChangeLog:
* objc-act.c (objc_add_property_declaration): Register unavailable
attribute.
(maybe_make_artificial_property_decl): Set available.
(objc_maybe_build_component_ref): Generalise to the method prototype
to count availability.
(objc_build_class_component_ref): Likewise.
(build_private_template): Likewise.
(objc_decl_method_attributes): Handle unavailable attribute.
(lookup_method_in_hash_lists): Amend comments.
(objc_finish_message_expr): Handle unavailability in addition to
deprecation.
(start_class): Likewise.
(finish_class): Likewise.
(lookup_protocol): Likewise.
(objc_declare_protocol): Likewise.
(start_protocol): Register unavailable attribute.
(really_start_method): Likewise.
(objc_gimplify_property_ref): Emit error on encountering an
unavailable entity (and a warning for a deprecated one).
gcc/testsuite/ChangeLog:
* g++.dg/ext/attr-unavailable-1.C: New test.
* g++.dg/ext/attr-unavailable-2.C: New test.
* g++.dg/ext/attr-unavailable-3.C: New test.
* g++.dg/ext/attr-unavailable-4.C: New test.
* g++.dg/ext/attr-unavailable-5.C: New test.
* g++.dg/ext/attr-unavailable-6.C: New test.
* g++.dg/ext/attr-unavailable-7.C: New test.
* g++.dg/ext/attr-unavailable-8.C: New test.
* g++.dg/ext/attr-unavailable-9.C: New test.
* gcc.dg/attr-unavailable-1.c: New test.
* gcc.dg/attr-unavailable-2.c: New test.
* gcc.dg/attr-unavailable-3.c: New test.
* gcc.dg/attr-unavailable-4.c: New test.
* gcc.dg/attr-unavailable-5.c: New test.
* gcc.dg/attr-unavailable-6.c: New test.
* obj-c++.dg/attributes/method-unavailable-1.mm: New test.
* obj-c++.dg/attributes/method-unavailable-2.mm: New test.
* obj-c++.dg/attributes/method-unavailable-3.mm: New test.
* obj-c++.dg/property/at-property-unavailable-1.mm: New test.
* obj-c++.dg/property/at-property-unavailable-2.mm: New test.
* obj-c++.dg/property/dotsyntax-unavailable-1.mm: New test.
* objc.dg/attributes/method-unavailable-1.m: New test.
* objc.dg/attributes/method-unavailable-2.m: New test.
* objc.dg/attributes/method-unavailable-3.m: New test.
* objc.dg/property/at-property-unavailable-1.m: New test.
* objc.dg/property/at-property-unavailable-2.m: New test.
* objc.dg/property/dotsyntax-unavailable-1.m: New test.
---
gcc/c-family/c-attribs.c | 69 +++++++++++
gcc/c/c-decl.c | 39 ++++--
gcc/c/c-tree.h | 2 +
gcc/c/c-typeck.c | 8 +-
gcc/cp/call.c | 4 +-
gcc/cp/class.c | 2 +
gcc/cp/cp-tree.h | 2 +-
gcc/cp/decl.c | 66 ++++++++--
gcc/cp/decl.h | 3 +-
gcc/cp/decl2.c | 58 +++++++--
gcc/cp/parser.c | 32 +++--
gcc/cp/typeck.c | 9 +-
gcc/cp/typeck2.c | 2 +-
gcc/lto-streamer-out.c | 1 +
gcc/objc/objc-act.c | 81 +++++++++----
gcc/print-tree.c | 2 +
gcc/testsuite/g++.dg/ext/attr-unavailable-1.C | 113 ++++++++++++++++++
gcc/testsuite/g++.dg/ext/attr-unavailable-2.C | 10 ++
gcc/testsuite/g++.dg/ext/attr-unavailable-3.C | 14 +++
gcc/testsuite/g++.dg/ext/attr-unavailable-4.C | 11 ++
gcc/testsuite/g++.dg/ext/attr-unavailable-5.C | 6 +
gcc/testsuite/g++.dg/ext/attr-unavailable-6.C | 110 +++++++++++++++++
gcc/testsuite/g++.dg/ext/attr-unavailable-7.C | 19 +++
gcc/testsuite/g++.dg/ext/attr-unavailable-8.C | 17 +++
gcc/testsuite/g++.dg/ext/attr-unavailable-9.C | 17 +++
gcc/testsuite/gcc.dg/attr-unavailable-1.c | 88 ++++++++++++++
gcc/testsuite/gcc.dg/attr-unavailable-2.c | 6 +
gcc/testsuite/gcc.dg/attr-unavailable-3.c | 10 ++
gcc/testsuite/gcc.dg/attr-unavailable-4.c | 88 ++++++++++++++
gcc/testsuite/gcc.dg/attr-unavailable-5.c | 6 +
gcc/testsuite/gcc.dg/attr-unavailable-6.c | 11 ++
.../attributes/method-unavailable-1.mm | 34 ++++++
.../attributes/method-unavailable-2.mm | 24 ++++
.../attributes/method-unavailable-3.mm | 22 ++++
.../property/at-property-unavailable-1.mm | 38 ++++++
.../property/at-property-unavailable-2.mm | 26 ++++
.../property/dotsyntax-unavailable-1.mm | 42 +++++++
.../objc.dg/attributes/method-unavailable-1.m | 34 ++++++
.../objc.dg/attributes/method-unavailable-2.m | 24 ++++
.../objc.dg/attributes/method-unavailable-3.m | 22 ++++
.../property/at-property-unavailable-1.m | 38 ++++++
.../property/at-property-unavailable-2.m | 26 ++++
.../property/dotsyntax-unavailable-1.m | 42 +++++++
gcc/tree-core.h | 10 +-
gcc/tree.c | 72 +++++++++++
gcc/tree.h | 6 +
46 files changed, 1302 insertions(+), 64 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/ext/attr-unavailable-1.C
create mode 100644 gcc/testsuite/g++.dg/ext/attr-unavailable-2.C
create mode 100644 gcc/testsuite/g++.dg/ext/attr-unavailable-3.C
create mode 100644 gcc/testsuite/g++.dg/ext/attr-unavailable-4.C
create mode 100644 gcc/testsuite/g++.dg/ext/attr-unavailable-5.C
create mode 100644 gcc/testsuite/g++.dg/ext/attr-unavailable-6.C
create mode 100644 gcc/testsuite/g++.dg/ext/attr-unavailable-7.C
create mode 100644 gcc/testsuite/g++.dg/ext/attr-unavailable-8.C
create mode 100644 gcc/testsuite/g++.dg/ext/attr-unavailable-9.C
create mode 100644 gcc/testsuite/gcc.dg/attr-unavailable-1.c
create mode 100644 gcc/testsuite/gcc.dg/attr-unavailable-2.c
create mode 100644 gcc/testsuite/gcc.dg/attr-unavailable-3.c
create mode 100644 gcc/testsuite/gcc.dg/attr-unavailable-4.c
create mode 100644 gcc/testsuite/gcc.dg/attr-unavailable-5.c
create mode 100644 gcc/testsuite/gcc.dg/attr-unavailable-6.c
create mode 100644
gcc/testsuite/obj-c++.dg/attributes/method-unavailable-1.mm
create mode 100644
gcc/testsuite/obj-c++.dg/attributes/method-unavailable-2.mm
create mode 100644
gcc/testsuite/obj-c++.dg/attributes/method-unavailable-3.mm
create mode 100644
gcc/testsuite/obj-c++.dg/property/at-property-unavailable-1.mm
create mode 100644
gcc/testsuite/obj-c++.dg/property/at-property-unavailable-2.mm
create mode 100644
gcc/testsuite/obj-c++.dg/property/dotsyntax-unavailable-1.mm
create mode 100644 gcc/testsuite/objc.dg/attributes/method-unavailable-1.m
create mode 100644 gcc/testsuite/objc.dg/attributes/method-unavailable-2.m
create mode 100644 gcc/testsuite/objc.dg/attributes/method-unavailable-3.m
create mode 100644
gcc/testsuite/objc.dg/property/at-property-unavailable-1.m
create mode 100644
gcc/testsuite/objc.dg/property/at-property-unavailable-2.m
create mode 100644
gcc/testsuite/objc.dg/property/dotsyntax-unavailable-1.m
diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index f1680820ecd..067dfabe0a4 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -120,6 +120,8 @@ static tree handle_pure_attribute (tree *, tree, tree,
int, bool *);
static tree handle_tm_attribute (tree *, tree, tree, int, bool *);
static tree handle_tm_wrap_attribute (tree *, tree, tree, int, bool *);
static tree handle_novops_attribute (tree *, tree, tree, int, bool *);
+static tree handle_unavailable_attribute (tree *, tree, tree, int,
+ bool *);
static tree handle_vector_size_attribute (tree *, tree, tree, int,
bool *) ATTRIBUTE_NONNULL(3);
static tree handle_nonnull_attribute (tree *, tree, tree, int, bool *);
@@ -391,6 +393,8 @@ const struct attribute_spec
c_common_attribute_table[] =
handle_novops_attribute, NULL },
{ "deprecated", 0, 1, false, false, false, false,
handle_deprecated_attribute, NULL },
+ { "unavailable", 0, 1, false, false, false, false,
+ handle_unavailable_attribute, NULL },
{ "vector_size", 1, 1, false, true, false, true,
handle_vector_size_attribute, NULL },
{ "visibility", 1, 1, false, false, false, false,
@@ -3737,6 +3741,71 @@ handle_deprecated_attribute (tree *node, tree name,
return NULL_TREE;
}
+/* Handle a "unavailable" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_unavailable_attribute (tree *node, tree name,
+ tree args, int flags,
+ bool *no_add_attrs)
+{
+ tree type = NULL_TREE;
+ int warn = 0;
+ tree what = NULL_TREE;
+
+ if (!args)
+ *no_add_attrs = true;
+ else if (TREE_CODE (TREE_VALUE (args)) != STRING_CST)
+ {
+ error ("the message attached to %<unavailable%> is not a string");
+ *no_add_attrs = true;
+ }
+
+ if (DECL_P (*node))
+ {
+ tree decl = *node;
+ type = TREE_TYPE (decl);
+
+ if (TREE_CODE (decl) == TYPE_DECL
+ || TREE_CODE (decl) == PARM_DECL
+ || VAR_OR_FUNCTION_DECL_P (decl)
+ || TREE_CODE (decl) == FIELD_DECL
+ || TREE_CODE (decl) == CONST_DECL
+ || objc_method_decl (TREE_CODE (decl)))
+ TREE_UNAVAILABLE (decl) = 1;
+ else
+ warn = 1;
+ }
+ else if (TYPE_P (*node))
+ {
+ if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
+ *node = build_variant_type_copy (*node);
+ TREE_UNAVAILABLE (*node) = 1;
+ type = *node;
+ }
+ else
+ warn = 1;
+
+ if (warn)
+ {
+ *no_add_attrs = true;
+ if (type && TYPE_NAME (type))
+ {
+ if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
+ what = TYPE_NAME (*node);
+ else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
+ && DECL_NAME (TYPE_NAME (type)))
+ what = DECL_NAME (TYPE_NAME (type));
+ }
+ if (what)
+ warning (OPT_Wattributes, "%qE attribute ignored for %qE", name, what);
+ else
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ }
+
+ return NULL_TREE;
+}
+
/* Return the "base" type from TYPE that is suitable to apply attribute
vector_size to by stripping arrays, function types, etc. */
static tree
diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index f19c82c81dd..27c6f13e8f2 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -70,13 +70,16 @@ enum decl_context
TYPENAME}; /* Typename (inside cast or sizeof) */
/* States indicating how grokdeclarator() should handle declspecs marked
- with __attribute__((deprecated)). An object declared as
- __attribute__((deprecated)) suppresses warnings of uses of other
- deprecated items. */
+ with __attribute__((deprecated)) or __attribute__((unavailable)).
+ An object declared as __attribute__((unavailable)) should suppress
+ any reports of being declared with unavailable or deprecated items.
+ An object declared as __attribute__((deprecated)) should suppress
+ warnings of uses of other deprecated items. */
enum deprecated_states {
DEPRECATED_NORMAL,
- DEPRECATED_SUPPRESS
+ DEPRECATED_SUPPRESS,
+ UNAVAILABLE_DEPRECATED_SUPPRESS
};
@@ -2630,6 +2633,10 @@ merge_decls (tree newdecl, tree olddecl, tree
newtype, tree oldtype)
if (TREE_DEPRECATED (newdecl))
TREE_DEPRECATED (olddecl) = 1;
+ /* Merge unavailability. */
+ if (TREE_UNAVAILABLE (newdecl))
+ TREE_UNAVAILABLE (olddecl) = 1;
+
/* If a decl is in a system header and the other isn't, keep the one on
the
system header. Otherwise, keep source location of definition rather than
declaration and of prototype rather than non-prototype unless that
@@ -4868,6 +4875,7 @@ quals_from_declspecs (const struct c_declspecs
*specs)
&& !specs->typedef_p
&& !specs->explicit_signed_p
&& !specs->deprecated_p
+ && !specs->unavailable_p
&& !specs->long_p
&& !specs->long_long_p
&& !specs->short_p
@@ -5070,9 +5078,14 @@ start_decl (struct c_declarator *declarator, struct
c_declspecs *declspecs,
tree expr = NULL_TREE;
enum deprecated_states deprecated_state = DEPRECATED_NORMAL;
- /* An object declared as __attribute__((deprecated)) suppresses
+ /* An object declared as __attribute__((unavailable)) suppresses
+ warnings and errors from __attribute__((deprecated/unavailable))
+ components.
+ An object declared as __attribute__((deprecated)) suppresses
warnings of uses of other deprecated items. */
- if (lookup_attribute ("deprecated", attributes))
+ if (lookup_attribute ("unavailable", attributes))
+ deprecated_state = UNAVAILABLE_DEPRECATED_SUPPRESS;
+ else if (lookup_attribute ("deprecated", attributes))
deprecated_state = DEPRECATED_SUPPRESS;
decl = grokdeclarator (declarator, declspecs,
@@ -6190,7 +6203,7 @@ smallest_type_quals_location (const location_t
*locations,
set to indicate whether operands in *EXPR can be used in constant
expressions.
DEPRECATED_STATE is a deprecated_states value indicating whether
- deprecation warnings should be suppressed.
+ deprecation/unavailability warnings should be suppressed.
In the TYPENAME case, DECLARATOR is really an absolute declarator.
It may also be so in the PARM case, for a prototype where the
@@ -6320,8 +6333,14 @@ grokdeclarator (const struct c_declarator
*declarator,
if (decl_context == NORMAL && !funcdef_flag && current_scope->parm_flag)
decl_context = PARM;
- if (declspecs->deprecated_p && deprecated_state != DEPRECATED_SUPPRESS)
- warn_deprecated_use (declspecs->type, declspecs->decl_attr);
+ if (deprecated_state != UNAVAILABLE_DEPRECATED_SUPPRESS)
+ {
+ if (declspecs->unavailable_p)
+ error_unavailable_use (declspecs->type, declspecs->decl_attr);
+ else if (declspecs->deprecated_p
+ && deprecated_state != DEPRECATED_SUPPRESS)
+ warn_deprecated_use (declspecs->type, declspecs->decl_attr);
+ }
if ((decl_context == NORMAL || decl_context == FIELD)
&& current_scope == file_scope
@@ -10753,6 +10772,8 @@ declspecs_add_type (location_t loc, struct
c_declspecs *specs,
specs->typespec_kind = spec.kind;
if (TREE_DEPRECATED (type))
specs->deprecated_p = true;
+ if (TREE_UNAVAILABLE (type))
+ specs->unavailable_p = true;
/* Handle type specifier keywords. */
if (TREE_CODE (type) == IDENTIFIER_NODE
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index 1f783db7dbc..292874cc317 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -370,6 +370,8 @@ struct c_declspecs {
BOOL_BITFIELD explicit_signed_p : 1;
/* Whether the specifiers include a deprecated typedef. */
BOOL_BITFIELD deprecated_p : 1;
+ /* Whether the specifiers include an unavailable typedef. */
+ BOOL_BITFIELD unavailable_p : 1;
/* Whether the type defaulted to "int" because there were no type
specifiers. */
BOOL_BITFIELD default_int_p : 1;
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 96840377d90..16b6f776214 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -2504,7 +2504,9 @@ build_component_ref (location_t loc, tree datum,
tree
component,
|| (use_datum_quals && TREE_THIS_VOLATILE (datum)))
TREE_THIS_VOLATILE (ref) = 1;
- if (TREE_DEPRECATED (subdatum))
+ if (TREE_UNAVAILABLE (subdatum))
+ error_unavailable_use (subdatum, NULL_TREE);
+ else if (TREE_DEPRECATED (subdatum))
warn_deprecated_use (subdatum, NULL_TREE);
datum = ref;
@@ -2789,7 +2791,9 @@ build_external_ref (location_t loc, tree id, bool
fun,
tree *type)
if (TREE_TYPE (ref) == error_mark_node)
return error_mark_node;
- if (TREE_DEPRECATED (ref))
+ if (TREE_UNAVAILABLE (ref))
+ error_unavailable_use (ref, NULL_TREE);
+ else if (TREE_DEPRECATED (ref))
warn_deprecated_use (ref, NULL_TREE);
/* Recursive call does not count as usage. */
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 9861be1f856..3df6c48e237 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -9078,7 +9078,7 @@ build_over_call (struct z_candidate *cand, int
flags,
tsubst_flags_t complain)
already_used = true;
}
else
- cp_warn_deprecated_use (fn, complain);
+ cp_handle_deprecated_or_unavailable (fn, complain);
/* If we're creating a temp and we already have one, don't create a
new one. If we're not creating a temp but we get one, use
@@ -9148,7 +9148,7 @@ build_over_call (struct z_candidate *cand, int
flags,
tsubst_flags_t complain)
TREE_NO_WARNING (val) = 1;
}
- cp_warn_deprecated_use (fn, complain);
+ cp_handle_deprecated_or_unavailable (fn, complain);
return val;
}
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index c03737294eb..f594d473325 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -5678,6 +5678,7 @@ type_build_ctor_call (tree t)
tree fn = *iter;
if (!DECL_ARTIFICIAL (fn)
|| TREE_DEPRECATED (fn)
+ || TREE_UNAVAILABLE (fn)
|| DECL_DELETED_FN (fn))
return true;
}
@@ -5706,6 +5707,7 @@ type_build_dtor_call (tree t)
tree fn = *iter;
if (!DECL_ARTIFICIAL (fn)
|| TREE_DEPRECATED (fn)
+ || TREE_UNAVAILABLE (fn)
|| DECL_DELETED_FN (fn))
return true;
}
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 052291c40fe..7912cf511ed 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6303,7 +6303,7 @@ extern bool is_list_ctor (tree);
extern void validate_conversion_obstack (void);
extern void mark_versions_used (tree);
extern bool unsafe_return_slot_p (tree);
-extern bool cp_warn_deprecated_use (tree, tsubst_flags_t =
tf_warning_or_error);
+extern bool cp_handle_deprecated_or_unavailable (tree, tsubst_flags_t =
tf_warning_or_error);
extern void cp_warn_deprecated_use_scopes (tree);
extern tree get_function_version_dispatcher (tree);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 62648841ac3..bdd290f6d02 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -2350,6 +2350,10 @@ duplicate_decls (tree newdecl, tree olddecl, bool
hiding, bool was_hidden)
if (TREE_DEPRECATED (newdecl))
TREE_DEPRECATED (olddecl) = 1;
+ /* Merge unavailability. */
+ if (TREE_UNAVAILABLE (newdecl))
+ TREE_UNAVAILABLE (olddecl) = 1;
+
/* Preserve function specific target and optimization options */
if (TREE_CODE (newdecl) == FUNCTION_DECL)
{
@@ -11398,20 +11402,24 @@ grokdeclarator (const cp_declarator *declarator,
if (attrlist && *attrlist == error_mark_node)
*attrlist = NULL_TREE;
- /* An object declared as __attribute__((deprecated)) suppresses
- warnings of uses of other deprecated items. */
+ /* An object declared as __attribute__((unavailable)) suppresses
+ any reports of being declared with unavailable or deprecated
+ items. An object declared as __attribute__((deprecated))
+ suppresses warnings of uses of other deprecated items. */
temp_override<deprecated_states> ds (deprecated_state);
- if (attrlist && lookup_attribute ("deprecated", *attrlist))
+ if (attrlist && lookup_attribute ("unavailable", *attrlist))
+ deprecated_state = UNAVAILABLE_DEPRECATED_SUPPRESS;
+ else if (attrlist && lookup_attribute ("deprecated", *attrlist))
deprecated_state = DEPRECATED_SUPPRESS;
- cp_warn_deprecated_use (type);
+ cp_handle_deprecated_or_unavailable (type);
if (type && TREE_CODE (type) == TYPE_DECL)
{
cp_warn_deprecated_use_scopes (CP_DECL_CONTEXT (type));
typedef_decl = type;
type = TREE_TYPE (typedef_decl);
if (DECL_ARTIFICIAL (typedef_decl))
- cp_warn_deprecated_use (type);
+ cp_handle_deprecated_or_unavailable (type);
}
/* No type at all: default to `int', and set DEFAULTED_INT
because it was not a user-defined typedef. */
@@ -14027,6 +14035,43 @@ type_is_deprecated (tree type)
return NULL_TREE;
}
+/* Returns an unavailable type used within TYPE, or NULL_TREE if none. */
+
+static tree
+type_is_unavailable (tree type)
+{
+ enum tree_code code;
+ if (TREE_UNAVAILABLE (type))
+ return type;
+ if (TYPE_NAME (type))
+ {
+ if (TREE_UNAVAILABLE (TYPE_NAME (type)))
+ return type;
+ else
+ {
+ cp_warn_deprecated_use_scopes (CP_DECL_CONTEXT (TYPE_NAME (type)));
+ return NULL_TREE;
+ }
+ }
+
+ /* Do warn about using typedefs to a deprecated class. */
+ if (OVERLOAD_TYPE_P (type) && type != TYPE_MAIN_VARIANT (type))
+ return type_is_deprecated (TYPE_MAIN_VARIANT (type));
+
+ code = TREE_CODE (type);
+
+ if (code == POINTER_TYPE || code == REFERENCE_TYPE
+ || code == OFFSET_TYPE || code == FUNCTION_TYPE
+ || code == METHOD_TYPE || code == ARRAY_TYPE)
+ return type_is_unavailable (TREE_TYPE (type));
+
+ if (TYPE_PTRMEMFUNC_P (type))
+ return type_is_unavailable
+ (TREE_TYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (type))));
+
+ return NULL_TREE;
+}
+
/* Decode the list of parameter types for a function type.
Given the list of things declared inside the parens,
return a list of types.
@@ -14086,11 +14131,18 @@ grokparms (tree parmlist, tree *parms)
if (type != error_mark_node)
{
- if (deprecated_state != DEPRECATED_SUPPRESS)
+ if (deprecated_state != UNAVAILABLE_DEPRECATED_SUPPRESS)
+ {
+ tree unavailtype = type_is_unavailable (type);
+ if (unavailtype)
+ cp_handle_deprecated_or_unavailable (unavailtype);
+ }
+ if (deprecated_state != DEPRECATED_SUPPRESS
+ && deprecated_state != UNAVAILABLE_DEPRECATED_SUPPRESS)
{
tree deptype = type_is_deprecated (type);
if (deptype)
- cp_warn_deprecated_use (deptype);
+ cp_handle_deprecated_or_unavailable (deptype);
}
/* [dcl.fct] "A parameter with volatile-qualified type is
diff --git a/gcc/cp/decl.h b/gcc/cp/decl.h
index 3252dd8a011..475a00d8a2f 100644
--- a/gcc/cp/decl.h
+++ b/gcc/cp/decl.h
@@ -44,7 +44,8 @@ extern void name_unnamed_type (tree, tree);
enum deprecated_states {
DEPRECATED_NORMAL,
- DEPRECATED_SUPPRESS
+ DEPRECATED_SUPPRESS,
+ UNAVAILABLE_DEPRECATED_SUPPRESS
};
extern enum deprecated_states deprecated_state;
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 1bc7b7e0197..590f8a3c157 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -1608,6 +1608,17 @@ cplus_decl_attributes (tree *decl, tree attributes,
int flags)
if (*decl == pattern)
TREE_DEPRECATED (tmpl) = true;
}
+
+ /* Likewise, propagate unavailability out to the template. */
+ if (TREE_UNAVAILABLE (*decl))
+ if (tree ti = get_template_info (*decl))
+ {
+ tree tmpl = TI_TEMPLATE (ti);
+ tree pattern = (TYPE_P (*decl) ? TREE_TYPE (tmpl)
+ : DECL_TEMPLATE_RESULT (tmpl));
+ if (*decl == pattern)
+ TREE_UNAVAILABLE (tmpl) = true;
+ }
}
/* Walks through the namespace- or function-scope anonymous union
@@ -5389,14 +5400,47 @@ maybe_instantiate_decl (tree decl)
}
}
-/* Maybe warn if DECL is deprecated, subject to COMPLAIN. Returns whether
or
- not a warning was emitted. */
+/* Error if the DECL is unavailable (unless this is currently
suppressed).
+ Maybe warn if DECL is deprecated, subject to COMPLAIN. Returns true if
+ an error or warning was emitted. */
bool
-cp_warn_deprecated_use (tree decl, tsubst_flags_t complain)
+cp_handle_deprecated_or_unavailable (tree decl, tsubst_flags_t complain)
{
- if (!(complain & tf_warning) || !decl
- || deprecated_state == DEPRECATED_SUPPRESS)
+ if (!decl)
+ return false;
+
+ if ((complain & tf_error)
+ && deprecated_state != UNAVAILABLE_DEPRECATED_SUPPRESS)
+ {
+ if (TREE_UNAVAILABLE (decl))
+ {
+ error_unavailable_use (decl, NULL_TREE);
+ return true;
+ }
+ else
+ {
+ /* Perhaps this is an unavailable typedef. */
+ if (TYPE_P (decl)
+ && TYPE_NAME (decl)
+ && TREE_UNAVAILABLE (TYPE_NAME (decl)))
+ {
+ decl = TYPE_NAME (decl);
+ /* Don't error within members of a unavailable type. */
+ if (TYPE_P (decl)
+ && currently_open_class (decl))
+ return false;
+
+ error_unavailable_use (decl, NULL_TREE);
+ return true;
+ }
+ }
+ /* Carry on to consider deprecatedness. */
+ }
+
+ if (!(complain & tf_warning)
+ || deprecated_state == DEPRECATED_SUPPRESS
+ || deprecated_state == UNAVAILABLE_DEPRECATED_SUPPRESS)
return false;
if (!TREE_DEPRECATED (decl))
@@ -5455,7 +5499,7 @@ cp_warn_deprecated_use_scopes (tree scope)
&& scope != error_mark_node
&& scope != global_namespace)
{
- if (cp_warn_deprecated_use (scope))
+ if (cp_handle_deprecated_or_unavailable (scope))
return;
if (TYPE_P (scope))
scope = CP_TYPE_CONTEXT (scope);
@@ -5567,7 +5611,7 @@ mark_used (tree decl, tsubst_flags_t complain)
TREE_USED (decl) = true;
}
- cp_warn_deprecated_use (decl, complain);
+ cp_handle_deprecated_or_unavailable (decl, complain);
/* We can only check DECL_ODR_USED on variables or functions with
DECL_LANG_SPECIFIC set, and these are also the only decls that we
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 323d7424a83..00595c0365b 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -17170,18 +17170,26 @@ cp_parser_template_name (cp_parser* parser,
/* If DECL is a template, then the name was a template-name. */
if (TREE_CODE (decl) == TEMPLATE_DECL)
{
- if (TREE_DEPRECATED (decl)
- && deprecated_state != DEPRECATED_SUPPRESS)
+ if ((TREE_DEPRECATED (decl) || TREE_UNAVAILABLE (decl))
+ && deprecated_state != UNAVAILABLE_DEPRECATED_SUPPRESS)
{
tree d = DECL_TEMPLATE_RESULT (decl);
tree attr;
if (TREE_CODE (d) == TYPE_DECL)
- attr = lookup_attribute ("deprecated",
- TYPE_ATTRIBUTES (TREE_TYPE (d)));
+ attr = TYPE_ATTRIBUTES (TREE_TYPE (d));
else
- attr = lookup_attribute ("deprecated",
- DECL_ATTRIBUTES (d));
- warn_deprecated_use (decl, attr);
+ attr = DECL_ATTRIBUTES (d);
+ if (TREE_UNAVAILABLE (decl))
+ {
+ attr = lookup_attribute ("unavailable", attr);
+ error_unavailable_use (decl, attr);
+ }
+ else if (TREE_DEPRECATED (decl)
+ && deprecated_state != DEPRECATED_SUPPRESS)
+ {
+ attr = lookup_attribute ("deprecated", attr);
+ warn_deprecated_use (decl, attr);
+ }
}
}
else
@@ -17432,7 +17440,9 @@ cp_parser_template_argument (cp_parser* parser)
}
if (cp_parser_parse_definitely (parser))
{
- if (TREE_DEPRECATED (argument))
+ if (TREE_UNAVAILABLE (argument))
+ error_unavailable_use (argument, NULL_TREE);
+ else if (TREE_DEPRECATED (argument))
warn_deprecated_use (argument, NULL_TREE);
return argument;
}
@@ -22930,9 +22940,9 @@ cp_parser_parameter_declaration_list (cp_parser*
parser, cp_parser_flags flags)
/*template_parm_p=*/false,
&parenthesized_p);
- /* We don't know yet if the enclosing context is deprecated, so wait
- and warn in grokparms if appropriate. */
- deprecated_state = DEPRECATED_SUPPRESS;
+ /* We don't know yet if the enclosing context is unavailable or
deprecated,
+ so wait and deal with it in grokparms if appropriate. */
+ deprecated_state = UNAVAILABLE_DEPRECATED_SUPPRESS;
if (parameter)
{
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 08e0c80f9b0..7d1e2fd27a6 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -2514,7 +2514,10 @@ build_class_member_access_expr (cp_expr object,
tree
member,
member_scope = DECL_CLASS_CONTEXT (member);
if (!mark_used (member, complain) && !(complain & tf_error))
return error_mark_node;
- if (TREE_DEPRECATED (member))
+
+ if (TREE_UNAVAILABLE (member))
+ error_unavailable_use (member, NULL_TREE);
+ else if (TREE_DEPRECATED (member))
warn_deprecated_use (member, NULL_TREE);
}
else
@@ -3217,7 +3220,9 @@ finish_class_member_access_expr (cp_expr object,
tree
name, bool template_p,
}
}
- if (TREE_DEPRECATED (member))
+ if (TREE_UNAVAILABLE (member))
+ error_unavailable_use (member, NULL_TREE);
+ else if (TREE_DEPRECATED (member))
warn_deprecated_use (member, NULL_TREE);
if (template_p)
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 445e2a211c8..4d014dac88f 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -2293,7 +2293,7 @@ build_functional_cast_1 (location_t loc, tree exp,
tree parms,
type = TREE_TYPE (exp);
if (DECL_ARTIFICIAL (exp))
- cp_warn_deprecated_use (type);
+ cp_handle_deprecated_or_unavailable (type);
}
else
type = exp;
diff --git a/gcc/lto-streamer-out.c b/gcc/lto-streamer-out.c
index 0ca2796da9c..2c164daf3b4 100644
--- a/gcc/lto-streamer-out.c
+++ b/gcc/lto-streamer-out.c
@@ -1212,6 +1212,7 @@ hash_tree (struct streamer_tree_cache_d *cache,
hash_map<tree, hashval_t> *map,
hstate.add_flag (TREE_STATIC (t));
hstate.add_flag (TREE_PROTECTED (t));
hstate.add_flag (TREE_DEPRECATED (t));
+ hstate.add_flag (TREE_UNAVAILABLE (t));
if (code != TREE_BINFO)
hstate.add_flag (TREE_PRIVATE (t));
if (TYPE_P (t))
diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c
index b9ed32d51d0..fc247220a62 100644
--- a/gcc/objc/objc-act.c
+++ b/gcc/objc/objc-act.c
@@ -1275,6 +1275,7 @@ objc_add_property_declaration (location_t location,
tree decl,
TREE_TYPE (property_decl) = TREE_TYPE (decl);
DECL_SOURCE_LOCATION (property_decl) = DECL_SOURCE_LOCATION (decl);
TREE_DEPRECATED (property_decl) = TREE_DEPRECATED (decl);
+ TREE_UNAVAILABLE (property_decl) = TREE_UNAVAILABLE (decl);
/* Add property-specific information. */
PROPERTY_NAME (property_decl) = DECL_NAME (decl);
@@ -1390,6 +1391,7 @@ maybe_make_artificial_property_decl (tree interface,
tree implementation,
TREE_TYPE (property_decl) = type;
DECL_SOURCE_LOCATION (property_decl) = input_location;
TREE_DEPRECATED (property_decl) = 0;
+ TREE_UNAVAILABLE (property_decl) = 0;
DECL_ARTIFICIAL (property_decl) = 1;
/* Add property-specific information. Note that one of
@@ -1668,7 +1670,7 @@ objc_maybe_build_component_ref (tree object, tree
property_ident)
{
tree expression;
tree getter_call;
- tree deprecated_method_prototype = NULL_TREE;
+ tree method_prototype_avail = NULL_TREE;
/* We have an additional nasty problem here; if this
PROPERTY_REF needs to become a 'getter', then the conversion
@@ -1702,10 +1704,10 @@ objc_maybe_build_component_ref (tree object, tree
property_ident)
is deprecated, but record the fact that the getter is
deprecated by setting PROPERTY_REF_DEPRECATED_GETTER to
the method prototype. */
- &deprecated_method_prototype);
+ &method_prototype_avail);
expression = build4 (PROPERTY_REF, TREE_TYPE(x), object, x, getter_call,
- deprecated_method_prototype);
+ method_prototype_avail);
SET_EXPR_LOCATION (expression, input_location);
TREE_SIDE_EFFECTS (expression) = 1;
@@ -1755,7 +1757,9 @@ objc_build_class_component_ref (tree class_name,
tree
property_ident)
}
else
{
- if (TREE_DEPRECATED (rtype))
+ if (TREE_UNAVAILABLE (rtype))
+ error ("class %qE is unavailable", class_name);
+ else if (TREE_DEPRECATED (rtype))
warning (OPT_Wdeprecated_declarations, "class %qE is deprecated",
class_name);
}
@@ -1767,17 +1771,17 @@ objc_build_class_component_ref (tree class_name,
tree property_ident)
{
tree expression;
tree getter_call;
- tree deprecated_method_prototype = NULL_TREE;
+ tree method_prototype_avail = NULL_TREE;
if (PROPERTY_HAS_NO_GETTER (x))
getter_call = NULL_TREE;
else
getter_call = objc_finish_message_expr
(object, PROPERTY_GETTER_NAME (x), NULL_TREE,
- &deprecated_method_prototype);
+ &method_prototype_avail);
expression = build4 (PROPERTY_REF, TREE_TYPE(x), object, x, getter_call,
- deprecated_method_prototype);
+ method_prototype_avail);
SET_EXPR_LOCATION (expression, input_location);
TREE_SIDE_EFFECTS (expression) = 1;
@@ -4548,6 +4552,8 @@ build_private_template (tree klass)
/* Copy the attributes from the class to the type. */
if (TREE_DEPRECATED (klass))
TREE_DEPRECATED (record) = 1;
+ if (TREE_UNAVAILABLE (klass))
+ TREE_UNAVAILABLE (record) = 1;
}
}
@@ -4973,6 +4979,7 @@ objc_decl_method_attributes (tree *node, tree
attributes, int flags)
tree name = TREE_PURPOSE (attribute);
if (is_attribute_p ("deprecated", name)
+ || is_attribute_p ("unavailable", name)
|| is_attribute_p ("sentinel", name)
|| is_attribute_p ("noreturn", name))
{
@@ -5438,9 +5445,9 @@ lookup_method_in_hash_lists (tree sel_name, int
is_class)
C++ template functions, it is called from 'build_expr_from_tree'
(in decl2.c) after RECEIVER and METHOD_PARAMS have been expanded.
- If the DEPRECATED_METHOD_PROTOTYPE argument is NULL, then we warn
+ If the method_prototype_avail argument is NULL, then we warn
if the method being used is deprecated. If it is not NULL, instead
- of deprecating, we set *DEPRECATED_METHOD_PROTOTYPE to the method
+ of deprecating, we set *method_prototype_avail to the method
prototype that was used and is deprecated. This is useful for
getter calls that are always generated when compiling dot-syntax
expressions, even if they may not be used. In that case, we don't
@@ -5449,7 +5456,7 @@ lookup_method_in_hash_lists (tree sel_name, int
is_class)
used. */
tree
objc_finish_message_expr (tree receiver, tree sel_name, tree
method_params,
- tree *deprecated_method_prototype)
+ tree *method_prototype_avail)
{
tree method_prototype = NULL_TREE, rprotos = NULL_TREE, rtype;
tree retval, class_tree;
@@ -5761,10 +5768,17 @@ objc_finish_message_expr (tree receiver, tree
sel_name, tree method_params,
In practice this makes sense since casting an object to 'id'
is often used precisely to turn off warnings associated with
the object being of a particular class. */
- if (TREE_DEPRECATED (method_prototype) && rtype != NULL_TREE)
+ if (TREE_UNAVAILABLE (method_prototype) && rtype != NULL_TREE)
{
- if (deprecated_method_prototype)
- *deprecated_method_prototype = method_prototype;
+ if (method_prototype_avail)
+ *method_prototype_avail = method_prototype;
+ else
+ error_unavailable_use (method_prototype, NULL_TREE);
+ }
+ else if (TREE_DEPRECATED (method_prototype) && rtype != NULL_TREE)
+ {
+ if (method_prototype_avail)
+ *method_prototype_avail = method_prototype;
else
warn_deprecated_use (method_prototype, NULL_TREE);
}
@@ -6936,7 +6950,9 @@ start_class (enum tree_code code, tree class_name,
tree super_name,
}
else
{
- if (TREE_DEPRECATED (super_interface))
+ if (TREE_UNAVAILABLE (super_interface))
+ error ("class %qE is not available", super);
+ else if (TREE_DEPRECATED (super_interface))
warning (OPT_Wdeprecated_declarations, "class %qE is deprecated",
super);
super_name = super;
@@ -7040,7 +7056,9 @@ start_class (enum tree_code code, tree class_name,
tree super_name,
/* TODO: Document what the objc_exception attribute is/does. */
/* We handle the 'deprecated', 'visibility' and (undocumented)
'objc_exception' attributes. */
- if (is_attribute_p ("deprecated", name))
+ if (is_attribute_p ("unavailable", name))
+ TREE_UNAVAILABLE (klass) = 1;
+ else if (is_attribute_p ("deprecated", name))
TREE_DEPRECATED (klass) = 1;
else if (is_attribute_p ("objc_exception", name))
CLASS_HAS_EXCEPTION_ATTR (klass) = 1;
@@ -7069,7 +7087,9 @@ start_class (enum tree_code code, tree class_name,
tree super_name,
}
else
{
- if (TREE_DEPRECATED (class_category_is_assoc_with))
+ if (TREE_UNAVAILABLE (class_category_is_assoc_with))
+ error ("class %qE is unavailable", class_name);
+ else if (TREE_DEPRECATED (class_category_is_assoc_with))
warning (OPT_Wdeprecated_declarations, "class %qE is deprecated",
class_name);
@@ -8096,6 +8116,7 @@ finish_class (tree klass)
else
objc_add_method (objc_interface_context, getter_decl, false, false);
TREE_DEPRECATED (getter_decl) = TREE_DEPRECATED (x);
+ TREE_UNAVAILABLE (getter_decl) = TREE_UNAVAILABLE (x);
METHOD_PROPERTY_CONTEXT (getter_decl) = x;
}
@@ -8140,6 +8161,7 @@ finish_class (tree klass)
else
objc_add_method (objc_interface_context, setter_decl, false, false);
TREE_DEPRECATED (setter_decl) = TREE_DEPRECATED (x);
+ TREE_UNAVAILABLE (setter_decl) = TREE_UNAVAILABLE (x);
METHOD_PROPERTY_CONTEXT (setter_decl) = x;
}
}
@@ -8193,7 +8215,9 @@ lookup_protocol (tree ident, bool
warn_if_deprecated,
bool definition_required)
for (chain = protocol_chain; chain; chain = TREE_CHAIN (chain))
if (ident == PROTOCOL_NAME (chain))
{
- if (warn_if_deprecated && TREE_DEPRECATED (chain))
+ if (TREE_UNAVAILABLE (chain))
+ error ("protocol %qE is unavailable", PROTOCOL_NAME (chain));
+ else if (warn_if_deprecated && TREE_DEPRECATED (chain))
{
/* It would be nice to use warn_deprecated_use() here, but
we are using TREE_CHAIN (which is supposed to be the
@@ -8218,6 +8242,7 @@ void
objc_declare_protocol (tree name, tree attributes)
{
bool deprecated = false;
+ bool unavailable = false;
#ifdef OBJCPLUS
if (current_namespace != global_namespace) {
@@ -8236,6 +8261,8 @@ objc_declare_protocol (tree name, tree attributes)
if (is_attribute_p ("deprecated", name))
deprecated = true;
+ else if (is_attribute_p ("unavailable", name))
+ unavailable = true;
else
warning (OPT_Wattributes, "%qE attribute directive ignored", name);
}
@@ -8260,6 +8287,8 @@ objc_declare_protocol (tree name, tree attributes)
TYPE_ATTRIBUTES (protocol) = attributes;
if (deprecated)
TREE_DEPRECATED (protocol) = 1;
+ if (unavailable)
+ TREE_UNAVAILABLE (protocol) = 1;
}
}
}
@@ -8269,6 +8298,7 @@ start_protocol (enum tree_code code, tree name, tree
list, tree attributes)
{
tree protocol;
bool deprecated = false;
+ bool unavailable = false;
#ifdef OBJCPLUS
if (current_namespace != global_namespace) {
@@ -8287,6 +8317,8 @@ start_protocol (enum tree_code code, tree name, tree
list, tree attributes)
if (is_attribute_p ("deprecated", name))
deprecated = true;
+ else if (is_attribute_p ("unavailable", name))
+ unavailable = true;
else
warning (OPT_Wattributes, "%qE attribute directive ignored", name);
}
@@ -8326,6 +8358,8 @@ start_protocol (enum tree_code code, tree name, tree
list, tree attributes)
TYPE_ATTRIBUTES (protocol) = attributes;
if (deprecated)
TREE_DEPRECATED (protocol) = 1;
+ if (unavailable)
+ TREE_UNAVAILABLE (protocol) = 1;
}
return protocol;
@@ -8855,6 +8889,8 @@ really_start_method (tree method,
warnings are produced), but just in case. */
if (TREE_DEPRECATED (proto))
TREE_DEPRECATED (method) = 1;
+ if (TREE_UNAVAILABLE (proto))
+ TREE_UNAVAILABLE (method) = 1;
/* If the method in the @interface was marked as
'noreturn', mark the function implementing the method
@@ -9586,12 +9622,17 @@ objc_gimplify_property_ref (tree *expr_p)
return;
}
+ /* FIXME, this should be a label indicating availability in general. */
if (PROPERTY_REF_DEPRECATED_GETTER (*expr_p))
{
- /* PROPERTY_REF_DEPRECATED_GETTER contains the method prototype
+ if (TREE_UNAVAILABLE (PROPERTY_REF_DEPRECATED_GETTER (*expr_p)))
+ error_unavailable_use (PROPERTY_REF_DEPRECATED_GETTER (*expr_p),
+ NULL_TREE);
+ else
+ /* PROPERTY_REF_DEPRECATED_GETTER contains the method prototype
that is deprecated. */
- warn_deprecated_use (PROPERTY_REF_DEPRECATED_GETTER (*expr_p),
- NULL_TREE);
+ warn_deprecated_use (PROPERTY_REF_DEPRECATED_GETTER (*expr_p),
+ NULL_TREE);
}
call_exp = getter;
diff --git a/gcc/print-tree.c b/gcc/print-tree.c
index 17c88f81770..1443d3f5c39 100644
--- a/gcc/print-tree.c
+++ b/gcc/print-tree.c
@@ -364,6 +364,8 @@ print_node (FILE *file, const char *prefix, tree node,
int indent,
fputs (code == CALL_EXPR ? " must-tail-call" : " static", file);
if (TREE_DEPRECATED (node))
fputs (" deprecated", file);
+ if (TREE_UNAVAILABLE (node))
+ fputs (" unavailable", file);
if (TREE_VISITED (node))
fputs (" visited", file);
diff --git a/gcc/testsuite/g++.dg/ext/attr-unavailable-1.C
b/gcc/testsuite/g++.dg/ext/attr-unavailable-1.C
new file mode 100644
index 00000000000..862651f6cbf
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/attr-unavailable-1.C
@@ -0,0 +1,113 @@
+/* Test __attribute__ ((unavailable)) */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+typedef int INT1 __attribute__((unavailable));
+typedef INT1 INT2 __attribute__ ((__unavailable__));
+
+typedef INT1 INT1a; /* { dg-error "'INT1' is unavailable" "" } */
+typedef INT1 INT1b __attribute__ ((unavailable));
+
+INT1 should_be_unavailable; /* { dg-error "'INT1' is unavailable" "" } */
+INT1a should_not_be_unavailable;
+
+INT1 f1(void) __attribute__ ((unavailable));
+INT1 f2(void) { return 0; } /* { dg-error "'INT1' is unavailable" "" } */
+
+INT2 f3(void) __attribute__ ((__unavailable__));
+INT2 f4(void) { return 0; } /* { dg-error "'INT2' is unavailable" "" } */
+int f5(INT2 x); /* { dg-error "'INT2' is unavailable" "" } */
+int f6(INT2 x) __attribute__ ((__unavailable__));
+
+typedef enum Color {red, green, blue} Color __attribute__((unavailable));
+
+int g1;
+int g2 __attribute__ ((unavailable));
+int g3 __attribute__ ((__unavailable__));
+Color k; /* { dg-error "'Color' is unavailable" "" } */
+
+typedef struct {
+ int field1;
+ int field2 __attribute__ ((unavailable));
+ int field3;
+ int field4 __attribute__ ((__unavailable__));
+ union {
+ int field5;
+ int field6 __attribute__ ((unavailable));
+ } u1;
+ int field7:1;
+ int field8:1 __attribute__ ((unavailable));
+ union {
+ int field9;
+ int field10;
+ } u2 __attribute__ ((unavailable));
+} S1;
+
+int func1()
+{
+ INT1 w; /* { dg-error "'INT1' is unavailable" "" } */
+ int x __attribute__ ((unavailable));
+ int y __attribute__ ((__unavailable__));
+ int z;
+ int (*pf)() = f1; /* { dg-error "'INT1 f1\\(\\)' is unavailable" "" } */
+
+ z = w + x + y + g1 + g2 + g3; /* { dg-error "'x' is unavailable" "" } */
+ /* { dg-error "'y' is unavailable" "y" { target *-*-* } .-1 } */
+ /* { dg-error "'g2' is unavailable" "g2" { target *-*-* } .-2 } */
+ /* { dg-error "'g3' is unavailable" "g3" { target *-*-* } .-3 } */
+ return f1(); /* { dg-error "'INT1 f1\\(\\)' is unavailable" "f1" } */
+}
+
+int func2(S1 *p)
+{
+ S1 lp;
+
+ if (p->field1)
+ return p->field2; /* { dg-error "'S1::field2' is unavailable" "" } */
+ else if (lp.field4) /* { dg-error "'S1::field4' is unavailable" "" } */
+ return p->field3;
+
+ p->u1.field5 = g1 + p->field7;
+ p->u2.field9; /* { dg-error "'S1::u2' is unavailable" "" } */
+ return p->u1.field6 + p->field8; /* { dg-error "'S1::<unnamed
union>::field6' is unavailable" "" } */
+ /* { dg-error "'S1::field8' is unavailable" "field8" { target *-*-* }
.-1
} */
+}
+
+struct SS1 {
+ int x;
+ INT1 y; /* { dg-error "'INT1' is unavailable" "" } */
+} __attribute__ ((unavailable));
+
+struct SS1 *p1; /* { dg-error "'SS1' is unavailable" "" } */
+
+struct __attribute__ ((__unavailable__)) SS2 {
+ int x;
+ INT1 y; /* { dg-error "'INT1' is unavailable" "" } */
+};
+
+struct SS2 *p2; /* { dg-error "'SS2' is unavailable" "" } */
+
+#ifdef __cplusplus
+class T {
+ public:
+ void member1(int) __attribute__ ((unavailable));
+ void member2(INT1) __attribute__ ((__unavailable__));
+ int member3(T *);
+ int x;
+} __attribute__ ((unavailable));
+
+T *p3; // { dg-error "'T' is unavailable" }
+
+inline void T::member1(int) {}
+
+int T::member3(T *p) // { dg-error "'T' is unavailable" }
+{
+ p->member1(1); /* { dg-error "'void T::member1\\(int\\)' is unavailable"
"" } */
+ (*p).member1(2); /* { dg-error "'void T::member1\\(int\\)' is
unavailable"
"" } */
+ p->member2(1); /* { dg-error "'void T::member2\\(INT1\\)' is
unavailable"
"" } */
+ (*p).member2(2); /* { dg-error "'void T::member2\\(INT1\\)' is
unavailable" "" } */
+ p->member3(p);
+ (*p).member3(p);
+ return f1(); /* { dg-error "'INT1 f1\\(\\)' is unavailable" "" } */
+}
+#endif
diff --git a/gcc/testsuite/g++.dg/ext/attr-unavailable-2.C
b/gcc/testsuite/g++.dg/ext/attr-unavailable-2.C
new file mode 100644
index 00000000000..3de5532817e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/attr-unavailable-2.C
@@ -0,0 +1,10 @@
+/* Test __attribute__ ((unavailable)) */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+void func(void);
+void func(void) __attribute__((unavailable));
+
+void f(void) {
+ func(); /* { dg-error "'void func\\(\\)' is unavailable" } */
+}
diff --git a/gcc/testsuite/g++.dg/ext/attr-unavailable-3.C
b/gcc/testsuite/g++.dg/ext/attr-unavailable-3.C
new file mode 100644
index 00000000000..1f267ea78c4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/attr-unavailable-3.C
@@ -0,0 +1,14 @@
+/* Check operator with __attribute__((unavailable)) */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+struct Foo
+{
+ operator int() __attribute__((unavailable));
+};
+
+void g(void)
+{
+ Foo f;
+ (int)f; // { dg-error "'Foo::operator int\\(\\)' is unavailable" }
+}
diff --git a/gcc/testsuite/g++.dg/ext/attr-unavailable-4.C
b/gcc/testsuite/g++.dg/ext/attr-unavailable-4.C
new file mode 100644
index 00000000000..b7f352ee3bd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/attr-unavailable-4.C
@@ -0,0 +1,11 @@
+/* Test __attribute__ ((unavailable)) */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+struct B {
+ virtual int foo() __attribute__((unavailable));
+};
+
+int main(void) {
+ ((B*)0)->foo(); // { dg-error "unavailable" }
+}
diff --git a/gcc/testsuite/g++.dg/ext/attr-unavailable-5.C
b/gcc/testsuite/g++.dg/ext/attr-unavailable-5.C
new file mode 100644
index 00000000000..3beea5d22c5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/attr-unavailable-5.C
@@ -0,0 +1,6 @@
+/* Test __attribute__ ((unavailable)) */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+struct Foo { int i; } __attribute__ ((unavailable));
+void foo() { Foo f; } // { dg-error "unavailable" }
diff --git a/gcc/testsuite/g++.dg/ext/attr-unavailable-6.C
b/gcc/testsuite/g++.dg/ext/attr-unavailable-6.C
new file mode 100644
index 00000000000..8a57ea0d88c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/attr-unavailable-6.C
@@ -0,0 +1,110 @@
+/* Test __attribute__ ((unavailable)) */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+typedef int INT1 __attribute__((unavailable("You can't use INT1")));
+typedef INT1 INT2 __attribute__ ((__unavailable__("You can't use
INT2")));
+
+typedef INT1 INT1a; /* { dg-error "'INT1' is unavailable: You can't use
INT1" "" } */
+
+INT1 should_be_unavailable; /* { dg-error "'INT1' is unavailable: You
can't
use INT1" "" } */
+INT1a should_not_be_unavailable;
+
+INT1 f1(void) __attribute__ ((unavailable("You can't use f1")));
+INT1 f2(void) { return 0; } /* { dg-error "'INT1' is unavailable: You
can't
use INT1" "" } */
+
+INT2 f3(void) __attribute__ ((__unavailable__("You can't use f3")));
+INT2 f4(void) { return 0; } /* { dg-error "'INT2' is unavailable: You
can't
use INT2" "" } */
+int f5(INT2 x); /* { dg-error "'INT2' is unavailable" "" } */
+int f6(INT2 x) __attribute__ ((__unavailable__("You can't use f6")));
+
+typedef enum Color {red, green, blue} Color
__attribute__((unavailable("You
can't use Color")));
+
+int g1;
+int g2 __attribute__ ((unavailable("You can't use g2")));
+int g3 __attribute__ ((__unavailable__("You can't use g3")));
+Color k; /* { dg-error "'Color' is unavailable: You can't use Color" "" }
*/
+
+typedef struct {
+ int field1;
+ int field2 __attribute__ ((unavailable("You can't use field2")));
+ int field3;
+ int field4 __attribute__ ((__unavailable__("You can't use field4")));
+ union {
+ int field5;
+ int field6 __attribute__ ((unavailable("You can't use field6")));
+ } u1;
+ int field7:1;
+ int field8:1 __attribute__ ((unavailable("You can't use field8")));
+ union {
+ int field9;
+ int field10;
+ } u2 __attribute__ ((unavailable("You can't use u2")));
+} S1;
+
+int func1()
+{
+ INT1 w; /* { dg-error "'INT1' is unavailable: You can't use INT1" "" }
*/
+ int x __attribute__ ((unavailable("You can't use x")));
+ int y __attribute__ ((__unavailable__("You can't use y")));
+ int z;
+ int (*pf)() = f1; /* { dg-error "'INT1 f1\\(\\)' is unavailable: You
can't
use f1" "" } */
+
+ z = w + x + y + g1 + g2 + g3; /* { dg-error "'x' is unavailable: You
can't
use x" "" } */
+ /* { dg-error "'y' is unavailable: You can't use y" "y" { target *-*-* }
.-1 } */
+ /* { dg-error "'g2' is unavailable: You can't use g2" "g2" { target
*-*-*
} .-2 } */
+ /* { dg-error "'g3' is unavailable: You can't use g3" "g3" { target
*-*-*
} .-3 } */
+ return f1(); /* { dg-error "'INT1 f1\\(\\)' is unavailable: You can't
use
f1" "f1" } */
+}
+
+int func2(S1 *p)
+{
+ S1 lp;
+
+ if (p->field1)
+ return p->field2; /* { dg-error "'S1::field2' is unavailable: You can't
use field2" "" } */
+ else if (lp.field4) /* { dg-error "'S1::field4' is unavailable: You
can't
use field4" "" } */
+ return p->field3;
+
+ p->u1.field5 = g1 + p->field7;
+ p->u2.field9; /* { dg-error "'S1::u2' is unavailable: You can't use
u2" ""
} */
+ return p->u1.field6 + p->field8; /* { dg-error "'S1::<unnamed
union>::field6' is unavailable: You can't use field6" "" } */
+ /* { dg-error "'S1::field8' is unavailable: You can't use field8"
"field8"
{ target *-*-* } .-1 } */
+}
+
+struct SS1 {
+ int x;
+ INT1 y; /* { dg-error "'INT1' is unavailable: You can't use INT1" "" }
*/
+} __attribute__ ((unavailable("You can't use SS1")));
+
+struct SS1 *p1; /* { dg-error "'SS1' is unavailable: You can't use SS1"
""
} */
+
+struct __attribute__ ((__unavailable__("You can't use SS2"))) SS2 {
+ int x;
+ INT1 y; /* { dg-error "'INT1' is unavailable: You can't use INT1" "" }
*/
+};
+
+struct SS2 *p2; /* { dg-error "'SS2' is unavailable: You can't use SS2"
""
} */
+
+class T {
+ public:
+ void member1(int) __attribute__ ((unavailable("You can't use
member1")));
+ void member2(INT1) __attribute__ ((__unavailable__("You can't use
member2")));
+ int member3(T *);
+ int x;
+} __attribute__ ((unavailable("You can't use T")));
+
+T *p3; // { dg-error "'T' is unavailable: You can't use T" }
+
+inline void T::member1(int) {}
+
+int T::member3(T *p) // { dg-error "'T' is unavailable: You can't use
T" }
+{
+ p->member1(1); /* { dg-error "'void T::member1\\(int\\)' is unavailable:
You can't use member1" "" } */
+ (*p).member1(2); /* { dg-error "'void T::member1\\(int\\)' is
unavailable:
You can't use member1" "" } */
+ p->member2(1); /* { dg-error "'void T::member2\\(INT1\\)' is
unavailable:
You can't use member2" "" } */
+ (*p).member2(2); /* { dg-error "'void T::member2\\(INT1\\)' is
unavailable: You can't use member2" "" } */
+ p->member3(p);
+ (*p).member3(p);
+ return f1(); /* { dg-error "'INT1 f1\\(\\)' is unavailable: You can't
use
f1" "" } */
+}
diff --git a/gcc/testsuite/g++.dg/ext/attr-unavailable-7.C
b/gcc/testsuite/g++.dg/ext/attr-unavailable-7.C
new file mode 100644
index 00000000000..c061aa3b6a2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/attr-unavailable-7.C
@@ -0,0 +1,19 @@
+/* Test __attribute__ ((unavailable)) */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+int g_nn;
+int& g_n __attribute__((unavailable)) = g_nn;
+
+void f()
+{
+ int f_nn;
+ int& f_n __attribute__((unavailable)) = f_nn;
+ f_n = 1; // { dg-error "'f_n' is unavailable" }
+}
+
+int main()
+{
+ g_n = 1; // { dg-error "'g_n' is unavailable" }
+ f();
+}
diff --git a/gcc/testsuite/g++.dg/ext/attr-unavailable-8.C
b/gcc/testsuite/g++.dg/ext/attr-unavailable-8.C
new file mode 100644
index 00000000000..334a2cf7286
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/attr-unavailable-8.C
@@ -0,0 +1,17 @@
+/* Test __attribute__ ((unavailable)) */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+class ToBeunavailable {
+} __attribute__ ((unavailable ("unavailable!")));
+
+typedef ToBeunavailable NotToBeunavailable; // { dg-error
"'ToBeunavailable' is unavailable" }
+
+int main() {
+
+ ToBeunavailable(); // { dg-error "'ToBeunavailable' is unavailable" }
+ ToBeunavailable x; // { dg-error "'ToBeunavailable' is unavailable" }
+
+ NotToBeunavailable();
+ NotToBeunavailable y;
+}
diff --git a/gcc/testsuite/g++.dg/ext/attr-unavailable-9.C
b/gcc/testsuite/g++.dg/ext/attr-unavailable-9.C
new file mode 100644
index 00000000000..44161336e78
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/attr-unavailable-9.C
@@ -0,0 +1,17 @@
+/* Test __attribute__ ((unavailable)) */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+template<typename T> struct __attribute__ ((unavailable)) S {};
+S<int> s;
+
+template <template <class> class T> struct A { };
+A<S> a;
+
+template <class T> void f() __attribute__ ((unavailable));
+
+int main()
+{
+ f<int>(); // { dg-error "unavailable" }
+ void (*p)() = f<char>; // { dg-error "unavailable" }
+}
diff --git a/gcc/testsuite/gcc.dg/attr-unavailable-1.c
b/gcc/testsuite/gcc.dg/attr-unavailable-1.c
new file mode 100644
index 00000000000..768214fcd3a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/attr-unavailable-1.c
@@ -0,0 +1,88 @@
+/* Test __attribute__ ((unavailable)) */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+typedef int INT1 __attribute__((unavailable));
+typedef INT1 INT2 __attribute__ ((__unavailable__));
+
+typedef INT1 INT1a; /* { dg-error "'INT1' is unavailable" "" } */
+typedef INT1 INT1b __attribute__ ((unavailable));
+
+INT1 should_be_unavailable; /* { dg-error "'INT1' is unavailable" "" } */
+INT1a should_not_be_unavailable;
+
+INT1 f1(void) __attribute__ ((unavailable));
+INT1 f2(void) { return 0; } /* { dg-error "'INT1' is unavailable" "" } */
+
+INT2 f3(void) __attribute__ ((__unavailable__));
+INT2 f4(void) { return 0; } /* { dg-error "'INT2' is unavailable" "" } */
+int f5(INT2 x); /* { dg-error "'INT2' is unavailable" "" } */
+int f6(INT2 x) __attribute__ ((__unavailable__)); /* { dg-error "'INT2'
is
unavailable" "" } */
+
+typedef enum {red, green, blue} Color __attribute__((unavailable));
+
+int g1;
+int g2 __attribute__ ((unavailable));
+int g3 __attribute__ ((__unavailable__));
+Color k; /* { dg-error "'Color' is unavailable" "" } */
+
+typedef struct {
+ int field1;
+ int field2 __attribute__ ((unavailable));
+ int field3;
+ int field4 __attribute__ ((__unavailable__));
+ union {
+ int field5;
+ int field6 __attribute__ ((unavailable));
+ } u1;
+ int field7:1;
+ int field8:1 __attribute__ ((unavailable));
+ union {
+ int field9;
+ int field10;
+ } u2 __attribute__ ((unavailable));
+} S1;
+
+int func1()
+{
+ INT1 w; /* { dg-error "'INT1' is unavailable" "" } */
+ int x __attribute__ ((unavailable));
+ int y __attribute__ ((__unavailable__));
+ int z;
+ int (*pf)() = f1; /* { dg-error "'f1' is unavailable" "" } */
+
+ z = w + x + y + g1 + g2 + g3; /* { dg-error "'x' is unavailable" "" } */
+ /* { dg-error "'y' is unavailable" "y" { target *-*-* } .-1 } */
+ /* { dg-error "'g2' is unavailable" "g2" { target *-*-* } .-2 } */
+ /* { dg-error "'g3' is unavailable" "g3" { target *-*-* } .-3 } */
+ return f1(); /* { dg-error "'f1' is unavailable" "f1" } */
+}
+
+int func2(S1 *p)
+{
+ S1 lp;
+
+ if (p->field1)
+ return p->field2; /* { dg-error "'field2' is unavailable" "" } */
+ else if (lp.field4) /* { dg-error "'field4' is unavailable" "" } */
+ return p->field3;
+
+ p->u1.field5 = g1 + p->field7;
+ p->u2.field9; /* { dg-error "'u2' is unavailable" "" } */
+ return p->u1.field6 + p->field8; /* { dg-error "'field6' is unavailable"
"" } */
+ /* { dg-error "'field8' is unavailable" "field8" { target *-*-* } .-1
} */
+}
+
+struct SS1 {
+ int x;
+ INT1 y; /* { dg-error "'INT1' is unavailable" "" } */
+} __attribute__ ((unavailable));
+
+struct SS1 *p1; /* { dg-error "'SS1' is unavailable" "" } */
+
+struct __attribute__ ((__unavailable__)) SS2 {
+ int x;
+ INT1 y; /* { dg-error "'INT1' is unavailable" "" } */
+};
+
+struct SS2 *p2; /* { dg-error "'SS2' is unavailable" "" } */
diff --git a/gcc/testsuite/gcc.dg/attr-unavailable-2.c
b/gcc/testsuite/gcc.dg/attr-unavailable-2.c
new file mode 100644
index 00000000000..303f973d5db
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/attr-unavailable-2.c
@@ -0,0 +1,6 @@
+/* Test __attribute__((unavailable)). Test types without names. */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+struct { int a; } __attribute__((unavailable)) x; /* { dg-error "type is
unavailable" } */
+typeof(x) y; /* { dg-error "type is unavailable" } */
diff --git a/gcc/testsuite/gcc.dg/attr-unavailable-3.c
b/gcc/testsuite/gcc.dg/attr-unavailable-3.c
new file mode 100644
index 00000000000..7274c193f3f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/attr-unavailable-3.c
@@ -0,0 +1,10 @@
+/* Test __attribute__((unavailable)). */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+void func(void);
+void func(void) __attribute__((unavailable));
+
+void f(void) {
+ func(); /* { dg-error "'func' is unavailable" } */
+}
diff --git a/gcc/testsuite/gcc.dg/attr-unavailable-4.c
b/gcc/testsuite/gcc.dg/attr-unavailable-4.c
new file mode 100644
index 00000000000..9e39c50fec6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/attr-unavailable-4.c
@@ -0,0 +1,88 @@
+/* Test __attribute__ ((unavailable("message"))) */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+typedef int INT1 __attribute__((unavailable("You can't use INT1")));
+typedef INT1 INT2 __attribute__ ((__unavailable__("You can't use
INT2")));
+
+typedef INT1 INT1a; /* { dg-error "'INT1' is unavailable: You can't use
INT1" "" } */
+typedef INT1 INT1b __attribute__ ((unavailable("You can't use INT1b")));
+
+INT1 should_be_unavailable; /* { dg-error "'INT1' is unavailable: You
can't
use INT1" "" } */
+INT1a should_not_be_unavailable;
+
+INT1 f1(void) __attribute__ ((unavailable("You can't use f1")));
+INT1 f2(void) { return 0; } /* { dg-error "'INT1' is unavailable: You
can't
use INT1" "" } */
+
+INT2 f3(void) __attribute__ ((__unavailable__("You can't use f3")));
+INT2 f4(void) { return 0; } /* { dg-error "'INT2' is unavailable: You
can't
use INT2" "" } */
+int f5(INT2 x); /* { dg-error "'INT2' is unavailable: You can't use INT2"
"" } */
+int f6(INT2 x) __attribute__ ((__unavailable__("You can't use f6")));
/* {
dg-error "'INT2' is unavailable: You can't use INT2" "" } */
+
+typedef enum {red, green, blue} Color __attribute__((unavailable("You
can't
use Color")));
+
+int g1;
+int g2 __attribute__ ((unavailable("You can't use g2")));
+int g3 __attribute__ ((__unavailable__("You can't use g3")));
+Color k; /* { dg-error "'Color' is unavailable: You can't use Color" "" }
*/
+
+typedef struct {
+ int field1;
+ int field2 __attribute__ ((unavailable("You can't use field2")));
+ int field3;
+ int field4 __attribute__ ((__unavailable__("You can't use field4")));
+ union {
+ int field5;
+ int field6 __attribute__ ((unavailable("You can't use field6")));
+ } u1;
+ int field7:1;
+ int field8:1 __attribute__ ((unavailable("You can't use field8")));
+ union {
+ int field9;
+ int field10;
+ } u2 __attribute__ ((unavailable("You can't use u2")));
+} S1;
+
+int func1()
+{
+ INT1 w; /* { dg-error "'INT1' is unavailable: You can't use INT1" "" }
*/
+ int x __attribute__ ((unavailable("Avoid x")));
+ int y __attribute__ ((__unavailable__("Bad y")));
+ int z;
+ int (*pf)() = f1; /* { dg-error "'f1' is unavailable: You can't use
f1" ""
} */
+
+ z = w + x + y + g1 + g2 + g3; /* { dg-error "'x' is unavailable: Avoid
x"
"" } */
+ /* { dg-error "'y' is unavailable: Bad y" "y" { target *-*-* } .-1 } */
+ /* { dg-error "'g2' is unavailable: You can't use g2" "g2" { target
*-*-*
} .-2 } */
+ /* { dg-error "'g3' is unavailable: You can't use g3" "g3" { target
*-*-*
} .-3 } */
+ return f1(); /* { dg-error "'f1' is unavailable: You can't use f1" ""
} */
+}
+
+int func2(S1 *p)
+{
+ S1 lp;
+
+ if (p->field1)
+ return p->field2; /* { dg-error "'field2' is unavailable: You can't use
field2" "" } */
+ else if (lp.field4) /* { dg-error "'field4' is unavailable: You can't
use
field4" "" } */
+ return p->field3;
+
+ p->u1.field5 = g1 + p->field7;
+ p->u2.field9; /* { dg-error "'u2' is unavailable: You can't use u2" "" }
*/
+ return p->u1.field6 + p->field8; /* { dg-error "'field6' is unavailable:
You can't use field6" "" } */
+ /* { dg-error "'field8' is unavailable: You can't use field8" "field8" {
target *-*-* } .-1 } */
+}
+
+struct SS1 {
+ int x;
+ INT1 y; /* { dg-error "'INT1' is unavailable: You can't use INT1" "" }
*/
+} __attribute__ ((unavailable("You can't use SS1")));
+
+struct SS1 *p1; /* { dg-error "'SS1' is unavailable: You can't use SS1"
""
} */
+
+struct __attribute__ ((__unavailable__("You can't use SS2"))) SS2 {
+ int x;
+ INT1 y; /* { dg-error "'INT1' is unavailable: You can't use INT1" "" }
*/
+};
+
+struct SS2 *p2; /* { dg-error "'SS2' is unavailable: You can't use SS2"
""
} */
diff --git a/gcc/testsuite/gcc.dg/attr-unavailable-5.c
b/gcc/testsuite/gcc.dg/attr-unavailable-5.c
new file mode 100644
index 00000000000..051f960c5cf
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/attr-unavailable-5.c
@@ -0,0 +1,6 @@
+/* Test __attribute__((unavailable)). Test types without names. */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+struct { int a; } __attribute__((unavailable ("Do not use"))) x; /* {
dg-error "type is unavailable" } */
+typeof(x) y; /* { dg-error "type is unavailable: Do not use" } */
diff --git a/gcc/testsuite/gcc.dg/attr-unavailable-6.c
b/gcc/testsuite/gcc.dg/attr-unavailable-6.c
new file mode 100644
index 00000000000..f5f4560c735
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/attr-unavailable-6.c
@@ -0,0 +1,11 @@
+/* Test __attribute__((unavailable)). Test merging with multiple
+ declarations. */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+void func(void);
+void func(void) __attribute__((unavailable ("Do not use")));
+
+void f(void) {
+ func(); /* { dg-error "'func' is unavailable: Do not use" } */
+}
diff --git a/gcc/testsuite/obj-c++.dg/attributes/method-unavailable-1.mm
b/gcc/testsuite/obj-c++.dg/attributes/method-unavailable-1.mm
new file mode 100644
index 00000000000..e5708c202c0
--- /dev/null
+++ b/gcc/testsuite/obj-c++.dg/attributes/method-unavailable-1.mm
@@ -0,0 +1,34 @@
+/* Test __attribute__ ((unavailable)) */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+#include <objc/objc.h>
+
+@interface MyClass
+{
+ Class isa;
+}
++ (int) method;
+- (int) method;
++ (int) unavailableClassMethod __attribute__((unavailable));
+- (int) unavailableInstanceMethod __attribute__((unavailable));
+@end
+
+/* Test that deprecation warnings are produced, but not if the
+ receiver is of type 'id'. */
+void foo (void)
+{
+ Class c;
+ id object;
+ MyClass *another_object;
+
+ [c method];
+ [object method];
+ [c unavailableClassMethod];
+ [object unavailableInstanceMethod];
+
+ [object method];
+ [another_object method];
+ [MyClass unavailableClassMethod]; /* { dg-error "is unavailable" } */
+ [another_object unavailableInstanceMethod]; /* { dg-error "is
unavailable"
} */
+}
diff --git a/gcc/testsuite/obj-c++.dg/attributes/method-unavailable-2.mm
b/gcc/testsuite/obj-c++.dg/attributes/method-unavailable-2.mm
new file mode 100644
index 00000000000..68ea46d2543
--- /dev/null
+++ b/gcc/testsuite/obj-c++.dg/attributes/method-unavailable-2.mm
@@ -0,0 +1,24 @@
+/* Test __attribute__ ((unavailable)) */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+#include <objc/objc.h>
+
+@interface MyClass
+{
+ Class isa;
+}
++ (int) unavailableClassMethod: (id)firstObject, ...
__attribute__((sentinel)) __attribute__((unavailable));
+- (int) unavailableInstanceMethod: (id)firstobject, ...
__attribute__((sentinel)) __attribute__((unavailable));
+@end
+
+/* Test that unavailability errors are produced even if the method is
+ also marked with another attribute too (this is to test the
+ processing of multiple attributes). */
+void foo (void)
+{
+ MyClass *object = nil;
+
+ [MyClass unavailableClassMethod: object, nil]; /* { dg-error "is
unavailable" } */
+ [object unavailableInstanceMethod: object, nil]; /* { dg-error "is
unavailable" } */
+}
diff --git a/gcc/testsuite/obj-c++.dg/attributes/method-unavailable-3.mm
b/gcc/testsuite/obj-c++.dg/attributes/method-unavailable-3.mm
new file mode 100644
index 00000000000..9e55ae11e1f
--- /dev/null
+++ b/gcc/testsuite/obj-c++.dg/attributes/method-unavailable-3.mm
@@ -0,0 +1,22 @@
+/* Test __attribute__ ((unavailable)) */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+#include <objc/objc.h>
+
+/* Test that __attribute__ ((__unavailable__)) works as well as
__attribute__ ((unavailable)). */
+@interface MyClass
+{
+ Class isa;
+}
++ (int) unavailableClassMethod: (id)firstObject, ...
__attribute__((__unavailable__));
+- (int) unavailableInstanceMethod: (id)firstobject, ...
__attribute__((__unavailable__));
+@end
+
+void foo (void)
+{
+ MyClass *object = nil;
+
+ [MyClass unavailableClassMethod: object, nil]; /* { dg-error "is
unavailable" } */
+ [object unavailableInstanceMethod: object, nil]; /* { dg-error "is
unavailable" } */
+}
diff --git
a/gcc/testsuite/obj-c++.dg/property/at-property-unavailable-1.mm
b/gcc/testsuite/obj-c++.dg/property/at-property-unavailable-1.mm
new file mode 100644
index 00000000000..6bb4755220d
--- /dev/null
+++ b/gcc/testsuite/obj-c++.dg/property/at-property-unavailable-1.mm
@@ -0,0 +1,38 @@
+/* Test __attribute__ ((unavailable)) */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+/* Test that properties can be unavailable. */
+
+#include <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@interface MyRootClass
+{
+ Class isa;
+ int a;
+}
+@property int a __attribute__((unavailable));
++ (id) initialize;
++ (id) alloc;
+- (id) init;
+@end
+
+@implementation MyRootClass
++ (id) initialize { return self; }
++ (id) alloc { return class_createInstance (self, 0); }
+- (id) init { return self; }
+@synthesize a;
+@end
+
+int main (void)
+{
+ MyRootClass *object = [[MyRootClass alloc] init];
+
+ object.a = 40; /* { dg-error "is unavailable" } */
+ if (object.a != 40) /* { dg-error "is unavailable" } */
+ abort ();
+
+ return (0);
+}
diff --git
a/gcc/testsuite/obj-c++.dg/property/at-property-unavailable-2.mm
b/gcc/testsuite/obj-c++.dg/property/at-property-unavailable-2.mm
new file mode 100644
index 00000000000..5edc1626c89
--- /dev/null
+++ b/gcc/testsuite/obj-c++.dg/property/at-property-unavailable-2.mm
@@ -0,0 +1,26 @@
+/* Test __attribute__ ((unavailable)) */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+/* Test that unavailability errors are produced when a setter/getter of
+ a @property is used directly. */
+
+#include <objc/objc.h>
+
+@interface MyClass
+{
+ Class isa;
+ int variable;
+}
+@property (assign, nonatomic) int property __attribute__ ((unavailable));
+@end
+
+void foo (void)
+{
+ MyClass *object = nil;
+
+ if ([object property] > 0) /* { dg-error "is unavailable" } */
+ {
+ [object setProperty: 43]; /* { dg-error "is unavailable" } */
+ }
+}
diff --git a/gcc/testsuite/obj-c++.dg/property/dotsyntax-unavailable-1.mm
b/gcc/testsuite/obj-c++.dg/property/dotsyntax-unavailable-1.mm
new file mode 100644
index 00000000000..e2ef2a5b23b
--- /dev/null
+++ b/gcc/testsuite/obj-c++.dg/property/dotsyntax-unavailable-1.mm
@@ -0,0 +1,42 @@
+/* Test __attribute__ ((unavailable)) */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+/* Test the 'dot syntax' with unavailable methods. */
+
+#include <objc/objc.h>
+
+@interface MyClass
+{
+ Class isa;
+}
++ (int) classCount __attribute__ ((unavailable));
++ (void) setClassCount: (int)value __attribute__ ((unavailable));
+
+- (int) count __attribute__ ((unavailable));
+- (void) setCount: (int)value __attribute__ ((unavailable));
+
+- (int) classCount2;
+- (void) setClassCount2: (int)value;
+
+- (int) count2;
+- (void) setCount2: (int)value;
+@end
+
+void foo (void)
+{
+ MyClass *object = nil;
+
+
+ if (object.count > 0) /* { dg-error "is unavailable" } */
+ object.count = 20; /* { dg-error "is unavailable" } */
+
+ if (MyClass.classCount < -7) /* { dg-error "is unavailable" } */
+ MyClass.classCount = 11; /* { dg-error "is unavailable" } */
+
+ if (object.classCount2 > 0)
+ object.classCount2 = 19;
+
+ if (object.count2 < -7)
+ object.count2 = 74;
+}
diff --git a/gcc/testsuite/objc.dg/attributes/method-unavailable-1.m
b/gcc/testsuite/objc.dg/attributes/method-unavailable-1.m
new file mode 100644
index 00000000000..7a3de6b245d
--- /dev/null
+++ b/gcc/testsuite/objc.dg/attributes/method-unavailable-1.m
@@ -0,0 +1,34 @@
+/* Test __attribute__ ((unavailable)) */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+#include <objc/objc.h>
+
+@interface MyClass
+{
+ Class isa;
+}
++ (int) method;
+- (int) method;
++ (int) unavailableClassMethod __attribute__((unavailable));
+- (int) unavailableInstanceMethod __attribute__((unavailable));
+@end
+
+/* Test that unavailability errors are produced, but not if the
+ receiver is of type 'id'. */
+void foo (void)
+{
+ Class c;
+ id object;
+ MyClass *another_object;
+
+ [c method];
+ [object method];
+ [c unavailableClassMethod];
+ [object unavailableInstanceMethod];
+
+ [object method];
+ [another_object method];
+ [MyClass unavailableClassMethod]; /* { dg-error "is unavailable" } */
+ [another_object unavailableInstanceMethod]; /* { dg-error "is
unavailable"
} */
+}
diff --git a/gcc/testsuite/objc.dg/attributes/method-unavailable-2.m
b/gcc/testsuite/objc.dg/attributes/method-unavailable-2.m
new file mode 100644
index 00000000000..68ea46d2543
--- /dev/null
+++ b/gcc/testsuite/objc.dg/attributes/method-unavailable-2.m
@@ -0,0 +1,24 @@
+/* Test __attribute__ ((unavailable)) */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+#include <objc/objc.h>
+
+@interface MyClass
+{
+ Class isa;
+}
++ (int) unavailableClassMethod: (id)firstObject, ...
__attribute__((sentinel)) __attribute__((unavailable));
+- (int) unavailableInstanceMethod: (id)firstobject, ...
__attribute__((sentinel)) __attribute__((unavailable));
+@end
+
+/* Test that unavailability errors are produced even if the method is
+ also marked with another attribute too (this is to test the
+ processing of multiple attributes). */
+void foo (void)
+{
+ MyClass *object = nil;
+
+ [MyClass unavailableClassMethod: object, nil]; /* { dg-error "is
unavailable" } */
+ [object unavailableInstanceMethod: object, nil]; /* { dg-error "is
unavailable" } */
+}
diff --git a/gcc/testsuite/objc.dg/attributes/method-unavailable-3.m
b/gcc/testsuite/objc.dg/attributes/method-unavailable-3.m
new file mode 100644
index 00000000000..9e55ae11e1f
--- /dev/null
+++ b/gcc/testsuite/objc.dg/attributes/method-unavailable-3.m
@@ -0,0 +1,22 @@
+/* Test __attribute__ ((unavailable)) */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+#include <objc/objc.h>
+
+/* Test that __attribute__ ((__unavailable__)) works as well as
__attribute__ ((unavailable)). */
+@interface MyClass
+{
+ Class isa;
+}
++ (int) unavailableClassMethod: (id)firstObject, ...
__attribute__((__unavailable__));
+- (int) unavailableInstanceMethod: (id)firstobject, ...
__attribute__((__unavailable__));
+@end
+
+void foo (void)
+{
+ MyClass *object = nil;
+
+ [MyClass unavailableClassMethod: object, nil]; /* { dg-error "is
unavailable" } */
+ [object unavailableInstanceMethod: object, nil]; /* { dg-error "is
unavailable" } */
+}
diff --git a/gcc/testsuite/objc.dg/property/at-property-unavailable-1.m
b/gcc/testsuite/objc.dg/property/at-property-unavailable-1.m
new file mode 100644
index 00000000000..855ccc6b028
--- /dev/null
+++ b/gcc/testsuite/objc.dg/property/at-property-unavailable-1.m
@@ -0,0 +1,38 @@
+/* Test __attribute__ ((unavailable)) */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+/* Test that properties can be unavailable. */
+
+#include <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@interface MyRootClass
+{
+ Class isa;
+ int a;
+}
+@property int a __attribute__((unavailable));
++ (id) initialize;
++ (id) alloc;
+- (id) init;
+@end
+
+@implementation MyRootClass
++ (id) initialize { return self; }
++ (id) alloc { return class_createInstance (self, 0); }
+- (id) init { return self; }
+@synthesize a;
+@end
+
+int main (void)
+{
+ MyRootClass *object = [[MyRootClass alloc] init];
+
+ object.a = 40; /* { dg-error "is unavailable" } */
+ if (object.a != 40) /* { dg-error "is unavailable" } */
+ abort ();
+
+ return 0;
+}
diff --git a/gcc/testsuite/objc.dg/property/at-property-unavailable-2.m
b/gcc/testsuite/objc.dg/property/at-property-unavailable-2.m
new file mode 100644
index 00000000000..5edc1626c89
--- /dev/null
+++ b/gcc/testsuite/objc.dg/property/at-property-unavailable-2.m
@@ -0,0 +1,26 @@
+/* Test __attribute__ ((unavailable)) */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+/* Test that unavailability errors are produced when a setter/getter of
+ a @property is used directly. */
+
+#include <objc/objc.h>
+
+@interface MyClass
+{
+ Class isa;
+ int variable;
+}
+@property (assign, nonatomic) int property __attribute__ ((unavailable));
+@end
+
+void foo (void)
+{
+ MyClass *object = nil;
+
+ if ([object property] > 0) /* { dg-error "is unavailable" } */
+ {
+ [object setProperty: 43]; /* { dg-error "is unavailable" } */
+ }
+}
diff --git a/gcc/testsuite/objc.dg/property/dotsyntax-unavailable-1.m
b/gcc/testsuite/objc.dg/property/dotsyntax-unavailable-1.m
new file mode 100644
index 00000000000..e2ef2a5b23b
--- /dev/null
+++ b/gcc/testsuite/objc.dg/property/dotsyntax-unavailable-1.m
@@ -0,0 +1,42 @@
+/* Test __attribute__ ((unavailable)) */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+/* Test the 'dot syntax' with unavailable methods. */
+
+#include <objc/objc.h>
+
+@interface MyClass
+{
+ Class isa;
+}
++ (int) classCount __attribute__ ((unavailable));
++ (void) setClassCount: (int)value __attribute__ ((unavailable));
+
+- (int) count __attribute__ ((unavailable));
+- (void) setCount: (int)value __attribute__ ((unavailable));
+
+- (int) classCount2;
+- (void) setClassCount2: (int)value;
+
+- (int) count2;
+- (void) setCount2: (int)value;
+@end
+
+void foo (void)
+{
+ MyClass *object = nil;
+
+
+ if (object.count > 0) /* { dg-error "is unavailable" } */
+ object.count = 20; /* { dg-error "is unavailable" } */
+
+ if (MyClass.classCount < -7) /* { dg-error "is unavailable" } */
+ MyClass.classCount = 11; /* { dg-error "is unavailable" } */
+
+ if (object.classCount2 > 0)
+ object.classCount2 = 19;
+
+ if (object.count2 < -7)
+ object.count2 = 74;
+}
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index c9280a8d3b1..2d074280407 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -1001,7 +1001,8 @@ struct GTY(()) tree_base {
unsigned user_align : 1;
unsigned nameless_flag : 1;
unsigned atomic_flag : 1;
- unsigned spare0 : 3;
+ unsigned unavailable_flag : 1;
+ unsigned spare0 : 2;
unsigned spare1 : 8;
@@ -1370,6 +1371,13 @@ struct GTY(()) tree_base {
CALL_EXPR_BY_DESCRIPTOR in
CALL_EXPR
+
+ unavailable_flag:
+
+ TREE_UNAVAILABLE in
+ all decls
+ all types
+
*/
struct GTY(()) tree_typed {
diff --git a/gcc/tree.c b/gcc/tree.c
index 9260772b846..ea3f87650dd 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -13162,6 +13162,78 @@ warn_deprecated_use (tree node, tree attr)
return w;
}
+/* Error out with an identifier which was marked 'unavailable'. */
+void
+error_unavailable_use (tree node, tree attr)
+{
+ escaped_string msg;
+
+ if (node == 0)
+ return;
+
+ if (!attr)
+ {
+ if (DECL_P (node))
+ attr = DECL_ATTRIBUTES (node);
+ else if (TYPE_P (node))
+ {
+ tree decl = TYPE_STUB_DECL (node);
+ if (decl)
+ attr = lookup_attribute ("unavailable",
+ TYPE_ATTRIBUTES (TREE_TYPE (decl)));
+ }
+ }
+
+ if (attr)
+ attr = lookup_attribute ("unavailable", attr);
+
+ if (attr)
+ msg.escape (TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr))));
+
+ if (DECL_P (node))
+ {
+ auto_diagnostic_group d;
+ if (msg)
+ error ("%qD is unavailable: %s", node, (const char *) msg);
+ else
+ error ("%qD is unavailable", node);
+ inform (DECL_SOURCE_LOCATION (node), "declared here");
+ }
+ else if (TYPE_P (node))
+ {
+ tree what = NULL_TREE;
+ tree decl = TYPE_STUB_DECL (node);
+
+ if (TYPE_NAME (node))
+ {
+ if (TREE_CODE (TYPE_NAME (node)) == IDENTIFIER_NODE)
+ what = TYPE_NAME (node);
+ else if (TREE_CODE (TYPE_NAME (node)) == TYPE_DECL
+ && DECL_NAME (TYPE_NAME (node)))
+ what = DECL_NAME (TYPE_NAME (node));
+ }
+
+ auto_diagnostic_group d;
+ if (what)
+ {
+ if (msg)
+ error ("%qE is unavailable: %s", what, (const char *) msg);
+ else
+ error ("%qE is unavailable", what);
+ }
+ else
+ {
+ if (msg)
+ error ("type is unavailable: %s", (const char *) msg);
+ else
+ error ("type is unavailable");
+ }
+
+ if (decl)
+ inform (DECL_SOURCE_LOCATION (decl), "declared here");
+ }
+}
+
/* Return true if REF has a COMPONENT_REF with a bit-field field
declaration
somewhere in it. */
diff --git a/gcc/tree.h b/gcc/tree.h
index f8f0a606439..e8a9c90f234 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -952,6 +952,11 @@ extern void omp_clause_range_check_failed
(const_tree,
const char *, int,
#define TREE_DEPRECATED(NODE) \
((NODE)->base.deprecated_flag)
+/* Nonzero in a _DECL if the use of the name is defined as an
+ unavailable feature by __attribute__((unavailable)). */
+#define TREE_UNAVAILABLE(NODE) \
+ ((NODE)->base.u.bits.unavailable_flag)
+
/* Nonzero indicates an IDENTIFIER_NODE that names an anonymous
aggregate, (as created by anon_aggr_name_format). */
#define IDENTIFIER_ANON_P(NODE) \
@@ -5120,6 +5125,7 @@ extern const_tree strip_invariant_refs (const_tree);
extern tree lhd_gcc_personality (void);
extern void assign_assembler_name_if_needed (tree);
extern bool warn_deprecated_use (tree, tree);
+extern void error_unavailable_use (tree, tree);
extern void cache_integer_cst (tree);
extern const char *combined_fn_name (combined_fn);
--
2.24.1