Soooo....After being on a mini-vacation and thinking about this more,
I'm a bit less satisfied with the current proposal. The main issue is
that we have seemingly two lookup rules based on which attribute is
used (counted_by vs. counted_by_expr).

  1. counted_by: We expect an expression that's a lone identifier.
Here, we use a pseudo-struct scope to resolve that identifier.
("Pseudo" because it's not fully defined in the standard but created
for this feature alone.)

  2. counted_by_expr: Any identifiers that appear in the struct need
to be forward declared. If they aren't, the normal lookup rules apply.

Now, I don't think this will be necessarily confusing to the
programmer, but it's inconsistent. In other words, either 'counted_by'
*must* forward declare the in-structure identifier or neither must.

It's also probable that most expressions will use in-structure
identifiers, with the occasional enum or macro. (I'm going off of
Yeoul's assertion that they've implemented this successfully on large
code bases and haven't had to make allowances for global identifiers.)

My counter proposal then is to do something like this:

1. The syntax needs to be unambiguous.
2. Identifier lookup must be consistent between the two attribute forms.
3. The common use case should take the least amount of code to write.
(More of a "nice to have".)

Therefore, I suggest the following rules, that are more-or-less the
reverse of the current proposal's rules:

- All untagged identifiers are assumed to be within the structure. If
they aren't found in the struct, it's an error.
- All globals (i.e. identifiers not in the struct) must be referenced
via a special tag or a builtin (e.g. __builtin_global_ref()). The tag
or builtin follow current scoping rules---i.e. it may pick up a shadow
variable rather than the global.

Examples:

[Assume a builtin called '__builtin_global_ref' that takes an
expression where every identifier within that expression is assumed
"global".]

struct A {
  int *buf __counted_by(len); // 'len' *must* be in the struct.
  int len;
};

constexpr int len = 42;
struct B {
  int *buf __counted_by(__builtin_global_ref(len)); // 'len' is a global.
};

enum { PADDING = 42 };
struct C {
  int *buf __counted_by_expr(len * __builtin_global_ref(PADDING));
  int len;
};

#define PADDING_EXPR __builtin_gloal_ref(len) + 42
struct D {
  int *buf __counted_by_expr(len * PADDING_EXPR);
    // PADDING_EXPR is expanded and that 'len' is not in the structure.
  int len;
};

#define PADDING_EXPR len + 42
struct E {
  int *buf __counted_by_expr(len * __builtin_global_ref(PADDING_EXPR));
    // PADDING_EXPR is expanded and that 'len' is not in the structure.
  int len;
};

There is the issue that the __builtin_global_ref() in 'struct E' may
appear to cause the sub-expression to have a higher affinity than the
multiplication but it doesn't. That may or may not be a programmer
error, but one to be aware of nonetheless.

-bw

Reply via email to