wmm@charis.UUCP (William M. Miller) (09/06/90)
As far as I can tell, X3.159-1989 does not define what happens in the following situation: struct X* xp1; { struct X* xp2; } The question is whether xp1 and xp2 have the same type. On the affirmative side, there doesn't appear to be anything in the Standard to indicate any difference in the way the scope rules apply to incomplete types. The following wording from 3.5.2.3 would seem to allow (but perhaps not to require?) this interpretation: A declaration of the form struct-or-union identifier ; specifies a structure or union type and declares a tag, both visible only within the scope in which the declaration occurs. It specifies a new type distinct from any type with the same tag in an enclosing scope (if any). If "any type with the same tag" includes incomplete types, the implication is that an incomplete type with the same tag in an enclosing type *would* be visible, apart from such a declaration. The commentary on one of the examples in 3.5.2.3 appears to be conclusive: ...the declarations struct s1 { struct s2 *s2p; /*...*/ }; /* D1 */ struct s2 { struct s1 *s1p; /*...*/ }; /* D2 */ specify a pair of structures that contain pointers to each other. Note, however, that if s2 were already declared as a tag in an enclosing scope, the declaration D1 would refer to *it*, not to the tag s2 declared in D2. Since the declaration of xp1 declares X as a tag in the enclosing block, this wording would indicate that the declaration of xp2 refers to the same tag and that, therefore, xp1 and xp2 have the same type. There are basically two factors supporting the opposite conclusion. The first is the wording used in 3.5.2.3 of the Rationale: "if struct y is already *defined* [emphasis mine] in a containing block..." This wording would tend to indicate that a full definition, not simply an incomplete type, is required in the containing block for the type to be visible. To illustrate the second consideration, consider the following slightly expanded version of the example with which I opened this posting: struct X* xp1; { struct X* xp2; } struct X { /*...*/ }; /* D1 */ 3.5.2.3 says about incomplete struct-or-union types, If the type is to be completed, another declaration of the tag in the same scope (but not in an enclosed block, which declares a new type known only within that block) shall define the content. If xp1 and xp2 have the same type, and the declaration D1 completes the type introduced by the declaration of xp1, then it also completes the type in the declaration of xp2, in violation of the above-quoted rule requiring such completion to be in the same scope. Does anyone out there in netland have anything to say about this question? ------------------------------------------------------------------------------ William M. Miller, Glockenspiel, Inc.; P. O. Box 366, Sudbury, MA 01776-0003 wmmiller@cup.portal.com BIX: wmiller CI$: 72105,1744 -- Non-disclaimer: My boss and I always see eye-to-eye (every time I look in the mirror). wmm@sdti.sdti.com
gwyn@smoke.BRL.MIL (Doug Gwyn) (09/07/90)
In article <1990Sep5.191221.5118@charis.UUCP> wmmiller@cup.portal.com writes: > struct X* xp1; > { > struct X* xp2; > } Neither of these declares a struct X. That is a crucial point to understand in conjunction with the example from 3.5.2.3 that you cited. >... there doesn't appear to be anything in the Standard to indicate any >difference in the way the scope rules apply to incomplete types. That's correct; visibility of an identifier (scope) is not affected by incompleteness of its type. > If the type is to be completed, another declaration of the tag in > the same scope (but not in an enclosed block, which declares a new > type known only within that block) shall define the content. Yes, basically one of the interesting things X3J11 figured out at the first interpretation-phase meeting was that the standard insists that type information is not propagated outward from a block. That has all sorts of subtle ramifications, fortunately not affecting programmers who use sensible coding style in the first place. For your example, basically I would say that not declaring what a struct X really is before declaring pointers to it is a poor practice except in the case of mutually-referential structures as in the 3.5.2.3 example, and even there one should as a matter of safety predeclare an incomplete type like: struct s2; /* forces s2 to refer to the one in the current scope */ struct s1 { struct s2 *s2p; /*...*/ }; struct s2 { struct s1 *s1p; /*...*/ };
wmm@charis.UUCP (William M. Miller) (09/10/90)
In article <13765@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn) writes: > In article <1990Sep5.191221.5118@charis.UUCP> wmmiller@cup.portal.com writes: > > struct X* xp1 > > { > > struct X* xp2; > > } > > Neither of these declares a struct X. That is a crucial point to > understand in conjunction with the example from 3.5.2.3 that you cited. What do you mean by "declaring a struct X?" The exact wording of 3.5.2.3 is If a type specifier of the form struct-or-union identifier occurs prior to the declaration that defines the content, the structure of union is an incomplete type. It declares a tag that specifies a type that may be used only when the size of an object of the specified type is not needed. When it says "declares a tag that specifies a type," I understood that to be equivalent to declaring a type "struct X." If you're drawing a distinction with the standalone declaration struct X; I don't see it, since the verbiage for this declaration ("specifies a structure or union type and declares a tag") seems essentially identical. If you're simply stating that neither declaration defines the contents, that's obviously true, but my question essentially boils down to whether such a defining declaration is needed. Besides, in the example, the issue is not whether a struct X is declared; the wording is, "if s2 were already declared as a tag in an enclosing scope," and it's clear that "struct X* p1" *does* declare X as a tag. > >... there doesn't appear to be anything in the Standard to indicate any > >difference in the way the scope rules apply to incomplete types. > > That's correct; visibility of an identifier (scope) is not affected by > incompleteness of its type. So the tag X from the outer block is visible in the inner block. > > If the type is to be completed, another declaration of the tag in > > the same scope (but not in an enclosed block, which declares a new > > type known only within that block) shall define the conte7t. > > Yes, basically one of the interesting things X3J11 figured out at the > first interpretation-phase meeting was that the standard insists that > type information is not propagated outward from a block. That has all > sorts of subtle ramifications, fortunately not affecting programmers > who use sensible coding style in the first place. I'm sorry to be obtuse, but I couldn't determine the "bottom line" in your posting. Let me give an example and a few possible interpretations, and perhaps you can tell me which of them is right and why (or give another interpretation I hadn't thought of). struct X* p1; void f() { struct X* p2; p2 = p1; /* A */ } struct X { int i; }; /* B */ INTERPRETATION 1: This is a legal compilation unit. p1 and p2 have the same type, so assignment A is allowed. Implication: the wording in the Standard requiring a completing declaration to be in the same block does not apply to the declaration inside f() because the type was introduced in the outer scope. Implication: the wording in the Rationale mentioning a definition is excessively restrictive. INTERPRETATION 2: This is an illegal compilation unit. p1 and p2 have different types, so assignment A is in error. Implication: the wording describing the example in the Standard is incorrect; instead of "if s2 were already declared as a tag in an enclosing scope," it should say something like "if s2 were declared as the tag of a structure whose contents have already been defined in an enclosing scope." Implication: the tags of incomplete types are *not* visible across scopes. INTERPRETATION 3: This is an illegal compilation unit. p1 and p2 have the same type, so assignment A is allowed; however, declaration B violates the restriction requiring a completing declaration to be in the same scope, since it completes the declaration in f() as well as the one in the outer scope. (BTW, I agree fully with the comment about "a sensible coding style." I'm not trying to see what I can get away with; as a member of X3J16, I'm trying to figure out what it would mean for C++ to be compatible with C on this point.) ------------------------------------------------------------------------------ William M. Miller, Glockenspiel, Inc.; P. O. Box 366, Sudbury, MA 01776-0003 wmmiller@cup.portal.com BIX: wmiller CI$: 72105,1744
scjones@thor.UUCP (Larry Jones) (09/10/90)
In article <1990Sep9.194037.346@charis.UUCP>, wmm@charis.UUCP (William M. Miller) writes: > > struct X* p1; > void f() { > struct X* p2; > p2 = p1; /* A */ > } > struct X { int i; }; /* B */ > > INTERPRETATION 1: This is a legal compilation unit. p1 and p2 have the same > type, so assignment A is allowed. Implication: the wording in the Standard > requiring a completing declaration to be in the same block does not apply to > the declaration inside f() because the type was introduced in the outer > scope. Implication: the wording in the Rationale mentioning a definition is > excessively restrictive. Bingo! The wording in section 3.5.2.3 could perhaps be clearer, but that is certainly the intent of the committee. Remember, the Rationale is not a part of the standard -- it uses much less formal and precise language to try to explain >why< the standard says what it says, not to explain >what< it says. ---- Larry Jones UUCP: uunet!sdrc!thor!scjones SDRC scjones@thor.UUCP 2000 Eastman Dr. BIX: ltl Milford, OH 45150-2789 AT&T: (513) 576-2070 I think my cerebellum just fused. -- Calvin
gwyn@smoke.BRL.MIL (Doug Gwyn) (09/10/90)
In article <1990Sep9.194037.346@charis.UUCP> wmmiller@cup.portal.com writes: > struct X* p1; > void f() { > struct X* p2; > p2 = p1; /* A */ > } > struct X { int i; }; /* B */ This is strictly conforming, and all three occurrences of "X" refer to the same structure type, which is complete at comment B. As an interesting contrast, consider struct X* p1; void f() { struct X* p2; struct X { char i; };/* C */ struct X* p3; p2 = p1; /* A */ } /* D */ struct X { int i; }; /* B */ In this example, p1 and p2 have the same struct type, as before, but p3 has a different struct type since the declaration ending at comment C declares a new type. At comment A, "struct X" refers to a complete type like the type of p3, different from the (still incomplete, as it happens) type of p1 and p2. Note also that at comment D "struct X" is still an incomplete type, because the new type at comment C does not propagate out of the scope within which it was declared (function-body block). It is also worth noting that the description of the properties of the special form of declaration struct-or-union identifier ; in 3.5.2.3 is NOT a deduction from other specifications, but specifies a special case (i.e. "kludge") that was adopted specifically for the purpose of hiding any declaration of the tag name in an outer scope. Thus, in the example struct X* p1; void f() { struct X; /* E */ struct X* p2; struct X { char i; };/* C */ struct X* p3; p2 = p1; /* A */ } /* D */ struct X { int i; }; /* B */ The type of both p2 and p3 will be that of the structure described at comment C, since the declaration at E starts a new type with tag "X" unrelated to the tag on the declaration of p1. (This form is like a declaration with struct-declarator-list in that it begins a new type, but unlike that in that it is an incomplete type.) P.S. This is how I read the standard and how I recall the discussion in X3J11; it is possible that an official interpretation could differ. For an official interpretation, you should send your query to X3J11 via the CBEMA X3 Secretariat. X3J11 meets again on the 24th of September, so if you need an official interpretation ruling soon, you should hurry.