From: t1markm@tv.tv.tek.COM (Mark Mason)
Newsgroups: gnu.gcc.bug
Subject: bug in limbo code in gcc 2.3.3
Date: 21 Jan 1993 18:18:25 -0500
Organization: GNUs Not Usenet
Distribution: gnu

Hello,

I seem to have found a bug in the limbo code in gcc 2.3.3 (running
on a sparc, cross-compiling to a m68k, -version information in the
debugger run below - but the bug seems to be target independent).

Basically, some of the type information stored for an extern decl
in block scope has been allocated from function_maybepermanent_obstack
rather than permanent_obstack. We found this because in some other
code (which I cannot provide because of licensing problems) spurious
warnings where generated about 'type mismatch with previous extern decl'.

At least one of the culprits is in grokdeclarator at line 4154 (below),
where a call to build_array_type() is made, but we have not yet detected
the case where the declaration in question is extern (and
end_temporary_allocation() has not been called to switch
to permanent_obstack).

  /* Detect the case of an array type of unspecified size
     which came, as such, direct from a typedef name.
     We must copy the type, so that each identifier gets
     a distinct type, so that each identifier's size can be
     controlled separately by its own initializer.  */

  if (type != 0 && typedef_type != 0
      && TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (typedef_type)
      && TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type) == 0)
    {
      type = build_array_type (TREE_TYPE (type), 0);
      if (size_varies)
	C_TYPE_VARIABLE_SIZE (type) = 1;
    }

Below is a simple test case, with a demonstration in the debugger of which
piece of type information is in the wrong obstack. This example itself does
not generate a spurious warning (which happens when the limbo'd type decl
is stomped on by something else, and is then later checked by a following
function definition who duplicated the extern decl).

Script started on Thu Jan 21 08:21:46 1993
soul.tv.tek.com[1]=> cat x.c
int
foo()
{
        extern char _sdata[];
}
soul.tv.tek.com[2]=> gdb /tv/lib/gcc/Vsystem/2.3.3/cc1
GDB 3.5, Copyright (C) 1989 Free Software Foundation, Inc.
There is ABSOLUTELY NO WARRANTY for GDB; type "info warranty" for details.
GDB is free software and you are welcome to distribute copies of it
 under certain conditions; type "info copying" to see the conditions.
Reading symbol data from /tv/lib/gcc/Vsystem/2.3.3/cc1...done.
Function abort not defined.
Type "help" for a list of commands.
(gdb) l pushdecl
Reading in symbols for ../c-decl.c...done.
Source file is more recent than executable.
1677       to agree with what X says.  */
1678    
1679    tree
1680    pushdecl (x)
1681         tree x;
1682    {
1683      register tree t;
l1684     register tree name = DECL_NAME (x);
1685      register struct binding_level *b = current_binding_level;
1686    
(gdb) l 2009
2004                     Only save it once.  This prevents temporary decls created in
2005                     expand_inline_function from being used here, since this
2006                     will have been set when the inline function was parsed.
2007                     It also helps give slightly better warnings.  */
2008                  if (IDENTIFIER_LIMBO_VALUE (name) == 0)
2009                    IDENTIFIER_LIMBO_VALUE (name) = x;
2010                }
2011    
2012              /* Warn if shadowing an argument at the top level of the body.  */
2013              if (oldlocal != 0 && !DECL_EXTERNAL (x)
(gdb) b 2009
Breakpoint 1 at 0x11750: file ../c-decl.c, line 2009.
(gdb) r x.c -o x.s -version
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /tv/lib/gcc/Vsystem/2.3.3/cc1 x.c -o x.s -version
GNU C version 2.3.3 (68k, MIT syntax) compiled by GNU C version 2.2.2.
enabled: -fdefer-pop -fpeephole -ffunction-cse -fcommon -fgnu-linker
         -m68020 -mc68020 -m68881 -mbitfield -m68030
 foo
Bpt 1, pushdecl (x=(tree) 0x12b758) (../c-decl.c line 2009)
2009                    IDENTIFIER_LIMBO_VALUE (name) = x;
(gdb) p debug_obstack(x)
Reading in symbols for ../tree.c...done.
object allocated from permanent_obstack.
$1 = void
(gdb) p debug_obstack(x->common.type)
object allocated from function maybepermanent obstack.
$2 = void
(gdb) quit
The program is running.  Quit anyway? (y or n) y
script done on Thu Jan 21 08:24:34 1993

I don't claim to fully understand the mystries of grokdeclarator and the
type system, but it seems that a similar problem could arise from the
following abusive code:

bar()
{
	struct foo {
		int x[4];
	};
	extern struct foo y;
}

Because the type information for 'struct foo' would be placed in the
function_maybepermanent_obstack at first. When the extern decl is
handled, it seems that the type information for struct foo would
have to be copied to the permanent_obstack (so the limbo entry for
'y' could refer to it). Or did I just wander off into the woodwork?

Thanks for your time,

Mark Mason
t1markm@sol.tv.tek.com	<- my current work email address.
mason@reed.edu	<- for personal contacts