C-family, Objective-C [1/3] : Implement Wobjc-root-class [PR77404].

This warning catches the case that the user has left the
superclass specification from a class interface.  Root
classes are, of course, permitted and an attribute is added
to mark these so that the diagnostic is suppressed.

The warning and attribute spellings have been kept in sync
with the language reference implementation (clang).

The diagnostic location information present in the objective-c
interface and class definitions is relatively poor.  This patch
adds a location for the class name to the interface and makes use
of it in existing warnings.

Part 1 is the changes to code and added tests.

Many entries in the testsuite make use of root classes so
there are a large number of mechanical changes there adding
"-Wno-objc-root-class" to the options.

The test changes are parts 2 (objective-c) and 3 (objective-c++)
in the patch series.

gcc/c-family/ChangeLog:

	PR objc/77404
	* c-attribs.c (handle_objc_root_class_attribute): New
	* c-objc.h (objc_start_class_interface): Add a location
	value for the position of the class name.
	* c.opt: Add Wobjc-root-class.
	* stub-objc.c (objc_start_class_interface): Add a location
	value for the position of the class name.

gcc/c/ChangeLog:

	PR objc/77404
	* c-parser.c (c_parser_objc_class_definition): Pass the
	location of the class name to the interface declaration.

gcc/cp/ChangeLog:

	PR objc/77404
	* parser.c (cp_parser_objc_class_interface): Pass the
	location of the class name to the interface declaration.

gcc/objc/ChangeLog:

	PR objc/77404
	* objc-act.c (objc_start_class_interface): Accept the location
	of the class name, use it in existing diagnostic.
	(start_class): Accept obj_root_class type attributes.  Warn when
	the interface for an implementation does not contain a super
	class (unless the diagnostic is suppressed by the the command
	line flag or the objc_root_class type attribute).

gcc/testsuite/ChangeLog:

	PR objc/77404
	* objc.dg/attributes/root-class-01.m: New test.
	* objc.dg/root-class-00.m: New test.
	* obj-c++.dg/attributes/root-class-01.mm: New test.
	* obj-c++.dg/root-class-00.mm: New test.

gcc/ChangeLog:

	PR objc/77404
	* doc/extend.texi: Document the objc_root_class attribute.
	* doc/invoke.texi: Document -Wobjc-root-class.
This commit is contained in:
Iain Sandoe 2020-10-25 07:49:16 +00:00
parent 4852c3266e
commit 3fe07cdec8
13 changed files with 96 additions and 6 deletions

View File

@ -158,6 +158,7 @@ static tree handle_patchable_function_entry_attribute (tree *, tree, tree,
int, bool *);
static tree handle_copy_attribute (tree *, tree, tree, int, bool *);
static tree handle_nsobject_attribute (tree *, tree, tree, int, bool *);
static tree handle_objc_root_class_attribute (tree *, tree, tree, int, bool *);
/* Helper to define attribute exclusions. */
#define ATTR_EXCL(name, function, type, variable) \
@ -513,6 +514,8 @@ const struct attribute_spec c_common_attribute_table[] =
/* Attributes used by Objective-C. */
{ "NSObject", 0, 0, true, false, false, false,
handle_nsobject_attribute, NULL },
{ "objc_root_class", 0, 0, true, false, false, false,
handle_objc_root_class_attribute, NULL },
{ NULL, 0, 0, false, false, false, false, NULL, NULL }
};
@ -5163,6 +5166,22 @@ handle_nsobject_attribute (tree *node, tree name, tree args,
return NULL_TREE;
}
/* Handle a "objc_root_class" attributes; arguments as in
struct attribute_spec.handler. */
static tree
handle_objc_root_class_attribute (tree */*node*/, tree name, tree /*args*/,
int /*flags*/, bool *no_add_attrs)
{
/* This has no meaning outside Objective-C. */
if (!c_dialect_objc())
warning (OPT_Wattributes, "%qE is only applicable to Objective-C"
" class interfaces, attribute ignored", name);
*no_add_attrs = true;
return NULL_TREE;
}
/* Attempt to partially validate a single attribute ATTR as if
it were to be applied to an entity OPER. */

