[gnu.gcc.bug] BUG

how@IRIS.UCDAVIS.EDU (W. Wilson Ho) (11/01/88)

When a "-E" flag is set to gcc, the following error message is given:

+------------
|how@iris:54> gcc -v -E foo.c
|gcc version 1.30
| /usr/local/lib/gcc-cpp -v -undef -D__GNU__ -D__GNUC__ -Dvax -Dunix foo.c
|GNU CPP version 1.30
|cpp: Is a directory for `'
+------------

where foo.c is ANY c program, event for empty file.

However, if the "-o" flag is given:

+------------
|how@iris:56> gcc -v -E foo.c -o foo.e
|gcc version 1.30
| /usr/local/lib/gcc-cpp -v -undef -D__GNU__ -D__GNUC__ -Dvax -Dunix foo.c -o foo.e
|GNU CPP version 1.30
+------------

everythings work fine.


The problem is probably that cpp always expects an output file name.
I couldn't find in the manual that we have to specify the output file
name when we want to run the preprocessor only.  Is this a bug or a
feature?

The gcc version I use is 1.30, running ultrix 2.2 on a vax 8600.

Wilson Ho
-------------------------------------------------------------------------------
  W. Wilson Ho		        |  INTERNET: how@iris.ucdavis.edu
  Division of Computer Science	|  UUCP:     {lll-crg, ucbvax}!ucdavis!iris!how
  EECS Department		|
  University of California	|  Phone:    (916)752-7109
  Davis, CA 95616		|
-------------------------------------------------------------------------------

rfg@MCC.COM (Ron Guilmette) (02/04/89)

There appears to be a problem with three of the instruction
patterns in the m88k.md file (as of 1.32).

The andsi3, iorsi3, and xorsi3 patterns cause the upper half
of the result word to be clobbered by the second machine
instruction generated.  This only happens in cases where one
of the values to be and'ed, or'ed, or xor'ed is a literal
constant.

The following minor patches fix all three problems.

// Ron Guilmette  -  MCC  -  Experimental (parallel) Systems Kit Project
// 3500 West Balcones Center Drive,  Austin, TX  78759  -  (512)338-3740
// ARPA: rfg@mcc.com
// UUCP: {rutgers,uunet,gatech,ames,pyramid}!cs.utexas.edu!pp!rfg

*** m88k.md-	Tue Jan 31 14:46:53 1989
--- m88k.md	Fri Feb  3 12:58:03 1989
***************
*** 1659,1663 ****
        return \"and\\t %0,%1,%2\";
      }
!   return \"and.u\\t %0,%1,hi16(%2)\;and\\t %0,%1,lo16(%2)\";
  }")
  
--- 1659,1663 ----
        return \"and\\t %0,%1,%2\";
      }
!   return \"and.u\\t %0,%1,hi16(%2)\;and\\t %0,%0,lo16(%2)\";
  }")
  
***************
*** 1684,1688 ****
    if (INT_FITS_16_BITS (i))
      return \"or\\t %0,%1,%2\";
!   return \"or.u\\t %0,%1,hi16(%2)\;or\\t %0,%1,lo16(%2)\";
  }")
  
--- 1684,1688 ----
    if (INT_FITS_16_BITS (i))
      return \"or\\t %0,%1,%2\";
!   return \"or.u\\t %0,%1,hi16(%2)\;or\\t %0,%0,lo16(%2)\";
  }")
  
***************
*** 1711,1715 ****
    if ((i & 0xffff) == 0)
      return \"xor.u\\t %0,%1,hi16(%2)\";
!   return \"xor.u\\t %0,%1,hi16(%2)\;xor\\t %0,%1,lo16(%2)\";
  }")
  
--- 1711,1715 ----
    if ((i & 0xffff) == 0)
      return \"xor.u\\t %0,%1,hi16(%2)\";
!   return \"xor.u\\t %0,%1,hi16(%2)\;xor\\t %0,%0,lo16(%2)\";
  }")
  

rfg@MCC.COM (Ron Guilmette) (04/23/89)

When compiled with -ansi and -pedantic, the following source file
gets 4 warnings.  I believe that the intent of -pedantic was to
provide GCC with fully ANSI conformant behavior.  Therefore, I
believe that the following code should generate 4 ERRORS rather
than 4 WARNINGS when -ansi and -pedantic are used.

(Side note: future ANSI-C test suites may contain (pedantic)
tests such as the following.  If GCC cannot be made to handle
such tests in an ANSI-conformant way, then such suites will
(rightfully) claim that GCC is *not* ANSI conformant.)

----------------------------------------------------------------
/*
  Check that it is illegal to try to apply the sizeof operator
  to the name of a function.
*/

extern void extern_function ();

int i = sizeof (extern_function);	/* ERROR */
int j = sizeof extern_function;		/* ERROR */

void test ()
{
	int i = sizeof (test);		/* ERROR */
	int j = sizeof test;		/* ERROR */

	i = j;
}

rfg@MCC.COM (Ron Guilmette) (04/25/89)

I have been making calls to debug_dump_tree() from within the
debugger (i.e. on the fly) to see what is happening to various
trees.  While doing this, I noticed two things:

	1)  I got segfaults sometimes because the dump() routine
	    (also in the print-tree.c file) tries to call print_rtl()
	    for operand[2] of CALL_EXPR's.  Sometimes, operand[2] is
	    null (for c++ at least) so when print_rtl() tries to
	    dereference its second argument... WACKO!  SEGFAULT!

	    The last patch below seems to fix the problem nicely.

	2)  the dump_tree() routine will *not* dump out all of the
	    information about a sub-tree which you may want to see.
	    This is apparently due to the fact that the "walk()"
	    routine tries to avoid visiting certain kinds of nodes
	    which it thinks may have already been printed out (even
	    though they have not been!).

	    Most of the patches given below are meant to provide a
	    alternative to debug_dump_tree() called debug_dump_whole_tree()
	    which will give you the *whole* story.  The patches are
	    quite trivial.

P.S. the following patches were made for the G++ 1.35.0- (pre-release)
but they will probably work fine also for G++ 1.34.x and/or GCC 1.34/1.35.

*** print-tree.c-	Mon Feb 27 19:40:59 1989
--- print-tree.c	Mon Apr 24 14:24:03 1989
***************
*** 59,63 ****
--- 59,74 ----
  }
  
+ static int interactive_tree_dumping = 0;
+ 
  void
+ debug_dump_whole_tree (root)
+      tree root;
+ {
+   interactive_tree_dumping = -1;
+   dump_tree (stderr, root);
+   interactive_tree_dumping = 0;
+ }
+ 
+ void
  dump_tree (outf, root)
       FILE *outf;
***************
*** 126,130 ****
       int indent;
  {
!   if (node != NULL
        /* Don't walk any global nodes reached from local nodes!
  	 The global nodes will be dumped at the end, all together.
--- 137,141 ----
       int indent;
  {
!   if (node != NULL && (interactive_tree_dumping ||
        /* Don't walk any global nodes reached from local nodes!
  	 The global nodes will be dumped at the end, all together.
***************
*** 131,137 ****
  	 Also don't mention a FUNCTION_DECL node that is marked local
  	 since it was fully described when it was dumped locally.  */
!       && (TREE_CODE (node) != FUNCTION_DECL
  	  || TREE_PERMANENT (node))
!       && (TREE_PERMANENT (leaf) == TREE_PERMANENT (node)))
      dump (node, indent+1);
  }
--- 142,148 ----
  	 Also don't mention a FUNCTION_DECL node that is marked local
  	 since it was fully described when it was dumped locally.  */
!       ((TREE_CODE (node) != FUNCTION_DECL
  	  || TREE_PERMANENT (node))
!       && (TREE_PERMANENT (leaf) == TREE_PERMANENT (node)))))
      dump (node, indent+1);
  }
***************
*** 435,438 ****
--- 446,451 ----
  	case CALL_EXPR:
  	  first_rtl = 2;
+ 	  if (!TREE_OPERAND (node, first_rtl))
+ 	    len--;			/* operand[2] may be null */
  	  break;
  	case METHOD_CALL_EXPR:


// Ron Guilmette  -  MCC  -  Experimental Systems Kit Project
// 3500 West Balcones Center Drive,  Austin, TX  78759  -  (512)338-3740
// ARPA: rfg@mcc.com
// UUCP: {rutgers,uunet,gatech,ames,pyramid}!cs.utexas.edu!pp!rfg

rfg@MCC.COM (Ron Guilmette) (07/04/89)

In the following code fragment, all of the functions suffer from the
same type of error, i.e. that they all declare their parameters in
terms of structured types which cannot be used EXCEPT within the functions
themselves (or perhaps just within their formal parameter lists).

Unfortunately GCC 1.35/sun3 only flags the first three functions with
warnings and doesn't even mention the other cases.  I believe that
all these cases should be considerd errors.  At the very least, they
should all ellicit warnings from the compiler.

A good case can be made for errors, especially for the functions which
are absolutely impossible to call (from outside).  The ones that are
impossible to call are the ones that use prototypes and also declare
some parameter to be of a (hidden) struct or union type.


-----------------------------------------------------------------------------
void function_1a1 (enum E_1a1 { Evalue_1a } p1) {		/* ERROR */
	p1 = p1;
}

void function_1a2 (struct S_1a2 { int Sfield_1a2; } p1) {	/* ERROR */
	p1 = p1;
}

void function_1a3 (union U_1a3 { int Ufield_1a3; } p1) {	/* ERROR */
	p1 = p1;
}

void function_1b1 (p1)
	enum E_1b1 { Evalue_1b1 } p1;				/* ERROR */
{
	p1 = p1;
}

void function_1b2 (p1)
	struct S_1b2 { int Sfield_1b2; } p1;			/* ERROR */
{
	p1 = p1;
}

void function_1b3 (p1)
	union U_1b3 { int Ufield_1b3; } p1;			/* ERROR */
{
	p1 = p1;
}

void function_2a1 (enum { Evalue_2a1 } p1) {			/* ERROR */
	p1 = p1;
}

void function_2a2 (struct { int Sfield_2a2; } p1) {		/* ERROR */
	p1 = p1;
}

void function_2a3 (union { int Ufield_2a3; } p1) {		/* ERROR */
	p1 = p1;
}

void function_2b1 (p1)
	enum { Evalue_2b1 } p1;					/* ERROR */
{
	p1 = p1;
}

void function_2b2 (p1)
	struct { int Sfield_2b2; } p1;				/* ERROR */
{
	p1 = p1;
}

void function_2b3 (p1)
	union { int Ufield_2b3; } p1;				/* ERROR */
{
	p1 = p1;
}
-----------------------------------------------------------------------------

// Ron Guilmette  -  MCC  -  Experimental Systems Kit Project
// 3500 West Balcones Center Drive,  Austin, TX  78759  -  (512)338-3740
// ARPA: rfg@mcc.com
// UUCP: {rutgers,uunet,gatech,ames,pyramid}!cs.utexas.edu!pp!rfg

rfg@ICS.UCI.EDU (12/07/89)

WARNING:  The following message is LONG and is only of concern to
those people who give a darn if -g and -O work correctly with COFF
object files.  Others should skip this message now.

The following code (derived from one of the libg++ test programs)
causes assembler errors on System V when compiled with -g and -O
under either GCC 1.36 or G++ 1.36.1 (with lots of patches for the
m88k & DG-UX installed).

-----------------------------------------------------------------
int unused;

inline int unused_indices()
{
  return unused;
}
int add(const int  elem)
{
  for(;;)
  {
    if (unused_indices() != 0)
    {
      int i =   7;
      return i;
    }
    unused = 0;
  }
}
-----------------------------------------------------------------

The problem here seems to be that (a) System V assemblers may
check to see that symbol definitions for the *special* debugging
symbols ".bb" (begin-block) and ".eb" (end-block) are properly
paired and ordered (as it seems they should be anyway).

When using -g (with GCC or G++) symbol definitions for the special
symbols ".bb" and ".eb" are generated from special kinds of line NOTES
(specifically, from NOTE_INSN_BLOCK_BEG and NOTE_INSN_BLOCK_END
respectively).

Unfortunately, if you are using -g *and* -O, then jump optimization
can cause a NOTE_INSN_BLOCK_BEG to become separated from its corresponding
NOTE_INSN_BLOCK_END, and the code motion that jump optimization may
cause to occur can then cause the NOTE_INSN_BLOCK_END to appear *before*
its associated NOTE_INSN_BLOCK_BEG!  Thus, the assembler will see a
symbol definition for ".eb" *before* a symbol definition for ".bb".

The proper solution seems to be simply to prevent jump optimization from
separating a matched pair of NOTE_INSN_BLOCK_BEG & NOTE_INSN_BLOCK_END.
The following patches for jump.c implement this solution.  (Your line
numbers may vary.)

---------------------------------------
While investigating this problem, I also noticed that the regular line
number NOTES for the inlined function call in the example above were
also looking quite screwy.  I made some fixes (included below) for these
cases as well.  Specifically, it seems to me that the code which causes
parameter values to be "passed into" an inline function invocation
should be thought of (by a debugger) as occuring on the line containing
the start of the inline function (or as near thereto as possible).
In the example above, this would be either line #3 or line #4 (for the
inlined call to "unused_indicies()").  Also, at the point in the generated
code where the inlining ends (line #11 in the example above), it seems to
me that the compiler should make another new line-number note which *could*
inform a debugger that we are now back executing the rest of the normal
line that follows the inlined function call.

I have implemented these changes also, and the necessary patches (to
integrate.c, stmt.c and c-parse.y) are included below following the
patches for jump.c.  (Your line numbers may vary.)

---------------------------------------
Note that on System V, the latter set of patches will (in all probability)
actually be useless (other than making it easier to read rtl dumps).  This
is because COFF line number information looses totally when it comes to
inlined functions.  COFF line numbers are supposed to always be expressed
as positive line OFFSETS from the first line of the containing function.
Unfortunately, inlining can cause the COFF line numbers for chunks of
inlined code to be NEGATIVE!!!  System V assemblers/linkers/debuggers can
(and often do) choke on such negative line numbers.

Because of this final problem (which probably only arises when you have
SDB_DEBUGGING_INFO defined in your tm-*.h file), I suggest that those
people who are using any of the following tm-*.h files should check their
definitions of ASM_OUTPUT_SOURCE_LINE to be sure that negative line
numbers get filtered out.  I do not have time to check all of these
myself.  The (potentially) problematic tm-*.h files are:

	tm-3b1.h
	tm-encore.h
	tm-harris.h
	tm-i386v.h
	tm-m88k.h	(I fixed my copy!)
	tm-vaxv.h

Note that a similar (negative line-number) problem can occur (with COFF) 
if your definitions of PUT_SDB_BLOCK_START and PUT_SDB_BLOCK_END fail to
filter out negative line numbers.  There are default definitions of these
macros in sdbout.c (and these default definitions should probably be
fixed to do the filtering) but you may also want to created fixed definitions
of these two macros (which do the filtering) in your own tm-*.h file (if you
are using one of the tm-*.h files listed above).

Enjoy,

// rfg
 
diff -rc2 1.36.1/jump.c 1.36.2/jump.c
*** 1.36.1/jump.c	Wed Sep  6 21:39:18 1989
--- 1.36.2/jump.c	Wed Dec  6 12:49:55 1989
***************
*** 84,87 ****
--- 84,88 ----
  rtx next_real_insn ();
  rtx prev_real_insn ();
+ static rtx last_insn_for_range ();
  rtx next_label ();
  
***************
*** 449,454 ****
  			    rtx range1beg = NEXT_INSN (insn);
  			    rtx range2beg = NEXT_INSN (label1);
! 			    rtx range1after = NEXT_INSN (range1end);
! 			    rtx range2after = NEXT_INSN (range2end);
  			    /* Splice range2 between INSN and LABEL1.  */
  			    NEXT_INSN (insn) = range2beg;
--- 450,476 ----
  			    rtx range1beg = NEXT_INSN (insn);
  			    rtx range2beg = NEXT_INSN (label1);
! 			    rtx range1after;
! 			    rtx range2after;
! 
!                             /* If necessary, adjust each range so that it
!                                includes a following NOTE_INSN_BLOCK_END if
!                                one follows the range but preceeds any following
!                                CODE_LABEL's or real insns.  This is needed
!                                because of the possibility that one of the
!                                ranges contains a NOTE_INSN_BLOCK_BEG that
!                                corresponds to the NOTE_INSN_BLOCK_END that we
!                                may find following the nominal range.  In such
!                                cases, we want to be sure to include the
!                                corresponding NOTE_INSN_BLOCK_END in the same
!                                range.  The range adjustment also causes
!                                BARRIERs to be kept with their associated
!                                JUMP_INSNs, but that's just a side effect.  */
! 
!                             range1end = last_insn_for_range (range1end);
!                             range2end = last_insn_for_range (range2end);
! 
! 			    range1after = NEXT_INSN (range1end);
! 			    range2after = NEXT_INSN (range2end);
! 
  			    /* Splice range2 between INSN and LABEL1.  */
  			    NEXT_INSN (insn) = range2beg;
***************
*** 958,961 ****
--- 980,1018 ----
  
    return insn;
+ }
+ 
+ /* Return the NOTE_INSN_BLOCK_END that follows INSN (but preceeds any
+    following real insns).  Failing that, return the last following BARRIER
+    that follows INSN (but preceeds any following real insns).  Failing that,
+    return INSN (which may be 0).  */
+ 
+ static rtx
+ last_insn_for_range (insn)
+      rtx insn;
+ {
+   register rtx return_val;
+   register rtx ahead;
+   register RTX_CODE code;
+ 
+   if (insn == 0)
+     return insn;
+   return_val = insn;
+   for (ahead = NEXT_INSN (insn); ahead; ahead = NEXT_INSN (ahead))
+     {
+       switch (GET_CODE (ahead))
+         {
+           case BARRIER:
+             return_val = ahead;
+             break;
+           case NOTE:
+             if (NOTE_LINE_NUMBER (ahead) == NOTE_INSN_BLOCK_END)
+               return ahead;
+             else
+               continue;		/* Just pass over regular NOTEs */
+           default:
+             return return_val;
+         }
+     }
+   return return_val;
  }
  

%%% here are the patches to get line numbers right for inlined calls

diff -rc2 1.36.1/c-parse.y 1.36.2/c-parse.y
*** 1.36.1/c-parse.y	Tue Sep 19 22:11:01 1989
--- 1.36.2/c-parse.y	Wed Dec  6 01:31:13 1989
***************
*** 952,956 ****
  		  clear_last_expr ();
  		  push_momentary ();
! 		  expand_start_bindings (0); }
  	;
  
--- 952,956 ----
  		  clear_last_expr ();
  		  push_momentary ();
! 		  expand_start_bindings (0, 1); }
  	;
  
diff -rc2 1.36.1/integrate.c 1.36.2/integrate.c
*** 1.36.1/integrate.c	Wed Nov 22 12:11:00 1989
--- 1.36.2/integrate.c	Wed Dec  6 01:32:14 1989
***************
*** 28,31 ****
--- 28,32 ----
  #include "insn-flags.h"
  #include "expr.h"
+ #include "input.h"
  
  #include "obstack.h"
***************
*** 592,595 ****
--- 593,597 ----
    rtx header = DECL_SAVED_INSNS (fndecl);
    rtx insns = FIRST_FUNCTION_INSN (header);
+   rtx parm_insns = FIRST_PARM_INSN (header);
    rtx insn;
    int max_regno = MAX_REGNUM (header) + 1;
***************
*** 629,632 ****
--- 631,644 ----
      }
  
+   /* For the benefit of debuggers that might understand such things, make
+      a note here of the file and line which contain the function header
+      for the function being inlined.  Also, make sure that the subsequent
+      call to expand_start_bindings() does not make another note based on
+      the actual current line & file (i.e. the place where the inlining is
+      actually occuring).  Making such a note would just nullify the effect
+      of the note we are making here.  */
+ 
+   emit_note (NOTE_SOURCE_FILE (parm_insns), NOTE_LINE_NUMBER (parm_insns));
+ 
    /* Make a binding contour to keep inline cleanups called at
       outer function-scope level from looking like they are shadowing
***************
*** 636,640 ****
    /* Make a fresh binding contour that we can easily remove.  */
    pushlevel (0);
!   expand_start_bindings (0);
  
    /* Get all the actual args as RTL, and store them in ARG_VEC.  */
--- 648,652 ----
    /* Make a fresh binding contour that we can easily remove.  */
    pushlevel (0);
!   expand_start_bindings (0, 0);
  
    /* Get all the actual args as RTL, and store them in ARG_VEC.  */
***************
*** 1073,1077 ****
    /* End the scope containing the copied formal parameter variables.  */
  
!   expand_end_bindings (getdecls (), 1, 1);
    poplevel (1, 1, 0);
    poplevel (0, 0, 0);
--- 1085,1091 ----
    /* End the scope containing the copied formal parameter variables.  */
  
!   expand_end_bindings (getdecls (), 0, 1);
!   /* Make sure that debuggers know that we are back where we started.  */
!   emit_note (input_filename, lineno);
    poplevel (1, 1, 0);
    poplevel (0, 0, 0);
diff -rc2 1.36.1/stmt.c 1.36.2/stmt.c
*** 1.36.1/stmt.c	Wed Nov 22 12:11:20 1989
--- 1.36.2/stmt.c	Wed Dec  6 01:36:10 1989
***************
*** 52,55 ****
--- 52,56 ----
  
  #include "rtl.h"
+ #include "input.h"
  #include "tree.h"
  #include "flags.h"
***************
*** 1678,1683 ****
  
  void
! expand_start_bindings (exit_flag)
       int exit_flag;
  {
    struct nesting *thisblock
--- 1679,1685 ----
  
  void
! expand_start_bindings (exit_flag, line_note_flag)
       int exit_flag;
+      int line_note_flag;
  {
    struct nesting *thisblock
***************
*** 1684,1689 ****
      = (struct nesting *) xmalloc (sizeof (struct nesting));
  
!   rtx note = emit_note (0, NOTE_INSN_BLOCK_BEG);
  
    /* Make an entry on block_stack for the block we are entering.  */
  
--- 1686,1701 ----
      = (struct nesting *) xmalloc (sizeof (struct nesting));
  
!   /* Force a line note here just in case this block gets moved around due to
!      jump optimizations.  */
  
+   rtx note = (line_note_flag)
+                ? emit_line_note_force (input_filename, lineno)
+                : 0;
+ 
+   if (note)
+     emit_note (0, NOTE_INSN_BLOCK_BEG);
+   else
+     note = emit_note (0, NOTE_INSN_BLOCK_BEG);
+ 
    /* Make an entry on block_stack for the block we are entering.  */
  
***************
*** 1772,1779 ****
  
    if (mark_ends)
!     emit_note (0, NOTE_INSN_BLOCK_END);
    else
!     /* Get rid of the beginning-mark if we don't make an end-mark.  */
!     NOTE_LINE_NUMBER (thisblock->data.block.first_insn) = NOTE_INSN_DELETED;
  
    if (thisblock->exit_label)
--- 1784,1800 ----
  
    if (mark_ends)
!     {
!       emit_note (input_filename, lineno);
!       emit_note (0, NOTE_INSN_BLOCK_END);
!     }
    else
!     {
!       /* Get rid of the beginning-mark if we don't make an end-mark.  */
!       rtx block_beg_note = thisblock->data.block.first_insn;
! 
!       if (NOTE_LINE_NUMBER (block_beg_note) != NOTE_INSN_BLOCK_BEG)
!         block_beg_note = NEXT_INSN (block_beg_note);
!       NOTE_LINE_NUMBER (block_beg_note) = NOTE_INSN_DELETED;
!     }
  
    if (thisblock->exit_label)