SYNOPSIS: unary-operator: . identifier DESCRIPTION: - It is not an lvalue. - This means sizeof() and _Lengthof() cannot be applied to them.Sorry, the above is a thinko. I wanted to say that, like sizeof() and _Lengthof(), you can't assign to it.- This prevents ambiguity with a designator in an initializer-list within a nested braced-initializer.- The type of a .identifier is always an incomplete type.Or rather, more easily prohibit explicitly using typeof(), sizeof(), and _Lengthof() to it.Hmm, this is not enough. Pointer arithmetics are interesting, and for that, you need to implicitly know the sizeof(*.p).How about allowing only integral types or pointers to integral types?
I've been thinking about keeping the number of passes as low as possible, while allowing most useful expressions:
Maybe forcing some ordering can help:- The type of a .initializer is complete after the opening parenthesis of the function-declarator (if it refers to a parameter) or after the opening brace of a braced-initializer, if it refers to a struct/union member, except when the type is a variably-modified type, which will be complete after the closing parenthesis or brace respectively.
I'm not sure I got the wording precisely, or if I covered all cases (like types that cannot be completed for other reasons, even after the closing ')' or '}'.
- This prevents circular dependencies involving sizeof() or _Lengthof(). - Shadowing rules apply. - This prevents ambiguity. EXAMPLES: - Valid examples (libc): int strncmp(const char s1[.n], const char s2[.n], size_t n); int cacheflush(void addr[.nbytes], int nbytes, int cache); long mbind(void addr[.len], unsigned long len, int mode, const unsigned long nodemask[(.maxnode + ULONG_WIDTH ‐ 1) / ULONG_WIDTH], unsigned long maxnode, unsigned int flags); void * bsearch(const void key[.size], const void base[.size * .nmemb], size_t nmemb, size_t size, int (*compar)(const void [.size], const void [.size])); - Valid examples (my own): void ustr2str(char dst[restrict .len + 1], const char src[restrict .len], size_t len); char * stpecpy(char dst[.end - .dst + 1], char *restrict src, char end[1]); - Valid examples (from this thread): - struct s { int a; }; void f(int a, int b[((struct s) { .a = 1 }).a]); Explanation: - Because of shadowing rules, .a=1 refers to the struct member.- Also, if .a referred to the parameter, it would be an rvalue, so it wouldn't be valid to assign to it. - (...).a refers to the struct member too, since otherwise an rvalue is not expected there.- void foo(struct bar { int x; char c[.x] } a, int x); Explanation: - Because of shadowing rules, [.x] refers to the struct member. - struct bar { int y; }; void foo(char p[((struct bar){ .y = .x }).y], int x); Explanation: - .x unambiguously refers to the parameter. - Undefined behavior: - struct bar { int y; }; void foo(char p[((struct bar){ .y = .y }).y], int y); Explanation: - Because of shadowing rules, =.y refers to the struct member. - .y=.y means initialize the member with itself (uninitialized use).- (...).y refers to the struct member, since otherwise an rvalue is not expected there.- Constraint violations: - void foo(char (*a)[sizeof *.b], char (*b)[sizeof *.a]); Explanation: - sizeof(*.b): Cannot get size of incomplete type. - sizeof(*.a): Cannot get size of incomplete type. - void f(size_t s, int a[sizeof(1) = 1]); Explanation: - Cannot assign to rvalue. - void f(size_t s, int a[.s = 1]); Explanation: - Cannot assign to rvalue. - void f(size_t s, int a[sizeof(.s)]);
This should actually be valid.
Explanation: - sizeof(.s): Cannot get size of incomplete type. Does this idea make sense to you? Cheers, Alex
-- <http://www.alejandro-colomar.es/>
Attachment:
OpenPGP_signature
Description: OpenPGP digital signature