View File

@ -124,7 +124,7 @@ extern tree objc_get_protocol_qualified_type (tree, tree);
extern tree objc_get_class_reference (tree);
extern tree objc_get_class_ivars (tree);
extern bool objc_detect_field_duplicates (bool);
extern void objc_start_class_interface (tree, tree, tree, tree);
extern void objc_start_class_interface (tree, location_t, tree, tree, tree);
extern void objc_start_category_interface (tree, tree, tree, tree);
extern void objc_start_protocol (tree, tree, tree);
extern void objc_continue_interface (void);

View File

@ -1002,6 +1002,11 @@ Enum(cpp_normalize_level) String(id) Value(normalized_identifier_C)
EnumValue
Enum(cpp_normalize_level) String(nfc) Value(normalized_C)
Wobjc-root-class
ObjC ObjC++ Var(warn_objc_root_class) Warning Init(1)
Warn if a class interface has no superclass. Root classes may use an attribute
to suppress this warning.
Wold-style-cast
C++ ObjC++ Var(warn_old_style_cast) Warning
Warn if a C-style cast is used in a program.

View File

@ -137,6 +137,7 @@ objc_set_method_opt (bool ARG_UNUSED (optional))
void
objc_start_class_interface (tree ARG_UNUSED (name),
location_t /*name_loc*/,
tree ARG_UNUSED (super),
tree ARG_UNUSED (protos),
tree ARG_UNUSED (attribs))

View File

@ -10801,6 +10801,7 @@ c_parser_objc_class_definition (c_parser *parser, tree attributes)
return;
}
id1 = c_parser_peek_token (parser)->value;
location_t loc1 = c_parser_peek_token (parser)->location;
c_parser_consume_token (parser);
if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
{
@ -10860,7 +10861,7 @@ c_parser_objc_class_definition (c_parser *parser, tree attributes)
tree proto = NULL_TREE;
if (c_parser_next_token_is (parser, CPP_LESS))
proto = c_parser_objc_protocol_refs (parser);
objc_start_class_interface (id1, superclass, proto, attributes);
objc_start_class_interface (id1, loc1, superclass, proto, attributes);
}
else
objc_start_class_implementation (id1, superclass);

View File

@ -33574,6 +33574,7 @@ cp_parser_objc_class_interface (cp_parser* parser, tree attributes)
bool is_class_extension;
cp_lexer_consume_token (parser->lexer); /* Eat '@interface'. */
location_t nam_loc = cp_lexer_peek_token (parser->lexer)->location;
name = cp_parser_identifier (parser);
if (name == error_mark_node)
{
@ -33593,7 +33594,7 @@ cp_parser_objc_class_interface (cp_parser* parser, tree attributes)
objc_start_category_interface (name, categ, protos, attributes);
else
{
objc_start_class_interface (name, super, protos, attributes);
objc_start_class_interface (name, nam_loc, super, protos, attributes);
/* Handle instance variable declarations, if any. */
cp_parser_objc_class_ivars (parser);
objc_continue_interface ();

View File

@ -8518,6 +8518,12 @@ and caught in another, the class must have default visibility.
Otherwise the two shared objects are unable to use the same
typeinfo node and exception handling will break.
@item objc_root_class @r{(Objective-C and Objective-C++ only)}
@cindex @code{objc_root_class} type attribute
This attribute marks a class as being a root class, and thus allows
the compiler to elide any warnings about a missing superclass and to
make additional checks for mandatory methods as needed.
@end table
To specify multiple attributes, separate them by commas within the

View File

@ -276,7 +276,7 @@ Objective-C and Objective-C++ Dialects}.
-fzero-link @gol
-gen-decls @gol
-Wassign-intercept -Wno-property-assign-default @gol
-Wno-protocol -Wselector @gol
-Wno-protocol -Wobjc-root-class -Wselector @gol
-Wstrict-selector-match @gol
-Wundeclared-selector}
@ -4348,6 +4348,13 @@ from the superclass. If you use the @option{-Wno-protocol} option, then
methods inherited from the superclass are considered to be implemented,
and no warning is issued for them.
@item -Wobjc-root-class @r{(Objective-C and Objective-C++ only)}
@opindex Wobjc-root-class
Warn if a class interface lacks a superclass. Most classes will inherit
from @code{NSObject} (or @code{Object}) for example. When declaring
classes intended to be root classes, the warning can be suppressed by
marking their interfaces with @code{__attribute__((objc_root_class))}.
@item -Wselector @r{(Objective-C and Objective-C++ only)}
@opindex Wselector
@opindex Wno-selector

