On 11/13/22 17:28, Alejandro Colomar wrote: > 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. > >    -  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)]); > >        Explanation: >        -  sizeof(.s): Cannot get size of incomplete type. > > > Does this idea make sense to you? > > > Cheers, > Alex --