Who owns declarations?

Hi,

I'm currently implementing Sema and AST support for C++ try-catch statements, and I'm confused about ownership.

A basic C++ try-catch looks like this:

try { ... }
catch (exception_type exception_var) { ... }

"exception_type exception_var" is a 'exception-declaration' production; very much like a function parameter declaration, actually. I use VarDecl to represent it in the AST, though.
However, I'm somewhat confused as to who owns the VarDecl. Should I destroy it when the CXXCatchStmt is destroyed? Should I serialize it as owned or as unowned?

Sebastian

I suggest that the CXXCatchStmt own the VarDecl, and be responsible for its destruction and serialization. This is how CXXConditionalDeclExpr handles its VarDecl for declarations of variables within the condition of an "if".

  - Doug

Douglas Gregor wrote:

I suggest that the CXXCatchStmt own the VarDecl, and be responsible for its destruction and serialization. This is how CXXConditionalDeclExpr handles its VarDecl for declarations of variables within the condition of an "if".

OK, thanks.

By the way, why does CXXConditionalDeclExpr derive from DeclRefExpr? That's counter-intuitive from several viewpoints.

Sebastian

Douglas Gregor wrote:

I suggest that the CXXCatchStmt own the VarDecl, and be responsible for its destruction and serialization. This is how CXXConditionalDeclExpr handles its VarDecl for declarations of variables within the condition of an "if".

OK, thanks.

By the way, why does CXXConditionalDeclExpr derive from DeclRefExpr?

I believe it's because IfStmt's condition is an Expr*, so CXXConditionalDeclExpr is an Expr that also declares a variable. The derivation from DeclRefExpr allows the rest of semantic analysis (that knows how to treat a DeclRefExpr as a boolean expression) to deal with the declaration.

That's counter-intuitive from several viewpoints.

How so?

  - Doug

Douglas Gregor wrote:

By the way, why does CXXConditionalDeclExpr derive from DeclRefExpr?

I believe it's because IfStmt's condition is an Expr*, so CXXConditionalDeclExpr is an Expr that also declares a variable. The derivation from DeclRefExpr allows the rest of semantic analysis (that knows how to treat a DeclRefExpr as a boolean expression) to deal with the declaration.

That's counter-intuitive from several viewpoints.

How so?

A CXXConditionalDeclExpr declares a variable, it doesn't reference it. That's the most important difference between the two, and it doesn't lend itself to using derivation - note that CXXConditionalDeclExpr doesn't have serialization implemented, precisely because it owns the Decl and DeclRefExpr doesn't, which causes confusion.

Sebastian

Douglas Gregor wrote:

By the way, why does CXXConditionalDeclExpr derive from DeclRefExpr?

I believe it's because IfStmt's condition is an Expr*, so CXXConditionalDeclExpr is an Expr that also declares a variable. The derivation from DeclRefExpr allows the rest of semantic analysis (that knows how to treat a DeclRefExpr as a boolean expression) to deal with the declaration.

That's counter-intuitive from several viewpoints.

How so?

A CXXConditionalDeclExpr declares a variable, it doesn't reference it.

It does both. We're talking about something like

  if (int x = foo()) {
  }

where everything in the parentheses is the CXXConditionalDeclExpr. It declares the variable x, and then acts as a reference to the variable x.

That's the most important difference between the two, and it doesn't lend itself to using derivation - note that CXXConditionalDeclExpr doesn't have serialization implemented, precisely because it owns the Decl and DeclRefExpr doesn't, which causes confusion.

Perhaps what we really need is not the CXXConditionalDeclExpr class, but the ability for DeclRefExpr to own its declaration (based on some flag, which could just be the expression class itself). That would also be useful, e.g., when we have to build an OverloadedFunctionDecl on-the-fly that will be owned by a DeclRefExpr, say, to retain the results of name lookup in a template.

  - Doug

So, in talking about this over lunch, we decided that CXXConditionalDeclExpr isn't the best way to model this (which you already knew <g>). The convincing argument is that the CXXConditionalDeclExpr might not even be the "If" expression itself, if it ends up being a class type with a conversion operator, e.g.,

  struct X {
    operator int();
  };

  if (X x = foo()) {
    // The expression for the If will be some kind of implicit call to X::operator int(), whose argument is the CXXConditionalDeclExpr
  }

It would be better for the IfStmt to have an optional VarDecl in it, and remove CXXConditionalDeclExpr.

It'd also be nice if we could handle the code above :slight_smile:

  - Doug