Implement -Wshadow.
authorChristoph Mallon <christoph.mallon@gmx.de>
Sun, 21 Dec 2008 18:02:44 +0000 (18:02 +0000)
committerChristoph Mallon <christoph.mallon@gmx.de>
Sun, 21 Dec 2008 18:02:44 +0000 (18:02 +0000)
[r24841]

cparser.1
parser.c

index 0a1f873..5f103d9 100644 (file)
--- a/cparser.1
+++ b/cparser.1
@@ -1,5 +1,5 @@
 .\" Please adjust this date whenever revising the manpage.
-.Dd December 16, 2008
+.Dd December 21, 2008
 .Dt CPARSER 1
 .Sh NAME
 .Nm cparser
@@ -203,6 +203,8 @@ Warn if cascaded comparisons appear which do not have their mathematical meaning
 Warn if + or - is used as operand of << or >>, e.g. x\ +\ y\ <<\ z.
 .It Fl Wredundant-decls
 Warn about redundant declarations, i.e. multiple declarations of the same object or static forward declarations which have no use before their definition.
+.It Fl Wshadow
+Warn when a new declaration shadows another declaration with the same name in an outer scope.
 .It Fl Wunreachable-code
 Warn when the compiler determines that a statement (or in some cases a part thereof) will never be executed.
 .It Fl Wunused
index 1787cdc..808f750 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -5023,7 +5023,7 @@ static entity_t *record_entity(entity_t *entity, const bool is_definition)
        if (symbol == NULL)
                return entity;
 
-       entity_t *previous_entity = get_entity(symbol, namespc);
+       entity_t *const previous_entity = get_entity(symbol, namespc);
        /* pushing the same entity twice will break the stack structure */
        assert(previous_entity != entity);
 
@@ -5053,160 +5053,167 @@ static entity_t *record_entity(entity_t *entity, const bool is_definition)
                         entity->declaration.type, symbol);
        }
 