View File

@ -571,11 +571,11 @@ lookup_protocol_in_reflist (tree rproto_list, tree lproto)
}
void
objc_start_class_interface (tree klass, tree super_class,
objc_start_class_interface (tree klass, location_t name_loc, tree super_class,
tree protos, tree attributes)
{
if (flag_objc1_only && attributes)
error_at (input_location, "class attributes are not available in Objective-C 1.0");
error_at (name_loc, "class attributes are not available in Objective-C 1.0");
objc_interface_context
= objc_ivar_context
@ -7014,6 +7014,12 @@ start_class (enum tree_code code, tree class_name, tree super_name,
CLASS_SUPER_NAME (objc_implementation_context)
= CLASS_SUPER_NAME (implementation_template);
}
if (!CLASS_SUPER_NAME (objc_implementation_context)
&& !lookup_attribute ("objc_root_class",
TYPE_ATTRIBUTES (implementation_template)))
warning (OPT_Wobjc_root_class, "class %qE defined without"
" specifying a base class", class_name);
break;
case CLASS_INTERFACE_TYPE:
@ -7044,6 +7050,8 @@ start_class (enum tree_code code, tree class_name, tree super_name,
TREE_DEPRECATED (klass) = 1;
else if (is_attribute_p ("objc_exception", name))
CLASS_HAS_EXCEPTION_ATTR (klass) = 1;
else if (is_attribute_p ("objc_root_class", name))
;
else if (is_attribute_p ("visibility", name))
;
else

View File

@ -0,0 +1,11 @@
/* Test Wobjc-root-class warning is suppressed by the objc_root_class attr.
Note that we don't issue a warning unless the TU contains an implementation
for the class. This should compile without warning. */
/* { dg-additional-options "-fsyntax-only " } */
__attribute__((objc_root_class))
@interface ARootObject
@end
@implementation ARootObject
@end

View File

@ -0,0 +1,10 @@
/* Test Wobjc-root-class.
Note that we don't issue a warning unless the TU contains an implementation
for the class. */
/* { dg-additional-options "-fsyntax-only " } */
@interface ARootObject
@end
@implementation ARootObject /* { dg-warning {class 'ARootObject' defined without specifying a base class} } */
@end

View File

@ -0,0 +1,11 @@
/* Test Wobjc-root-class warning is suppressed by the objc_root_class attr.
Note that we don't issue a warning unless the TU contains an implementation
for the class. This should compile without warning. */
/* { dg-additional-options "-fsyntax-only " } */
__attribute__((objc_root_class))
@interface ARootObject
@end
@implementation ARootObject
@end

View File

@ -0,0 +1,10 @@
/* Test Wobjc-root-class.
Note that we don't issue a warning unless the TU contains an implementation
for the class. */
/* { dg-additional-options "-fsyntax-only " } */
@interface ARootObject
@end
@implementation ARootObject
@end /* { dg-warning {class 'ARootObject' defined without specifying a base class} } */