Hi again, here is an updated patch for a new warning about redundant access-specifiers. It takes Dave's various comments into account.
The main changes w.r.t. to the previous versions are: * The warning is now a two-level warning with a slightly shorter name: -Waccess-specifiers=1, -Waccess-specifiers=2 with -Waccess-specifiers defaulting to -Waccess-specifiers=1. * The warning now checks for 3 different scenarios, see testcase Waccess-specifiers-2.C below: A) Two consecutive access-specifiers, so that the first one has no effect. (This is new.) B) Two (non-consecutive) equal access-specifiers. (That's what the original patch checked.) C) An access-specifier that does not change the class-type's default. (That's what I only suggested in the original patch.) The first two tests are enabled in level 1, the last in level 2. * The warning is now in a separate function. * The fix-it hints now include the colon after the access-specifier. * There's a testcase for the fix-it hints. What's missing from Dave's comments are some examples for invoke.texi. I'll work on that once the warning made it into the trunk. The switch statement in cp_parser_maybe_warn_access_specifier is a little bit ugly. It would be nicer to emit the warnings directly next to the checks. But then I'd have to write the code for the fix-it hint 3 times. With C++11 I'd use a lambda for this, but with C++03 I hope the switch is OK. Bootstrapped and regtested on x86_64-pc-linux-gnu. OK for trunk? Regards, Volker 2017-07-22 Volker Reichelt <v.reich...@netcologne.de> * doc/invoke.texi (-Waccess-specifiers, -Waccess-specifiers=): Document new warning options. Index: gcc/doc/invoke.texi =================================================================== --- gcc/doc/invoke.texi (revision 250356) +++ gcc/doc/invoke.texi (working copy) @@ -259,7 +259,8 @@ @xref{Warning Options,,Options to Request or Suppress Warnings}. @gccoptlist{-fsyntax-only -fmax-errors=@var{n} -Wpedantic @gol -pedantic-errors @gol --w -Wextra -Wall -Waddress -Waggregate-return @gol +-w -Wextra -Wall -Waccess-specifiers -Waccess-specifiers=@var{n} @gol +-Waddress -Waggregate-return @gol -Walloc-zero -Walloc-size-larger-than=@var{n} -Walloca -Walloca-larger-than=@var{n} @gol -Wno-aggressive-loop-optimizations -Warray-bounds -Warray-bounds=@var{n} @gol @@ -5254,6 +5255,13 @@ Warn about overriding virtual functions that are not marked with the override keyword. +@item -Waccess-specifiers @r{(C++ and Objective-C++ only)} +@itemx -Waccess-specifiers=@var{n} +@opindex Wno-access-specifiers +@opindex Waccess-specifiers +Warn when an access-specifier is redundant because it was already given +before. + @item -Walloc-zero @opindex Wno-alloc-zero @opindex Walloc-zero =================================================================== 2017-07-22 Volker Reichelt <v.reich...@netcologne.de> * c.opt (Waccess-specifiers=): New C++ warning flag. (Waccess-specifiers): New alias. Index: gcc/c-family/c.opt =================================================================== --- gcc/c-family/c.opt (revision 250443) +++ gcc/c-family/c.opt (working copy) @@ -476,6 +476,14 @@ C ObjC C++ ObjC++ Var(warn_div_by_zero) Init(1) Warning Warn about compile-time integer division by zero. +Waccess-specifiers +C++ ObjC++ Warning Alias(Waccess-specifiers=, 1, 0) +Warn about redundant access-specifiers. + +Waccess-specifiers= +C++ ObjC++ Var(warn_access_specifiers) Warning Joined RejectNegative UInteger +Warn about redundant access-specifiers. + Wduplicated-branches C ObjC C++ ObjC++ Var(warn_duplicated_branches) Init(0) Warning Warn about duplicated branches in if-else statements. =================================================================== 2017-07-22 Volker Reichelt <v.reich...@netcologne.de> * cp-tree.h (struct saved_scope): New access_specifier_loc variable. (current_access_specifier_loc): New macro. * class.c (struct class_stack_node): New access_loc variable. (pushclass): Push current_access_specifier_loc. Set new initial value. (popclass): Pop current_access_specifier_loc. * parser.c (cp_parser_maybe_warn_access_specifier): New function to warn about duplicated access-specifiers. (cp_parser_member_specification_opt): Call it. Set current_access_specifier_loc. Index: gcc/cp/class.c =================================================================== --- gcc/cp/class.c (revision 250443) +++ gcc/cp/class.c (working copy) @@ -60,6 +60,7 @@ /* The access specifier pending for new declarations in the scope of this class. */ tree access; + location_t access_loc; /* If were defining TYPE, the names used in this class. */ splay_tree names_used; @@ -7724,6 +7725,7 @@ csn->name = current_class_name; csn->type = current_class_type; csn->access = current_access_specifier; + csn->access_loc = current_access_specifier_loc; csn->names_used = 0; csn->hidden = 0; current_class_depth++; @@ -7739,6 +7741,7 @@ current_access_specifier = (CLASSTYPE_DECLARED_CLASS (type) ? access_private_node : access_public_node); + current_access_specifier_loc = UNKNOWN_LOCATION; if (previous_class_level && type != previous_class_level->this_entity @@ -7778,6 +7781,7 @@ current_class_name = current_class_stack[current_class_depth].name; current_class_type = current_class_stack[current_class_depth].type; current_access_specifier = current_class_stack[current_class_depth].access; + current_access_specifier_loc = current_class_stack[current_class_depth].access_loc; if (current_class_stack[current_class_depth].names_used) splay_tree_delete (current_class_stack[current_class_depth].names_used); } Index: gcc/cp/cp-tree.h =================================================================== --- gcc/cp/cp-tree.h (revision 250443) +++ gcc/cp/cp-tree.h (working copy) @@ -1531,6 +1531,7 @@ tree class_name; tree class_type; tree access_specifier; + source_location access_specifier_loc; tree function_decl; vec<tree, va_gc> *lang_base; tree lang_name; @@ -1592,6 +1593,7 @@ class, or union). */ #define current_access_specifier scope_chain->access_specifier +#define current_access_specifier_loc scope_chain->access_specifier_loc /* Pointer to the top of the language name stack. */ Index: gcc/cp/parser.c =================================================================== --- gcc/cp/parser.c (revision 250453) +++ gcc/cp/parser.c (working copy) @@ -23082,6 +23082,69 @@ return; } +/* Warn about redundant access-specifiers. */ + +static void +cp_parser_maybe_warn_access_specifier (cp_parser* parser) +{ + cp_token *token = cp_lexer_peek_token (parser->lexer); + cp_token *colon_token = cp_lexer_peek_nth_token (parser->lexer, 2); + cp_token *next_token = cp_lexer_peek_nth_token (parser->lexer, 3); + + int message_id = 0; + + /* Check for two consecutive access-specifiers. */ + if (colon_token->type == CPP_COLON && (next_token->keyword == RID_PUBLIC + || next_token->keyword == RID_PROTECTED + || next_token->keyword == RID_PRIVATE)) + message_id = 1; + /* Check for access-specifiers not changing access. */ + else if (current_access_specifier == token->u.value) + { + if (current_access_specifier_loc != UNKNOWN_LOCATION) + message_id = 2; + else if (warn_access_specifiers > 1) + message_id = 3; + } + + if (!message_id) + return; + + /* Emit warning. */ + gcc_rich_location richloc (token->location); + richloc.add_fixit_remove (); + if (colon_token->type == CPP_COLON) + richloc.add_fixit_remove (colon_token->location); + + switch (message_id) + { + case 1: + warning_at_rich_loc (&richloc, OPT_Waccess_specifiers_, + "redundant %qE access-specifier", + token->u.value); + inform (next_token->location, "directly followed by another one here"); + break; + + case 2: + warning_at_rich_loc (&richloc, OPT_Waccess_specifiers_, + "duplicate %qE access-specifier", + token->u.value); + inform (current_access_specifier_loc, + "same access-specifier was previously given here"); + break; + + case 3: + warning_at_rich_loc (&richloc, OPT_Waccess_specifiers_, + "access-specifier %qE is redundant within %qs", + token->u.value, + class_key_or_enum_as_string (current_class_type)); + break; + + default: + gcc_unreachable (); + } +} + /* Parse an (optional) member-specification. member-specification: @@ -23111,10 +23174,15 @@ case RID_PUBLIC: case RID_PROTECTED: case RID_PRIVATE: + /* Warn about redundant access-specifiers. */ + if (warn_access_specifiers) + cp_parser_maybe_warn_access_specifier (parser); + /* Consume the access-specifier. */ cp_lexer_consume_token (parser->lexer); /* Remember which access-specifier is active. */ current_access_specifier = token->u.value; + current_access_specifier_loc = token->location; /* Look for the `:'. */ cp_parser_require (parser, CPP_COLON, RT_COLON); break; =================================================================== 2017-07-22 Volker Reichelt <v.reich...@netcologne.de> * g++.dg/warn/Waccess-specifiers-1.C: New test. * g++.dg/warn/Waccess-specifiers-2.C: New test. Index: gcc/testsuite/g++.dg/warn/Waccess-specifiers-1.C =================================================================== --- gcc/testsuite/g++.dg/warn/Waccess-specifiers-1.C 2017-07-22 +++ gcc/testsuite/g++.dg/warn/Waccess-specifiers-1.C 2017-07-22 @@ -0,0 +1,38 @@ +// { dg-options "-Waccess-specifiers" } + +struct A +{ + int i; + public: // { dg-message "previously" } + int j; + public: // { dg-warning "duplicate 'public' access-specifier" } + int k; + protected: // { dg-message "previously" } + + class B + { + private: // { dg-message "previously" } + int m; + private: // { dg-warning "duplicate 'private' access-specifier" } + int n; + protected: // { dg-warning "redundant 'protected' access-specifier" } + public: // { dg-message "directly followed" } + }; + + protected: // { dg-warning "duplicate 'protected' access-specifier" } + void a(); + public: + void b(); + private: // { dg-message "previously" } + void c(); + private: // { dg-warning "duplicate 'private' access-specifier" } + void d(); + public: + void e(); + protected: // { dg-message "previously" } + void f(); + protected: // { dg-warning "duplicate 'protected' access-specifier" } + // { dg-message "previously" "" { target *-*-* } .-1 } + void g(); + protected: // { dg-warning "duplicate 'protected' access-specifier" } +}; Index: gcc/testsuite/g++.dg/warn/Waccess-specifiers-2.C =================================================================== --- gcc/testsuite/g++.dg/warn/Waccess-specifiers-2.C 2017-07-22 +++ gcc/testsuite/g++.dg/warn/Waccess-specifiers-2.C 2017-07-22 @@ -0,0 +1,44 @@ +// { dg-options "-Waccess-specifiers=2 -fdiagnostics-show-caret" } + +class A +{ + public: /* { dg-warning "access-specifier" } + { dg-begin-multiline-output "" } + public: + ^~~~~~ + ------- + { dg-end-multiline-output "" } */ + + private: /* { dg-message "directly followed" } + { dg-begin-multiline-output "" } + private: + ^~~~~~~ + { dg-end-multiline-output "" } */ +}; + +struct B +{ + protected: /* { dg-message "previously" } + { dg-begin-multiline-output "" } + protected: + ^~~~~~~~~ + { dg-end-multiline-output "" } */ + B(); + + protected : /* { dg-warning "access-specifier" } + { dg-begin-multiline-output "" } + protected : + ^~~~~~~~~ + --------- - + { dg-end-multiline-output "" } */ +}; + +class C +{ + private: /* { dg-warning "redundant within" } + { dg-begin-multiline-output "" } + private: + ^~~~~~~ + -------- + { dg-end-multiline-output "" } */ +};