-       if (previous_entity != NULL &&
-                       previous_entity->base.parent_scope == &current_function->parameters &&
-                       previous_entity->base.parent_scope->depth + 1 == current_scope->depth) {
-               assert(previous_entity->kind == ENTITY_PARAMETER);
-               errorf(pos,
-                      "declaration '%#T' redeclares the parameter '%#T' (declared %P)",
-                                        entity->declaration.type, symbol,
-                                        previous_entity->declaration.type, symbol,
-                                        &previous_entity->base.source_position);
-               goto finish;
-       }
-
-       if (previous_entity != NULL &&
-                       previous_entity->base.parent_scope == current_scope) {
-               if (previous_entity->kind != entity->kind) {
-                       if (!is_error_entity(previous_entity) && !is_error_entity(entity)) {
-                               error_redefined_as_different_kind(pos, previous_entity,
-                                               entity->kind);
-                       }
-                       goto finish;
-               }
-               if (previous_entity->kind == ENTITY_ENUM_VALUE) {
-                       errorf(pos, "redeclaration of enum entry '%Y' (declared %P)",
-                                  symbol, &previous_entity->base.source_position);
-                       goto finish;
-               }
-               if (previous_entity->kind == ENTITY_TYPEDEF) {
-                       /* TODO: C++ allows this for exactly the same type */
-                       errorf(pos, "redefinition of typedef '%Y' (declared %P)",
-                              symbol, &previous_entity->base.source_position);
+       if (previous_entity != NULL) {
+               if (previous_entity->base.parent_scope == &current_function->parameters &&
+                               previous_entity->base.parent_scope->depth + 1 == current_scope->depth) {
+                       assert(previous_entity->kind == ENTITY_PARAMETER);
+                       errorf(pos,
+                                       "declaration '%#T' redeclares the parameter '%#T' (declared %P)",
+                                       entity->declaration.type, symbol,
+                                       previous_entity->declaration.type, symbol,
+                                       &previous_entity->base.source_position);
                        goto finish;
                }
 
-               /* at this point we should have only VARIABLES or FUNCTIONS */
-               assert(is_declaration(previous_entity) && is_declaration(entity));
+               if (previous_entity->base.parent_scope == current_scope) {
+                       if (previous_entity->kind != entity->kind) {
+                               if (!is_error_entity(previous_entity) && !is_error_entity(entity)) {
+                                       error_redefined_as_different_kind(pos, previous_entity,
+                                                       entity->kind);
+                               }
+                               goto finish;
+                       }
+                       if (previous_entity->kind == ENTITY_ENUM_VALUE) {
+                               errorf(pos, "redeclaration of enum entry '%Y' (declared %P)",
+                                               symbol, &previous_entity->base.source_position);
+                               goto finish;
+                       }
+                       if (previous_entity->kind == ENTITY_TYPEDEF) {
+                               /* TODO: C++ allows this for exactly the same type */
+                               errorf(pos, "redefinition of typedef '%Y' (declared %P)",
+                                               symbol, &previous_entity->base.source_position);
+                               goto finish;
+                       }
 
-               declaration_t *const prev_decl = &previous_entity->declaration;
-               declaration_t *const decl      = &entity->declaration;
+                       /* at this point we should have only VARIABLES or FUNCTIONS */
+                       assert(is_declaration(previous_entity) && is_declaration(entity));
+
+                       declaration_t *const prev_decl = &previous_entity->declaration;
+                       declaration_t *const decl      = &entity->declaration;
+
+                       /* can happen for K&R style declarations */
+                       if (prev_decl->type       == NULL             &&
+                                       previous_entity->kind == ENTITY_PARAMETER &&
+                                       entity->kind          == ENTITY_PARAMETER) {
+                               prev_decl->type                   = decl->type;
+                               prev_decl->storage_class          = decl->storage_class;
+                               prev_decl->declared_storage_class = decl->declared_storage_class;
+                               prev_decl->modifiers              = decl->modifiers;
+                               prev_decl->deprecated_string      = decl->deprecated_string;
+                               return previous_entity;
+                       }
 
-               /* can happen for K&R style declarations */
-               if (prev_decl->type       == NULL             &&
-                               previous_entity->kind == ENTITY_PARAMETER &&
-                               entity->kind          == ENTITY_PARAMETER) {
-                       prev_decl->type                   = decl->type;
-                       prev_decl->storage_class          = decl->storage_class;
-                       prev_decl->declared_storage_class = decl->declared_storage_class;
-                       prev_decl->modifiers              = decl->modifiers;
-                       prev_decl->deprecated_string      = decl->deprecated_string;
-                       return previous_entity;
-               }
+                       type_t *const orig_type = decl->type;
+                       assert(orig_type != NULL);
+                       type_t *const type      = skip_typeref(orig_type);
+                       type_t *const prev_type = skip_typeref(prev_decl->type);
 
-               type_t *const orig_type = decl->type;
-               assert(orig_type != NULL);
-               type_t *const type      = skip_typeref(orig_type);
-               type_t *const prev_type = skip_typeref(prev_decl->type);
+                       if (!types_compatible(type, prev_type)) {
+                               errorf(pos,
+                                               "declaration '%#T' is incompatible with '%#T' (declared %P)",
+                                               orig_type, symbol, prev_decl->type, symbol,
+                                               &previous_entity->base.source_position);
+                       } else {
+                               unsigned old_storage_class = prev_decl->storage_class;
+                               if (warning.redundant_decls               &&
+                                               is_definition                     &&
+                                               !prev_decl->used                  &&
+                                               !(prev_decl->modifiers & DM_USED) &&
+                                               prev_decl->storage_class == STORAGE_CLASS_STATIC) {
+                                       warningf(&previous_entity->base.source_position,
+                                                       "unnecessary static forward declaration for '%#T'",
+                                                       prev_decl->type, symbol);
+                               }
 
-               if (!types_compatible(type, prev_type)) {
-                       errorf(pos,
-                                  "declaration '%#T' is incompatible with '%#T' (declared %P)",
-                                  orig_type, symbol, prev_decl->type, symbol,
-                                  &previous_entity->base.source_position);
-               } else {
-                       unsigned old_storage_class = prev_decl->storage_class;
-                       if (warning.redundant_decls               &&
-                                       is_definition                     &&
-                                       !prev_decl->used                  &&
-                                       !(prev_decl->modifiers & DM_USED) &&
-                                       prev_decl->storage_class == STORAGE_CLASS_STATIC) {
-                               warningf(&previous_entity->base.source_position,
-                                        "unnecessary static forward declaration for '%#T'",
-                                        prev_decl->type, symbol);
-                       }
-
-                       storage_class_t new_storage_class = decl->storage_class;
-
-                       /* pretend no storage class means extern for function
-                        * declarations (except if the previous declaration is neither
-                        * none nor extern) */
-                       if (entity->kind == ENTITY_FUNCTION) {
-                               /* the previous declaration could have unspecified parameters or
-                                * be a typedef, so use the new type */
-                               if (prev_type->function.unspecified_parameters || is_definition)
-                                       prev_decl->type = type;
+                               storage_class_t new_storage_class = decl->storage_class;
+
+                               /* pretend no storage class means extern for function
+                                * declarations (except if the previous declaration is neither
+                                * none nor extern) */
+                               if (entity->kind == ENTITY_FUNCTION) {
+                                       /* the previous declaration could have unspecified parameters or
+                                        * be a typedef, so use the new type */
+                                       if (prev_type->function.unspecified_parameters || is_definition)
+                                               prev_decl->type = type;
+
+                                       switch (old_storage_class) {
+                                               case STORAGE_CLASS_NONE:
+                                                       old_storage_class = STORAGE_CLASS_EXTERN;
+                                                       /* FALLTHROUGH */
+
+                                               case STORAGE_CLASS_EXTERN:
+                                                       if (is_definition) {
+                                                               if (warning.missing_prototypes &&
+                                                                               prev_type->function.unspecified_parameters &&
+                                                                               !is_sym_main(symbol)) {
+                                                                       warningf(pos, "no previous prototype for '%#T'",
+                                                                                       orig_type, symbol);
+                                                               }
+                                                       } else if (new_storage_class == STORAGE_CLASS_NONE) {
+                                                               new_storage_class = STORAGE_CLASS_EXTERN;
+                                                       }
+                                                       break;
 
-                               switch (old_storage_class) {
-                               case STORAGE_CLASS_NONE:
-                                       old_storage_class = STORAGE_CLASS_EXTERN;
-                                       /* FALLTHROUGH */
-
-                               case STORAGE_CLASS_EXTERN:
-                                       if (is_definition) {
-                                               if (warning.missing_prototypes &&
-                                                   prev_type->function.unspecified_parameters &&
-                                                   !is_sym_main(symbol)) {
-                                                       warningf(pos, "no previous prototype for '%#T'",
-                                                                        orig_type, symbol);
-                                               }
-                                       } else if (new_storage_class == STORAGE_CLASS_NONE) {
-                                               new_storage_class = STORAGE_CLASS_EXTERN;
+                                               default:
+                                                       break;
                                        }
-                                       break;
-
-                               default:
-                                       break;
+                               } else if (is_type_incomplete(prev_type)) {
+                                       prev_decl->type = type;
                                }
-                       } else if (is_type_incomplete(prev_type)) {
-                               prev_decl->type = type;
-                       }
 
-                       if (old_storage_class == STORAGE_CLASS_EXTERN &&
-                                       new_storage_class == STORAGE_CLASS_EXTERN) {
+                               if (old_storage_class == STORAGE_CLASS_EXTERN &&
+                                               new_storage_class == STORAGE_CLASS_EXTERN) {
 warn_redundant_declaration:
-                               if (!is_definition           &&
-                                   warning.redundant_decls  &&
-                                   is_type_valid(prev_type) &&
-                                   strcmp(previous_entity->base.source_position.input_name,
-                                          "<builtin>") != 0) {
-                                       warningf(pos,
-                                                "redundant declaration for '%Y' (declared %P)",
-                                                symbol, &previous_entity->base.source_position);
-                               }
-                       } else if (current_function == NULL) {
-                               if (old_storage_class != STORAGE_CLASS_STATIC &&
-                                   new_storage_class == STORAGE_CLASS_STATIC) {
-                                       errorf(pos,
-                                              "static declaration of '%Y' follows non-static declaration (declared %P)",
-                                              symbol, &previous_entity->base.source_position);
-                               } else if (old_storage_class == STORAGE_CLASS_EXTERN) {
-                                       prev_decl->storage_class          = STORAGE_CLASS_NONE;
-                                       prev_decl->declared_storage_class = STORAGE_CLASS_NONE;
-                               } else {
-                                       /* ISO/IEC 14882:1998(E) §C.1.2:1 */
-                                       if (c_mode & _CXX)
-                                               goto error_redeclaration;
-                                       goto warn_redundant_declaration;
-                               }
-                       } else if (is_type_valid(prev_type)) {
-                               if (old_storage_class == new_storage_class) {
+                                       if (!is_definition           &&
+                                                       warning.redundant_decls  &&
+                                                       is_type_valid(prev_type) &&
+                                                       strcmp(previous_entity->base.source_position.input_name,
+                                                               "<builtin>") != 0) {
+                                               warningf(pos,
+                                                               "redundant declaration for '%Y' (declared %P)",
+                                                               symbol, &previous_entity->base.source_position);
+                                       }
+                               } else if (current_function == NULL) {
+                                       if (old_storage_class != STORAGE_CLASS_STATIC &&
+                                                       new_storage_class == STORAGE_CLASS_STATIC) {
+                                               errorf(pos,
+                                                               "static declaration of '%Y' follows non-static declaration (declared %P)",
+                                                               symbol, &previous_entity->base.source_position);
+                                       } else if (old_storage_class == STORAGE_CLASS_EXTERN) {
+                                               prev_decl->storage_class          = STORAGE_CLASS_NONE;
+                                               prev_decl->declared_storage_class = STORAGE_CLASS_NONE;
+                                       } else {
+                                               /* ISO/IEC 14882:1998(E) §C.1.2:1 */
+                                               if (c_mode & _CXX)
+                                                       goto error_redeclaration;
+                                               goto warn_redundant_declaration;
+                                       }
+                               } else if (is_type_valid(prev_type)) {
+                                       if (old_storage_class == new_storage_class) {
 error_redeclaration:
-                                       errorf(pos, "redeclaration of '%Y' (declared %P)",
-                                              symbol, &previous_entity->base.source_position);
-                               } else {
-                                       errorf(pos,
-                                              "redeclaration of '%Y' with different linkage (declared %P)",
-                                              symbol, &previous_entity->base.source_position);
+                                               errorf(pos, "redeclaration of '%Y' (declared %P)",
+                                                               symbol, &previous_entity->base.source_position);
+                                       } else {
+                                               errorf(pos,
+                                                               "redeclaration of '%Y' with different linkage (declared %P)",
+                                                               symbol, &previous_entity->base.source_position);
+                                       }
                                }
                        }
+
+                       prev_decl->modifiers |= decl->modifiers;
+                       if (entity->kind == ENTITY_FUNCTION) {
+                               previous_entity->function.is_inline |= entity->function.is_inline;
+                       }
+                       return previous_entity;
                }
 
-               prev_decl->modifiers |= decl->modifiers;
-               if (entity->kind == ENTITY_FUNCTION) {
-                       previous_entity->function.is_inline |= entity->function.is_inline;
+               if (warning.shadow) {
+                       warningf(pos, "%s '%Y' shadows %s (declared %P)",
+                                       get_entity_kind_name(entity->kind), symbol,
+                                       get_entity_kind_name(previous_entity->kind),
+                                       &previous_entity->base.source_position);
                }
-               return previous_entity;
        }
 
        if (entity->kind == ENTITY_FUNCTION) {