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