[cfe-dev] PATCH: Cleanup function redeclaration representations

Doug Gregor doug.gregor at gmail.com
Thu Apr 24 06:10:18 PDT 2008


Hi Argiris,

On Thu, Apr 24, 2008 at 5:13 AM, Argiris Kirtzidis <akyrtzi at gmail.com> wrote:
> Doug Gregor wrote:
>
> > Perhaps the real issue is that we shouldn't be calling
> > HandleTopLevelDecl for re-declarations, because they aren't declaring
> > unique entities, e.g., HandleTopLevelRedeclaration.
> >
> >
>
>  There are types of ASTConsumers that would expect to get re/declarations as
> the parser encounters them. Think of a consumer that colorizes
> variable/param names
>  for an IDE. If we hide the redeclarations we make things complicated for
> them, I'm not sure what the benefit would be.

There are other types of ASTConsumers that don't want to see
redeclarations, e.g., a consumer that is parsing documentation for
declarations or generating Python wrappers. We need both declarations
and redeclarations passed to the consumer, and the consumer needs to
be able to tell which is which. That needs to be present in any
scheme.

> > So, if name lookup is going to continue to find the first declaration
> > of a function (as it does in your suggestion and in the patch I
> > committed), that first declaration either needs to accumulate
> > information from redeclarations or access to its internals needs to
> > walk through the chain of redeclarations, e.g., to find default
> > arguments.
> >
> >
>
>  Yes, that's what I'm proposing. The first decl accumulates the information
> and/or walks the redeclarations for info.
>  Like the getBody() in your patch that walks the redeclarations to get the
> body.

There's a lot of walking to do, here. We'll need to walk the
redeclaration chain to get parameter names, default arguments, the
return type, the source location, etc., because we want to use the
most recent redeclaration for diagnostic purposes. For example:

  void f(int, int);
  void f(int, int y = 5);

  void g() {
    f(); // error: not enough arguments in call; should refer to the
most recent "f" declaration
  }

Redeclarations can change a lot of things... one can use typedefs for
parameter types (C and C++), rename parameters, add default arguments,
add a prototype (C), change to a different "compatible" type such as
int -> enum (C), etc. All of these would have to walk the
redeclaration chain.

> > The comment I have about this approach is that we'll end up with
> > different calls to the same function pointing at different
> > FunctionDecl nodes. For example:
> >
> >  void f(int x); // #1
> >  void g(int x) { f(x); } // call points to #1
> >  void f(int x); // #2
> >  void h(int x) { f(x); } // call points to #2
> >
> > I don't know whether that's a benefit or not :) In some sense, it
> > accurately represents the source code (that's good), but it's also a
> > little confusing: they both refer to exactly the same function, so why
> > do they refer to different FunctionDecl nodes?
> >
> >
>
>  I don't quite understand what you mean. Name lookup should only see and
> return the first decl (as the function decl that represents 'f' function).
>  Both calls should point to #1, why will they refer to different
> FunctionDecl nodes ?

If we agree that both should point to #1, that's great; one of my
alternative patches used a slightly different scheme where the first
call would point to #1 and the second to #2. We can ignore that
approach.

> > There's some philosophy behind my approach to function redeclarations:
> > I want "normal" users of the AST to only see a single FunctionDecl for
> > each function, and that FunctionDecl should contain all of the
> > information that the AST contains about that function.
> >
>
>  I agree. The only difference is in case of
>
>
>   void f(int x); // #1
>   void f(int x = 2); // #2
>
>
>  instead of merging to #2 and swaping contents with #1, thus pointer of #1
> now points to #2,
>  I suggest merging to #1.
>  In both cases, every use of 'f' will point to the same FunctionDecl node.

Ah, I understand what you mean. I think the important question is: how
much do you merge into #1, and do you preserve the previous
information in #1? Does #1 get the new parameter names from #2? New
typedefs in the parameter types? What about the source location?

  void f(int x); // #1
  typedef int MyFlags;
  void f(MyFlags flags = 0); // #2

What parts of the declaration at #2 will go into the FunctionDecl for
#1? Additionally: when information gets merged into #1, is that same
information that was in the FunctionDecl for #1 lost? (e.g., the
parameter name "x" it used?)

>  That way ASTConsumers like the syntax-colorizer I mentioned and
> pretty-printer (SerializationTest uses this one), can use redeclarations the
> same way
>  as single declarations. If a ASTConsumer cares only about single decls, it
> can check a decl.isRedeclaration() method and act accordingly.

We can design the interface either way... a syntax-colorizer could
just override HandleRedeclaration to call the same routine that deals
with single declarations, because it treats them the same. Other tools
can handle redeclarations differently.

  - Doug



More information about the cfe-dev mailing list