From fd0b8fce4dc174fa55a0a706e2068a00eacf466a Mon Sep 17 00:00:00 2001 From: Jim Wilson Date: Tue, 15 Sep 1992 17:54:45 -0700 Subject: [PATCH] (print_lang_identifier): Print value of limbo field. (pushdecl): Check an extern decl against both previous global and previous limbo declarations. For global declarations, clear limbo value field. For block level extern declarations, set limbo field if zero. (grokdeclarator): If this is a block level extern, then allocate it on the permanent obstack, not the temporary obstack. From-SVN: r2128 --- gcc/c-decl.c | 88 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 67 insertions(+), 21 deletions(-) diff --git a/gcc/c-decl.c b/gcc/c-decl.c index d0f0c1c8b3a..5e4bbc0623d 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -679,6 +679,7 @@ print_lang_identifier (file, node, indent) print_node (file, "label", IDENTIFIER_LABEL_VALUE (node), indent + 4); print_node (file, "implicit", IDENTIFIER_IMPLICIT_DECL (node), indent + 4); print_node (file, "error locus", IDENTIFIER_ERROR_LOCUS (node), indent + 4); + print_node (file, "limbo value", IDENTIFIER_LIMBO_VALUE (node), indent + 4); } /* Create a new `struct binding_level'. */ @@ -1785,22 +1786,31 @@ pushdecl (x) } } - /* Multiple external decls of the same identifier ought to match. */ + /* Multiple external decls of the same identifier ought to match. + Check against both global declarations and out of scope (limbo) block + level declarations. - if (DECL_EXTERNAL (x) && IDENTIFIER_GLOBAL_VALUE (name) != 0 - && (DECL_EXTERNAL (IDENTIFIER_GLOBAL_VALUE (name)) - || TREE_PUBLIC (IDENTIFIER_GLOBAL_VALUE (name))) - /* We get warnings about inline functions where they are defined. - Avoid duplicate warnings where they are used. */ - && !DECL_INLINE (x)) + We get warnings about inline functions where they are defined. + Avoid duplicate warnings where they are used. */ + if (DECL_EXTERNAL (x) && ! DECL_INLINE (x)) { - if (! comptypes (TREE_TYPE (x), - TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (name)))) + tree decl; + + if (IDENTIFIER_GLOBAL_VALUE (name) != 0 + && (DECL_EXTERNAL (IDENTIFIER_GLOBAL_VALUE (name)) + || TREE_PUBLIC (IDENTIFIER_GLOBAL_VALUE (name)))) + decl = IDENTIFIER_GLOBAL_VALUE (name); + else if (IDENTIFIER_LIMBO_VALUE (name) != 0) + /* Decls in limbo are always extern, so no need to check that. */ + decl = IDENTIFIER_LIMBO_VALUE (name); + else + decl = 0; + + if (decl && ! comptypes (TREE_TYPE (x), TREE_TYPE (decl))) { pedwarn_with_decl (x, "type mismatch with previous external decl"); - pedwarn_with_decl (IDENTIFIER_GLOBAL_VALUE (name), - "previous external decl of `%s'"); + pedwarn_with_decl (decl, "previous external decl of `%s'"); } } @@ -1864,6 +1874,9 @@ pushdecl (x) IDENTIFIER_GLOBAL_VALUE (name) = x; + /* We no longer care about any previous block level declarations. */ + IDENTIFIER_LIMBO_VALUE (name) = 0; + /* Don't forget if the function was used via an implicit decl. */ if (IDENTIFIER_IMPLICIT_DECL (name) && TREE_USED (IDENTIFIER_IMPLICIT_DECL (name))) @@ -1970,6 +1983,16 @@ pushdecl (x) && TREE_PUBLIC (x)) { TREE_PUBLIC (name) = 1; + + /* Save this decl, so that we can do type checking against + other decls after it falls out of scope. + + Only save it once. This prevents temporary decls created in + expand_inline_function from being used here, since this + will have been set when the inline function was parsed. + It also helps give slightly better warnings. */ + if (IDENTIFIER_LIMBO_VALUE (name) == 0) + IDENTIFIER_LIMBO_VALUE (name) = x; } /* Warn if shadowing an argument at the top level of the body. */ @@ -3948,6 +3971,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) } else if (TREE_CODE (declarator) == CALL_EXPR) { + int extern_ref = (!(specbits & (1 << (int) RID_AUTO)) + || current_binding_level == global_binding_level); tree arg_types; /* Declaring a function type. @@ -3977,6 +4002,12 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) type = double_type_node; #endif /* TRADITIONAL_RETURN_FLOAT */ + /* If this is a block level extern, it must live past the end + of the function so that we can check it against other extern + declarations (IDENTIFIER_LIMBO_VALUE). */ + if (extern_ref && allocation_temporary_p ()) + end_temporary_allocation (); + /* Construct the function type and go to the next inner layer of declarator. */ @@ -4216,6 +4247,14 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) } else if (TREE_CODE (type) == FUNCTION_TYPE) { + /* Every function declaration is "external" + except for those which are inside a function body + in which `auto' is used. + That is a case not specified by ANSI C, + and we use it for forward declarations for nested functions. */ + int extern_ref = (!(specbits & (1 << (int) RID_AUTO)) + || current_binding_level == global_binding_level); + if (specbits & (1 << (int) RID_AUTO) && (pedantic || current_binding_level == global_binding_level)) pedwarn ("invalid storage class for function `%s'", @@ -4231,18 +4270,19 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) && pedantic) pedwarn ("invalid storage class for function `%s'", IDENTIFIER_POINTER (declarator)); + + /* If this is a block level extern, it must live past the end + of the function so that we can check it against other + extern declarations (IDENTIFIER_LIMBO_VALUE). */ + if (extern_ref && allocation_temporary_p ()) + end_temporary_allocation (); + decl = build_decl (FUNCTION_DECL, declarator, type); if (pedantic && (constp || volatilep)) pedwarn ("ANSI C forbids const or volatile functions"); - /* Every function declaration is "external" - except for those which are inside a function body - in which `auto' is used. - That is a case not specified by ANSI C, - and we use it for forward declarations for nested functions. */ - if (!(specbits & (1 << (int) RID_AUTO)) - || current_binding_level == global_binding_level) + if (extern_ref) DECL_EXTERNAL (decl) = 1; /* Record absence of global scope for `static' or `auto'. */ TREE_PUBLIC (decl) @@ -4268,6 +4308,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) else { /* It's a variable. */ + /* An uninitialized decl with `extern' is a reference. */ + int extern_ref = !initialized && (specbits & (1 << (int) RID_EXTERN)); /* Move type qualifiers down to element of an array. */ if (TREE_CODE (type) == ARRAY_TYPE && (constp || volatilep)) @@ -4280,6 +4322,12 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) #endif } + /* If this is a block level extern, it must live past the end + of the function so that we can check it against other + extern declarations (IDENTIFIER_LIMBO_VALUE). */ + if (extern_ref && allocation_temporary_p ()) + end_temporary_allocation (); + decl = build_decl (VAR_DECL, declarator, type); if (size_varies) C_DECL_VARIABLE_SIZE (decl) = 1; @@ -4287,9 +4335,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) if (inlinep) pedwarn_with_decl (decl, "variable `%s' declared `inline'"); - /* An uninitialized decl with `extern' is a reference. */ - DECL_EXTERNAL (decl) - = !initialized && (specbits & (1 << (int) RID_EXTERN)); + DECL_EXTERNAL (decl) = extern_ref; /* At top level, the presence of a `static' or `register' storage class specifier, or the absence of all storage class specifiers makes this declaration a definition (perhaps tentative). Also, -- 2.30.2