This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: error_mark_node


> Date: Wed, 01 Nov 2000 14:14:25 +0000
> From: Nathan Sidwell <nathan@codesourcery.com>

> what's the canonical way to deal with error_mark_node?

The canonical way, is to place code that checks for error_mark_node
early, and do something as sensible as possible and return it through.
There is a boundary, despite what Mark said, for which you don't want
to move the checking any lower, and another for which checking higher
doesn't buy you anything and last, there is the middle area grey area
for which some reoutines need you to check for them and others that
don't need it.

It is just complex.  While we could migrate all the checks all the way
down, I'm not sure that is wise, we would then need checks in, I
suspect, every last macro.  I suspect these checks would impose a
hefty performance hit.  I think we can use the tree checking code that
was placed in recently to get a feel for the performance impact.
Generally, we try and factor the checks out to a layer just high
enough so that the cost of checking doesn't matter much, but yet low
enough so that we don't have to have massive amounts of checking code
at higher layers.  In short any routine that is `fast' (and widely
used), should not have checks for error_mark_node, but rather its
caller should.  If a routine is slow, then it should only check if it
calls fast routines.  Any routine that checks is `slow' and calls fast
routines.  If this isn't the case, then it should not check.  Well,
unless it's the case that all the routines in the transitive closure
are fast routines, or routines that can't generate error_mark_nodes
and the cost of the error checking in the routines that would need
such checking code is smaller than the cost of adding them to the
called functions.

The brittleness of this can be seen when a routine it changed to call
a fast routine, when it never did so before.  That's a problem, as
there would be no existing check, but yet, one is necessary (otherwise
we'll ICE).  Or maybe it did, but the check doesn't protect the area
where we are inserting a fast call.  For example, we see code like:

	  /* Not found as a data field, look for it as a method.  If found,
	     then if this is the only possible one, return it, else
	     report ambiguity error.  */
	  tree fndecls = lookup_fnfields (basetype_path, name, 1);
	  if (fndecls == error_mark_node)
	    return error_mark_node;
	  if (fndecls)
	    {
	      /* If the function is unique and static, we can resolve it
		 now.  Otherwise, we have to wait and see what context it is
		 used in; a component_ref involving a non-static member
		 function can only be used in a call (expr.ref).  */

	      if (TREE_CHAIN (fndecls) == NULL_TREE
		  && TREE_CODE (TREE_VALUE (fndecls)) == FUNCTION_DECL)
		{

Here we are in a slow routine, we have a slow routine lookup_fnfields,
and after it, we have a fast routine TREE_CHAIN, and between, we have
code to mitigate the boundary.

The optimizer isn't up to the task of eliminating these checks, which
is why we labour on them in the source code.  It is a price we paid to
make the compiler fast.

There is an open question of exactly how fast a routine has to be
before we decide to not litter it with checking code.  I don't have an
answer to that.

We've never gone though in a systematic approach and just added the
checks we need to solve all or most of the ICEs.  This would be a
great project for someone, as the work should be fairly easy and it
would improve the imagine of g++.

If someone wants to take this project on, I can say more about the
tpical way to deal with ICEs and how to fix them.


Now, having said all that, is someone has a better strategy for
handling error_mark_node, love to hear a comprehensive proposal.  I
described more the status quo, and why it is the way it is, than free
thinking about what exactly would be better.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]