Sema && redefinitions

Hello, Everyone

We faced with the following problem trying to add sema checks for
dllimport / dllexport attributes.

Consider the following situation:

void __attribute__((dllimport)) foo();

void foo() {
}

In this situation we need to ignore dllimport attribute everywhere and
issue warning. The problem is that at the point, when we just saw the
body of foo() w/o dllimport attribute - all attributes were already
merged in and thus we cannot distinguish declaration and redefintion.

Another approach is the store first decl somewhere and process in the
late end of sema. But then we faced with one problem... How one can
obtain definition of 'foo' given a first declaration? It seems, that
getPreviousDeclaration() works only backward, is there way to obtain the
definition?

All other possible solutions look really hacky and lead to significant
overhead (e.g. checks on each definition, etc).

Or... maybe there is some other clever way to do semanatic checks in
such situations we're not aware of?

Hello, Everyone

We faced with the following problem trying to add sema checks for
dllimport / dllexport attributes.

Consider the following situation:

void __attribute__((dllimport)) foo();

void foo() {
}

In this situation we need to ignore dllimport attribute everywhere and
issue warning. The problem is that at the point, when we just saw the
body of foo() w/o dllimport attribute - all attributes were already
merged in and thus we cannot distinguish declaration and redefintion.

Couldn't you just scan the getPreviousDeclaration() chain backward, to find the first declaration of this function that contains the dllimport attribute? You can complain about that declaration, then remove the attribute from all of the declarations to silence any further warnings.

Another approach is the store first decl somewhere and process in the
late end of sema. But then we faced with one problem... How one can
obtain definition of 'foo' given a first declaration? It seems, that
getPreviousDeclaration() works only backward, is there way to obtain the
definition?

If you've processed the whole translation unit, you could look up the most recent declaration of 'foo' and call getBody on it to find the definition.

  - Doug

Hi, Douglas

Couldn't you just scan the getPreviousDeclaration() chain backward, to
find the first declaration of this function that contains the
dllimport attribute? You can complain about that declaration, then
remove the attribute from all of the declarations to silence any
further warnings.

At this point (when we already saw the body) all attributes are already
merged thus we cannot distinguish the following two cases:
1. Definition originally contained attribute applied
2. Attribute was on prev. declaration

If you've processed the whole translation unit, you could look up the
most recent declaration of 'foo'

How?

Hi Anton,

Hi, Douglas

Couldn't you just scan the getPreviousDeclaration() chain backward, to
find the first declaration of this function that contains the
dllimport attribute? You can complain about that declaration, then
remove the attribute from all of the declarations to silence any
further warnings.

At this point (when we already saw the body) all attributes are already
merged thus we cannot distinguish the following two cases:
1. Definition originally contained attribute applied
2. Attribute was on prev. declaration

Attributes are only merged from earlier declarations to later declarations. So, for example, if we had:

void foo(); // #1
void __attribute__((dllimport)) foo(); // #2

void foo() { // #3
}

#1 doesn't have the dllimport attribute. #2 adds the dllimport attribute, but only to declaration #2. #2 has a getPreviousDeclaration() link back to #1.

At #3, we merge the dllimport from #2 into #3, so #3 has the dllimport attribute. #3's getPreviousDeclaration() link back to #2.

So, from the point where you hit the definition, you can walk the getPreviousDeclaration() chain back until you find the declaration that either has no previous declaration or whose previous declaration does not have the attribute.

If you've processed the whole translation unit, you could look up the
most recent declaration of 'foo'

How?

Hrm. Actually, this is tougher than expected. I guess you could look through the declarations in the translation unit and then perform name lookup (e.g., via Sema::LookupDecl) on the names of each to get the most recent declaration. Still, it's messy; I hope that the scheme described above works out for you, because I think it's far simpler.

   - Doug

Hi, Douglas

At #3, we merge the dllimport from #2 into #3, so #3 has the dllimport
attribute. #3's getPreviousDeclaration() link back to #2.

The problem is that we need to separate two cases:

1.
void foo() __attribute__((dllimport));
void foo() {}

This is legal, we need just to ignore dllimport attribute and issue a warning

2. void foo() __attribute__((dllimport)) {}

This is hard error.

At the point, when attributes were merged, we cannot distinguish cases
1 and 2 and I feel pretty bad into adding something 'custom' inside
merging logic...

So, from the point where you hit the definition, you can walk the
getPreviousDeclaration() chain back until you find the declaration
that either has no previous declaration or whose previous declaration
does not have the attribute.

Right, but this won't give anything to us, see example above.

Oh, that is tricky. Our ASTs can't tell those two cases apart.

To fix this, I suspect we'd want to add a bit into Attr that states whether this copy of the attribute was specified directly or whether it was propagated from a previous declaration of the same entity. We do something similar with default arguments of function parameters.

  - Doug