Mar 3 16:48 1993 Issues; by Plum+Saks; WG21/N0239; X3J16/93-0032 Page 1 Date: Mon, 1 Feb 93 17:56:48 HST Original-From: plumhall!plum@uunet.UU.NET (Thomas Plum) Subject: core issues 159 thru 250 Message c++std-core-1823 Dan Saks and I posted some lists of C++ issues to the editorial reflector last August, as edit-36 and edit-37 . I re-formatted these somewhat, and registered them with Josee Lajoie. We jointly decided that, at least for this initial posting, the abbreviated format you see below would suffice for now. When the issues lists become more automated, I will format them into the (by now familiar) "issues" format. The first part lists the issues from #core-159 to #core-250 . The second email lists issues #core-251 to #core-331 . Thomas Plum Plum Hall Inc, #261 PO Box 111333 plum@plumhall.com Kamuela HI 96743 USA [please note new numbers] 808-882-1255 FAX 808-882-1556 --------------------------------------------------------------------- | Subject: Editorial Notes on the C++ Working Paper (Part 1) | Date: July 1992 | By: Thomas Plum and Daniel Saks Issue #core-159: double-underscore shouldn't be required diagnostic __ 28p31 When "required diagnostics" are specified, several people have suggested that "double underscore" should not be in the "required diagnostic" category. The general subject of "required diagnostics" still needs clarifying. Issue #core-160: don't say "error which shall be diagnosed" [editorial] __ 291p31 now says "It is an error which shall be diagnosed if the value of an integer literal cannot be represented by any of the allowed types." This is not a good precedent. The whole issue of required diagnostics should be addressed consistently and wholesale, not just item-by-item like this. For now, we would suggest saying "It is an error if the value ...." Issue #core-161: name of class with constructor can't be shared __ 32p24: We believe that the discussion in core-787 thru 791 re stat(9) is still unresolved. For what it's worth, our preference would be to support Jerry Schwarz's suggestion in core-791: If we are going to make a special case out of this, I'd prefer to just make the original conflict illegal. That is a classname defined in the same scope as an "object, function, or enumerator of the same name" cannot have constructors. 92/12/07 NOTE: Stroustrup's article "Evolution of C++: 1985 to 1989" says: "The name of a class with a constructor cannot also simultaneously refer to something else: struct s { s(); /* ... */ }; Mar 3 16:48 1993 Issues; by Plum+Saks; WG21/N0239; X3J16/93-0032 Page 2 int s(); // error Issue #core-162: does :: qualifying work inside block scope? __ 32p23 It's not clear whether the :: qualifying is supposed to work inside block scope. Issue #core-163: state exact rules for use of enum hidden by object [editorial] __ 32p27a says that an enumeration name hidden by an object name can be used when appropriately prefixed. The draft is a bit unclear. It just says "Similarly ..." Just how "similar"? Issue #core-164: "no linkage" or "internal linkage" for typedef etc. [editorial] __ 33p31 says that typedef names, enumerators, and template names do not have external linkage. Does this mean "either internal linkage or no linkage", or does it mean "no linkage"? We have a preference for "no linkage", on the grounds that the linkage rules are complicated enough already. Issue #core-165: more precise about agreement of type of extern [editorial] __ 33p71 The types specified in all declarations of a particular external name must be identical except for the use of typedef names (f7.1.3) and unspecified array bounds (f8.2.4). Here is where the definition of "type" comes into play. We suggest "After all type-transformations (during which typedefs are replaced by their definitions), the types specified by all declarations of a particular external name must be identical, except that such types may differ by the presence or absence of a major array bound." Issue #core-166: consistency regarding static initialization __ 34p5 says that the initialization of nonlocal static objects in a translation unit is done before the first use of any function or object defined in that translation unit. Then 35p52 says that such initializations may be done before the first statement of main or deferred to any point in time before the first use of a function or object defined in that translation unit. Then 35p53 says that the default initialization of all static objects to zero is performed before any dynamic (that is, run-time) initialization. There is considerable overlap between these static initialization requirements and the requirements made elsewhere. E.g. 67p42 says that when a static variable is initialized with a non-constant expression, the default initialization by 0 takes place before block entry. 92/12/07 NOTE: When Environment Subgroup reports on static initialization, these clauses should all be examined. Issue #core-167: timing of "old C" static initializers __ 34p5: Discussions are underway in WG21+X3J16 on the issue of the timing of "old C" static constant (but non-zero) initializers. Should C++ promise to initialize with static constants prior to any constructors? There is no consensus yet. Mar 3 16:48 1993 Issues; by Plum+Saks; WG21/N0239; X3J16/93-0032 Page 3 Issue #core-168: order of static initializer __ 34p54 No further order is imposed on the init of objs from different trans-units This is still under debate, as of June 92. Not yet resolved. Issue #core-169: destructors and atexit __ 34p64 says that if atexit is to be called, objects initialized before an atexit call may not be destroyed until after the function specified in the atexit call has been called. What does this mean? Does it require that after T obj = init; atexit(&fun); the variable obj cannot be destroyed until the exit-time call to fun ? If we understand this requirement, one simple way to ensure the requirement is met is, upon exit, first complete all the atexit call list, and only then do the destructors. If this is true, then the words "If atexit() is to be called" would seem to be redundant. Issue #core-170: define "signed integer" and "unsigned integer type" __ 361p71 [Jun 92] says "Types char and the signed and unsigned integer types, ..." includes signed char and unsigned char , which were left out of the previous list. Good. Note, however, that the terms "signed integer type" and "unsigned integer type" are not in the current draft. The C Compatibility Group recommended that all the ANSI-C definitions of arithmetic types be adopted as-is (or at least in substance if not identical words), just to avoid little errors like this. Yes, of course, enumeration is now omitted from integral type. Issue #core-171: representation of char* and void* ___ 362: For practical C compatibility, an implementation should either (a) support the old C behavior in which char* and void* have the "same representation" or (b) issue diagnostic messages about programs whose behavior depends upon the "same representation" rules. It seems very dangerous to allow a "quiet change" that invalidates such programs without any diagnosis. 92/12/07 NOTE: This is discussed in detail in x3j16-compat-84 regarding layout rules. Issue #core-172: add "incompletely-defined object type" __ 362p6 After the London meeting, we confirmed with Bjarne that his suggested set of acronyms was F.T., I.O.T., and C.O.T. Somewhere around 362p6 we should adopt the basic description from ISO C of the three type categories. We propose new names: "function type", "incompletely-defined object type", and "completely-defined object type". (C++ already has a "complete type" in unrelated context.) 92/12/07 NOTE: This is on Jonathan's action items from the Boston meeting. Issue #core-173: rules for cv-qualifiers on conversion to void* __ 46p15 The rules for converting pointers to void* are incomplete. Mar 3 16:48 1993 Issues; by Plum+Saks; WG21/N0239; X3J16/93-0032 Page 4 Here's a fresh attempt: "An expression of type ``pointer to cv-qualifiers-1 T1'' (a C.O.T. or an I.O.T.) may be converted to a ``pointer to cv-qualifiers-2 void'' type if the following restriction holds: The set of cv-qualifiers in cv-qualifiers-1 must be a subset of the set of cv-qualifiers in cv-qualifiers-2." Better idea: State the rules for "sufficiently-qualified target pointer" in one place, and refer to that phrase everywhere else. Issue #core-174: "sufficient bits" is non-portable __ 46p16 An operand of type ``pointer to function ...'' can be converted to type ``void*'' if sufficient bits. [This is highly non-portable; it should be an extension, not part of the Standard.] Issue #core-175: clarify "null pointer converted into itself" [editorial] __ 46p18 "The null pointer is converted into itself." This is somewhat too vague. And why is this rule attached to the derived-to-base conversion rule? Issue #core-176: what happens in pointer-to-member conversion __ 48p* Section 4.8 describes *when* conversion from ptr-to-member-of-base can be converted to ptr-to-member-of-derived, but omits discussion of *what* happens. Here is a very bad version of the missing words: "If class D is derived from class B , and b has type B , and d has type D , and pointer-to-member-of-base-class pmb is converted to pointer-to-member-of-derived-class pmd , then the member name in class B designated by b.*pmb is the same member name as is designated by d.*pmd in D's instance of B." Also, we think the wording of 48p14 is either wrong or ungrammatical. We think what is meant would read like this: "A pointer to a T1-member of a class B may be converted to a pointer to a T2-member of a class D derived from class B, provided the (inverse) conversion from a pointer to class D into a pointer to the (accessible) base class B can be done unambiguously, and provided that T2 differs from T1 only in having more cv-qualifiers." Some version of the same words is needed in 55p*, where again there is no definition of the semantics, just "The result is an object ... [*which object*]". Issue #core-177: disallow converting to pointer to member of derived? __ 48p14 implies it's ok to cast from a pointer to a member of a virtual base class to a pointer to member in a derived class. But the corresponding cast from a pointer to a virtual base class to a derived class is disallowed in 54p9. Some implementors have argued that the reason for disallowing the cast from virtual base to derived is that there is no way to find the relative offsets of the two using the usual implementation of virtual base classes, and that the corresponding cast for a pointer to member should be disallowed for the same reason. Mar 3 16:48 1993 Issues; by Plum+Saks; WG21/N0239; X3J16/93-0032 Page 5 Issue #core-178: completely specify treatment of operands __ 5p6 We think this paragraph needs greater precision. Part of the necessary discussion is currently placed in 824p5 (Declarators, Arrays). Here is our best shot at the required words: "Certain restrictions and rules govern the treatment of operands. 1. When an expression is used to initialize a reference (including function argument and function return), the behavior is governed by 8.4.3 (References), including the possible production of a temporary. 2. Otherwise, if the expression is the operand of the unary operators sizeof , address-of (&), increment (++), or decrement (--), or if the expression is the left operand of the class member access operator (.), or if the expression is the left operand of one of the assignment operators (=, +=, etc.), the behavior is governed by the appropriate section of this chapter. 3. Otherwise, if the expression is a character string literal used to initialize an array of character type, or is a wide string literal used to initialize an array with element type wchar_t, the behavior is governed by Character Arrays (8.4.2). 4. Otherwise, if the expression is an lvalue that has type ``array of T'', the expression is converted to an expression that has type ``pointer to T'' that points to the initial element of the array object and is not an lvalue. 5. Otherwise, if the expression has type ``function returning T'', and it is the operand of the address-of operator, the behavior is governed by Unary Operators (5.3). 6. Otherwise, if the expression has type ``function returning T'', and it is the left operand of the function-call operator, the behavior is governed by Function Call (5.2.2). 7. Otherwise, if the expression has type ``function returning T'', it is converted into an expression of type ``pointer to function returning T'', unless the expression designates a non-static member function, in which case the program is erroneous [or valid pointer-to-member-function?? see martino item in core-971]. 8. Otherwise, if the operand is an lvalue, the value of the operand is produced by the _evaluation_ of the lvalue, that is, by accessing the value stored in the object designated by the lvalue. An expression of type ``reference to T'' is an lvalue, and the evaluation accesses the object designed by the reference. A reference can be thought of as a name (or alternative name) for an object. The type of the evaluated result is the same type as the lvalue, except for the removal of any cv-qualifiers modifying that type. [FOOTNOTE: Thus, if i is a variable of type const volatile int , the type of the right operand of the assignment j = i is simply ``int''.] This removal of cv-qualifiers does not count as a standard conversion Mar 3 16:48 1993 Issues; by Plum+Saks; WG21/N0239; X3J16/93-0032 Page 6 when considering overloading resolution (13.2). 9. Otherwise, the operand is a non-lvalue expression. [FOOTNOTE: A non-lvalue expression is sometimes informally referred to as an ``rvalue''.] These transformations determine the type of the operand. This type is the _original operand type_, to which further conversions may be applied (as determined by Standard Conversions, 4). The original operand type is significant for determinations of Overloading (13) and Templates (15). [And chapters 13 and 15 need to incorporate "original operand type". Or use some other words to define this concept. The current draft is probably not sufficiently clear.] Issue #core-179: value of reference can be function? __ 5p7: Note that 37p1 says that, in C++, the term "lvalue" designates both object and function. Therefore, where 5p7 says that the value of a reference expression is the "object of type T denoted by the reference", this is overlooking the expressions of function type. (Or should 822 be revised to prohibit "reference to function"?) Issue #core-180: qualified-id isn't always a valid primary-expression __ 51p16 says that qualified-id is a primary-expression . This probably introduces more than is wanted. Clearly, qualified-id is an evaluatable expression (anywhere) if it is a static member, or (inside a non-static member function) if it is a data member. But even "evaluatable" is insufficient: what about sizeof(qualified-id) ? And Martin raised good issues about &qualified-id and &(qualified-id) . Needs clarifying. [see core-971] Issue #core-181: clarity about class-name::class-name [editorial] __ 51p8 says Where class-name::class-name or class-name::~class-name is used, the two class-names must refer to the same class; this notation names constructors (12.1) and destructors (12.4), respectively. We think what is intended would read as follows: Where class-name::class-name is used, and the two class-names refer to the same class, this notation names the constructor (12.1). Where class-name::~class-name is used, the two class-names must refer to the same class; this notation names the destructor (12.4). As written, the draft disallows class1::class2 . Issue #core-182: incorrect reference to (9.1) [editorial] __ 51p81 says that "(9.1)" is the reference for "nested-class-specifier", but now it's found in 7.1 . Purely editorial. Issue #core-183: prohibit explicit call of base-class destructor? __ 51p81: Explicit calls of a base-class destructor through an object pointer are not specifically allowed by the spec. Constructors and destructors are not inherited, so some have argued that such calls should be disallowed. Implementations differ. Issue #core-184: passing class object to varargs function Mar 3 16:48 1993 Issues; by Plum+Saks; WG21/N0239; X3J16/93-0032 Page 7 __ 522p52 "An object of a class for which no formal argument is declared is passed as a data structure." Much too vague. The C Standard is also too vague. C implies that a class X arg *can* be passed, but that the only portable way to receive it would be for the receiving function to use va_arg(ap, class X) and retrieve it as an entire object. The C Standard _is_ clear that va_arg cannot be used to extract the scalar members of class X one at a time. For example, we were informed of a C implementation with two separate argument stacks -- a scalar stack and an aggregates stack. The va_arg mechanism works (just barely), because every time you ask for va_arg(ap, struct st) , the compiler knows that the struct st is the next aggregate in the aggregate stack. The words in the draft seem to imply a different mechanism. Consider struct di { double d; int i; } odi; The words in the draft seem to imply that if we pass odi to a varargs function, that function would access its arguments with va_arg(p, double) and then va_arg(p, int). This would abolutely bomb in some ISO C environments. It assumes one particular strategy for passing varargs. The only guarantee of ISO C is that if odi is passed as an argument, it can be accessed with va_arg(ap, struct di) (or just va_arg(ap, di) in C++, of course). We know this creates issues about assignment operators, constructors, destructors, etc. Maybe the only arguments with well-defined semantics are "C structures" (or possibly "aggregates"). 92/12/07 NOTE: The paper x3j16-compat-84 solicits a name and definition for "Plain Old Data Structure" [PODS]. This is one place where [PODS] would be relevant. Issue #core-185: lvalue-ness of members of temporaries __ 524 This allows function-returning-class-object to be the left operand of dot and arrow . And the lvalue-ness of the result depends only on the lvalue-ness of the member. This means that it's always valid to take the address of an accessible data member inside a temporary returned object, such as p = &f().m; OR f2( &f1().m ); [Feb 92] Nearly everyone we've talked to believes that these words are just an error, not a feature. Perhaps it should say something like "and it is an lvalue if the left-hand expression is an lvalue and the member is an lvalue". [July 92] There has been much recent discussion of such uses of returned classes in the core reflector recently. It's still under discussion. Issue #core-186: type of o.m __ 524: The "type" of o.m is not specified. If m is a function, this is a non-trivial question. (See note on 53p2 below.) Our suggestion is that, for function member, the type should somehow include both the class type and the function member type. Issue #core-187: prohibit address of member function? __ 53p2: We've heard a suggestion (from Clamage, we think) that it should be illegal to take the address-of a member function of a class object, unless the function is static. That is, &o.f or &p->f should be Mar 3 16:48 1993 Issues; by Plum+Saks; WG21/N0239; X3J16/93-0032 Page 8 allowed only if f is a static member. This does not appear to be said anywhere. It is related, but not identical, to the observation in 94p6 (see below) about the type of a member. (See 51p8 above.) Issue #core-188: "lvalue" includes "function" __ 53p2 is written as though "lvalue" only meant "object", not "function". But 37p1 says that "lvalue" designates both object and function. Issue #core-189: drop unary + of pointer? __ 53p31 Unary + can apply to a pointer. ANSI C dropped this out of its draft several years ago. We believe the problem had something to do with pointers on a segmented architecture, but do not recall exactly. It is not a "compatibility" question because no strictly-conforming ANSI C program can use it. Issue #core-190: postfix ++ isn't lvalue __ 531p14 The result of prefix ++ is an lvalue, but 525p15 says that the result of postfix ++ is not an lvalue. In ANSI C, neither is an lvalue. Again, no compatibility problem, just a difference. 92/12/07 NOTE: Since writing this, I've seen discussion by Stroustrup indicating that the asymmetry is deliberate. Consider the item dropped (unless someone wants to document the reason for this). Issue #core-191: sizeof and IOT __ 532p13 When "incompletely-defined object type (IOT)" is added to the definitions, this becomes one of the natural places to use it: "The sizeof operator may not be applied to a function, a bit-field, an undefined class, the type void, or an array with an unspecified dimension." becomes "The sizeof operator may not be applied to an expression that has function type or an IOT, or to the parenthesized name of such a type, or to an lvalue that designates a bit-field object." (as in the ANSI C standard). Issue #core-192: add __strict_align_t? __ 533p??: It would be useful if provided a typedef for a name such as __strict_align_t , a type whose alignment is the strictest required in this environment. It is otherwise hard to write a portable overloaded new operator. Faking it, by defining a union of several "typical" types, is not really portable, and its quiet mode of failure might be extremely puzzling, because the program would run just fine most of the time in most environments, except that in some unusual environment the program would occasionally produce an alignment error. As WG14 and X3J11 have found out, some compilers add an alignment requirement for structures embedded inside structures, one which is even more restrictive than the scalar types! There are no real-world guarantees about alignment, unless the committee imposes them. ALTERNATIVE: The committee could prescribe specific requirements for alignment. E.g., in any conforming environment, no object may have an alignment requirement more restrictive than this specific type: struct _strict_align_t { struct { long n; double d; }; }; 92/12/07 NOTE: To allow the writing of portable allocators, it may also Mar 3 16:48 1993 Issues; by Plum+Saks; WG21/N0239; X3J16/93-0032 Page 9 be necessary to define an __align_pointer(p) function, which returns the nearest pointer (address) value which is aligned on the strictest boundary and is greater than or equal to the pointer value p . Issue #core-193: returned value from new (no bookkeeping?) __ 533p4: The draft doesn't actually say that the value returned by the new function is returned by the new expression. Or if it's an array, how the value returned is related. People could make reasonable assumptions, but the draft doesn't specify anything. Here are some suggestions we've received, but it's also been noted that some implementations may not support some of these: a) the value of the first argument to 'operator new' will be equal to the size of the object type being created b) the value of the pointer returned by the 'operator new' function will be the value of the new operator c) the value of the pointer deleted by the delete operator will be the value passed to the 'operator delete' function d) the size of storage to be freed(deleted) will be equal to the size of the object type being deleted Issue #core-194: new of array, and generated constructor __ 533p_102 says that new can create arrays of objects of class type with constructors if the class has a default (niladic) constructor. Does a class with a generated constructor count? Issue #core-195: use "less strict alignment" not "smaller size" __ 54p83 "It is guaranteed that a pointer to an object of a given size may be converted to a pointer to an object of the same or smaller size and back again without change." X3J11 revised these old words to use "less strict alignment" rather than "smaller size": (C Lang.3.4) "It is guaranteed, however, that a pointer to an object of a given alignment may be converted to a pointer to an object of the same alignment or a less strict alignment and back again; the result shall compare equal to the original pointer. (An object that has character type has the least strict alignment.)" Issue #core-196: IOT and pointer cast __ 54p_121 "A yet undefined class may be used in a pointer cast, in which case no assumptions will be made about class lattices." When "incompletely-defined object type" gets incorporated, this is one of the affected paragraphs. Issue #core-197: use "lvalue expression" rather than "object"? __ 54p_131 "An object [!] may be explicitly converted to a reference type X& if ..." Objects exist at run-time. (So when 533p11 says "The new operator attempts to create an object of the type-name ..." this is a correct use of the word object.) Expressions that designate objects might more clearly be called "lvalue expressions"; the wording might be something like "An lvalue expression may be explicitly converted to a reference type X& if ..." Mar 3 16:48 1993 Issues; by Plum+Saks; WG21/N0239; X3J16/93-0032 Page 10 This use of the word "object" rather than "lvalue expression" is pervasive throughout the draft, not just a one-shot change here. [July 92] This topic is being discussed in the core reflector now. Issue #core-198: clarify "conversion of reference to base" __ 54p_133 "Conversion of a reference to a base class ... is handled similarly ["similarly"? Just how similar?] to the conversion of a pointer to a base class ... with respect to ambiguity, virtual classes, and so on." ["and so on"? Exactly what?] Issue #core-199: converting object pointer and function pointer __ 54p_15* Converting object ptrs into fct ptrs and vice versa. (1) No portable program can do this, because no guarantees are provided re sizes of ptrs. (2) In ANSI C, it's a syntax error to convert obj-ptr into fct-ptr and vice-versa. ("Constraint error", actually.) (3) Language like "has enough bits" can't go in the standard. E.g., many architectures have complicated pointer layouts (segment+offset, maybe protection-status bits, etc). So number-of-bits isn't precise enough. For all these reasons, we suggest that the result of converting obj-ptr to fct-ptr and vice-versa be "undefined behavior". We would, of course, be willing to have it be flatly prohibited, but we don't know whether some environments want to keep supporting it. Issue #core-200: calling through pointer to member function __ 54p_18: Needs another sentence, modeled after 54p_16: "The effect of calling a member function through a pointer to a member function type that differs from the type used in the definition of the member function is undefined." Alternatively, change 54p_162 to say "The effect of calling a function (or member function) through a pointer (or pointer to member) . etc." Issue #core-201: prohibit relationals upon void*? __ 59p2 (Relational) This allows char *pc; void *pv; if ( pc < pv ) // ... I.e., ptr-to-object can be compared less-than (or greater-than) a void* pointer. We have no serious objection; it's just looser than C allows. It's a "C difference", but not a "C incompatibility". It's philosophically a bit strange, though, that C++ aims to be more type-safe than C, but allows such free-and-easy use of a "typeless type" like void* . Issue #core-202: prohibit lvalue use of assignment? __ 5_16p12 was revised in Feb 92 draft by vote of WG21+X3J16 to allow conditional-expr: logical-or-expr ? expr : assignment-expr We believe that this now means that n ? i=a : j=b is supposed to parse as n ? (i=a) : (j=b) If we have understood this correctly, this change may introduce a very subtle, but very serious, quiet change to some existing C++ programs. Several current compilers accept the example expression, but they parse it as Mar 3 16:48 1993 Issues; by Plum+Saks; WG21/N0239; X3J16/93-0032 Page 11 (n ? (i=a) : j) = b that is, assign b to whichever lvalue was chosen. I grant that many people would find the "old" behavior more surprising, so some might claim that the change is good, even if it changes the behavior of some (previously surprising) programs. Allowing the result of assignment to be an lvalue, so that (i=a) = b is allowable in the first place, would seem in itself to create some reliability problems. Is there a purpose for the lvalue-ness of assignment which is important enough to over-ride the reliability question? If no one else sees a problem here, the current draft is clear, and not in itself any problem. Issue #core-203: [no remaining issue, resolved] __ 5_17p1 LA3_16 Assignment: [our previous editorial note was wrong - here's a revision] Notice that C++ says the type of (the result of) asst is the type of the left operand, where C says "type of left operand with cv-qualifiers removed". This is a necessary difference, not an oversight: volatile int vi; void f(volatile int *p); f( &(vi = 0) ); // the assignment is an lvalue, so cv-quals needed This kind of note is good for the rationale. Issue #core-204: constraints on assignment of pointers ___ 5_17p3 The restrictions -- "constraints" -- on assignment of pointers are too vague in the C++ wording. And the treatment of qualifiers is still wrong. Here's a suggestion: "An operand of type ``pointer to T1'' can be assigned to an lvalue of type ``pointer to T2'' if the types T1 and T2 differ only in the presence of more cv-qualifiers modifying T2. For example, a ``pointer to const int'' can be assigned to a ``pointer to const volatile int'', but not vice-versa. [Define as "sufficiently-qualified".] Issue #core-205: irrelevant semicolon [editorial] __ 5_17p81 There is an irrelevant semicolon here: ... " ... is equivalent to E1 = E2 op (E2) ..." Issue #core-206: allow cv-qualifier in new-expression? __ 533p41 says that the type-specifier-seq in a new-expression can't contain a cv-qualifier. Some have suggested that this restriction should be lifted. Current implementations differ. Issue #core-207: register as well as auto? __ 67p23 discusses destruction of auto variables. Should it also mention register too? Issue #core-208: register as well as auto? __ 67p24 "past an initialized auto [ or register ? ]" Issue #core-209: register as well as auto? Mar 3 16:48 1993 Issues; by Plum+Saks; WG21/N0239; X3J16/93-0032 Page 12 __ 67p25 destruction of auto [or register?] defined in loop is done upon xfer out of loop [redundant??] Issue #core-210: register as well as auto? __ 67p25 destruction of auto [or register?] decl'ed in block is done upon xfer out of block [redundant??] Issue #core-211: register as well as auto? __ 67p25 destruction of initialized auto [or register?] is done upon xfer out of its scope [redundant??] Issue #core-212: register as well as auto? __ 67p41 "An auto [ or register ? ] variable constructed ..." Issue #core-213: prohibit vacuous declarations? __ 7p19b: Should the draft should prohibit vacuous decls like this? enum { }; class { int i; }; class { }; Currently, they don't seem to be prohibited. Issue #core-214: require decl-specifier (except ctor and dtor)? __ 7p13: declaration: decl-specifier-seq-opt init-declarator-list-opt ; Draft seems to allow empty decl-specifier on function decl. Is this really needed for anything besides ctors and dtors? If so, provide a note in rationale. If not, say so explicitly in draft. Issue #core-215: prohibit extern combined with friend ? __ 71p16: No rule prohibits, in a class decl, putting extern onto a friend decl. There were murmurs at Dallas mtg that this is an oversight. Then it should be corrected. Same observation for putting friend onto an extern decl. Issue #core-215: prohibit extern typedef and extern inline ? __ 71p2 It has been suggested that common practice prohibits the combinations extern typedef and extern inline . This isn't said anywhere that we can find. Here is a more general conjecture: "A decl-specifier-seq may contain at most one storage-class-specifier, or one function-specifier, or the friend specifier, or the typedef specifier, but not more than one." Some true statement should be made, unless we are just overlooking what's already said. Issue #core-216: provide definition for template-specifier? __ 71p15 There's no definition for template-specifier in the grammar. The appendix grammar is different: it has a template-declaration as an alternative under declaration. Issue #core-217: re-definition of typedef __ 713p21 says that typedef may be redefined to refer to the type to which it already refers. What about... typedef char C1; typedef char C2; typedef C1 C2; What about ... typedef int A2x5[2][5]; Mar 3 16:48 1993 Issues; by Plum+Saks; WG21/N0239; X3J16/93-0032 Page 13 typedef int A2x5[2][5]; Implementations differ. Does the draft mean exactly what it says, or are there some unspoken exceptions to these rules? Issue #core-218: mapping type specifiers into types [editorial] __ 716 discusses type specifiers. Lists of specifiers are mapped into the specific finite set of types. E.g. unsigned int and int unsigned both map into ``unsigned int''. In most contexts, signed int maps into ``int''. Where allowed, the empty-type-specifier-list maps into ``int''. Abbreviated surface-types like unsigned long map into full types like ``unsigned long int''. The draft could be made clearer. This is a crucial place where the "surface-type vs type" distinction is important. Issue #core-219: mapping cv-qualifiers into types [editorial] __ 716 LA53 The ordering of cv-qualifiers is immaterial; therefore, the conversion from a surface-type involving cv-qualifiers will arrange them in a canonical ordering. (Presumably, "``const'' first, then ``volatile''" is an adequate ordering rule.) In the syntax for type-specifier, use the non-terminal cv-qualifier instead of listing const and volatile . It is hard to talk about the previous canonical ordering without a proper non-terminal. Issue #core-220: type-specifier::typedef-name [resolved] __ 716: the production type-specifier:: class-name is unnecessary. The same sentences can be produced by other rules: type-specifier: simple-type-specifier simple-type-specifier: qualified-class-specifier qualified-class-specifier:: nested-class-specifier nested-class-specifier: class-name [April 92] Alternatively, it has been suggested that the production should be type-specifier: ::typedef-name , to allow a more general behavior for :: . [June 92] The June draft is revised, as indicated: ::typedef-name . Status: resolved. Issue #core-221: type-specifier: cv-qualifier [editorial] __ 716: the productions type-specifier: const volatile should simply be type-specifier: cv-qualifier Mar 3 16:48 1993 Issues; by Plum+Saks; WG21/N0239; X3J16/93-0032 Page 14 Issue #core-222: allow cv-qualifiers in function declaration [editorial?] __ 716p18 and 716p19: the draft says "The words const and volatile may be added to any legal type-specifier in the declaration of an object. Otherwise, at most one type specifier may be given in a declaration." The phrase "of an object" in 716p18 is overspecification; it precludes using "const volatile" in a function declaration. Issue #core-223: is extern X x; an initialized defining instance? __ 716p1_11 says "Unless explicitly declared extern, a const object does not have external linkage and must be initialized." class X { public: const int i; X() : i(0) { } }; extern const X x; // is this initialized? int main() { return x.i; } If you leave off the extern, there's no question that x is initialized. If the extern is there, how can you tell if it's a reference or a definition? Issue #core-224: what access for struct X; class X {...}; ? __ 716p73: if defined, a name declared as a class must be defined as a class or struct. What is the default access control for such a class? E.g., struct X; class X { ... }; Default access is private or public? Issue #core-225: clarify "explicit qualification" __ 72p41 says "enumerators defined in a class ... can be referred to outside member functions of that class only by explicit qualification..." Does this mean that class X { enum T { A, B, C }; static T e; }; X::T e = A; // error A must be qualified? Issue #core-226: extern "C" interaction with static member __ 74p24: Needs clarifying. The words imply that in extern "C" { class c { static int i; }; Mar 3 16:48 1993 Issues; by Plum+Saks; WG21/N0239; X3J16/93-0032 Page 15 }; the extern "C" applies to i . Is the linkage specification required, allowed, or prohibited, when i is later defined, as in extern "C" int c::i = 0; Issue #core-227: extern "C" interaction with static object declaration __ 74p53 says "Functions and objects may be declared static within the { } of a linkage specification." However, there's no statement about extern "C" static int i; Issue #core-228: extern "C" interaction with static function declaration __ 74p53b: functions and objects may be declared static within the { } of a linkage specification. What about in a linkage specification without { } ? E.g., extern "C" static int f(); Explicit rules are needed to account for any difference between the brace version and the braceless version. Implementations differ in their handling of the two versions, but the draft has no guidance. Issue #core-229: how can IOT class be "used"? __ 711p82: Draft needs to be specific about what constitutes "use" of an extern decl of an undefined class. (I.e., "incompletely-defined object type"?) E.g., for class X; extern X a; extern X f(); extern X &g(); can you a) pass a as an argument to a fn of an X parameter? b) pass a as an argument to a fn of an X& parameter? c) pass &a as an argument to a fn of an X* parameter? d) accept a return value from f? d) accept a return value from g? Issue #core-230: restrictions on "declarator-id" [resolved] __ 82p13: The draft says "Except for ..., a declarator-id will be a simple identifier." Should say "must be a simple identifier". Right? 92/12/08 NOTE: This was resolved at Boston meeting. Issue #core-231: declarator algorithm is incorrect [editorial] __ 821 LA541 Pointer declarator: This section in all drafts up to Jun 92 has carried the same incorrect wording. The algorithm given is just plain wrong: multiple "pointer-to" nestings come out reversed. Take a moment to trace what it does with a declaration like int *const *volatile p; ... int *c *v p --> T D1 is int *v p --> "vol ptr to int" ---- ---- --- --- T D1 T D1(D1) --> "const ptr to vol ptr to int" (which is exactly backwards). The correct approach is already embodied in the array-declarator section (824). It would go something like this: In a declaration T D where D has the form Mar 3 16:48 1993 Issues; by Plum+Saks; WG21/N0239; X3J16/93-0032 Page 16 * cv-qualifier-seq-opt D1 and the type of the identifier in the declaration T D1 is ``type-modifier T'', then the type of the identifier of D is ``type-modifier cv-qualifier-seq pointer to T''. [etc. as-is] Issue #core-232: declarator algorithm is incorrect [editorial] __ 822 Reference declarator: This section needs the same rewrite as 821, something like this: In a declaration T D where D has the form & cv-qualifier-seq-opt D1 and the type of the identifier in the declaration T D1 is ``type-modifier T'', then the type of the identifier of D is ``type-modifier cv-qualifier-seq reference to T''. [etc. as-is] Issue #core-233: declarator algorithm is incorrect [editorial] __ 823 Pointer to member declarator: This section needs the same rewrite as 821, something like this: In a declaration T D where D has the form qualified-class-specifier :: * cv-qualifier-seq-opt D1 and the type of the identifier in the declaration T D1 is ``type-modifier T'', then the type of the identifier of D is ``type-modifier cv-qualifier-seq pointer to member of class class-name of type T''. [etc. as-is] Issue #core-234: precise array declarator [editorial] __ 824p1 LA542 Array declarator: This section already has the "type-modifier" gizmo that makes the rules work, but the discussion of "bound" (or should it be "dimension"?) is still too vague. Here's how it might look: In a declaration T D where D has the form D1[constant-expression-opt] and the type of the identifier in the declaration T D1 is ``type-modifier T'', then the type of the identifier of D is an array type. If the constant-expression (5.19) is present, it must be of enumeration or integral type and have a value greater than 0. The constant expression specifies the _bound_ (number of elements) of the array. [index entry for "bound, of array"] If the value of the constant-expression is N, the array has N elements numbered 0 to N-1, and the type of the identifier of D is ``type-modifier array of N T''. If the constant-expression is omitted, the type of the identifier of D is ``type-modifier array of unknown bound of T'', an I.O.T. ("incomplete object type"). Issue #core-235: enums are listed twice [editorial] __ 824p21 Enums are included in fundamental types, so its redundant to list them again. Maybe just put a footnote onto "fundamental type": [FOOTNOTE: The enumeration types are included in the fundamental types.] Issue #core-236: when can array bound be omitted? [editorial] __ 824p33 says "The first constant-expression may also be omitted when the declarator is followed by an initialize-clause." Shouldn't it be "...followed by an initializer." Issue #core-237: type of array [editorial] __ 824p34 The last sentence could be clearer like this: "In this case, Mar 3 16:48 1993 Issues; by Plum+Saks; WG21/N0239; X3J16/93-0032 Page 17 the bound (of value N, say) is calculated from the number of initial elements supplied, and the type of the identifier of D is ``array of N T''. Issue #core-238: discuss array conversion in Expressions (5) [editorial] __ 824p5 LA221 See the discussion at 5p6 above regarding conversions of array lvalues. The first two sentences of 824p5 discuss conversions of arrays in expressions, so they don't belong here under declarators. Replace these sentences with something like this: "Conversions affecting lvalues of array type are described in Expressions (5)." Issue #core-239: array or function parameters [editorial] __ 825p3 currently says "Argument types that differ only in the use of typedef names or unspecified argument array bounds agree exactly." It should say something more like this: "The type of each parameter is determined from its own decl-specifier-seq and declarator. Any typedef names are replaced by their definition. After determining the type of each parameter, any parameter of type ``array of type'' or ``function returning type'' is adjusted to be ``pointer to type'' or ``pointer to function returning type,'' respectively. Issue #core-240: overloading on presence/absence of ellipsis __ 825p32 - presence/absence of ellipsis is part of type Very puzzling. This explicit sentence in the draft implies that a function can be overloaded solely based on presence/absence of ellipsis. But given an invocation of that function which matches the non-ellipsis prototype, doesn't it always match the ellipsis prototype also? Issue #core-241: transformation of parameter types __ 825p33 After producing the list of parameter types, several transformations take place upon the types. Any cv-qualifier modifying a parameter type is deleted; e.g., the type ``const int'' becomes simply ``int''. [The previous sentence may be a substantive change; see 825p33a below.] If the decl-specifier register modifies a parameter type, the specifier is deleted; e.g., ``register pointer to char'' becomes simply ``pointer to char''. So, for a more complex example, the parm-declaration-list (const int i, register j, volatile a[], void f()) produces the type-list ``(int, int, pointer to volatile int, and function of no parameters returning void)''. Issue #core-242: parameter of type ``const T'' ___ 825p33 Re deletion of "const" and "volatile" cv-qualifiers on the type of prototype declarations. This is a C compatibility question. In C, the following is valid: int f(int); int f(const int i) { return i+1; } // valid C, invalid C++? The rules for "compatible type" determine that f and f designate the same function (LA543p6 "For each parameter declared with qualified type, its type for these comparisons is the unqualified version of its declared type"). Whether the "const" cv-qualifier "really is part of the function type" is irrelevant in C; for all the purposes of C the two declarations are "close enough". We have several choices: Mar 3 16:48 1993 Issues; by Plum+Saks; WG21/N0239; X3J16/93-0032 Page 18 1. (Status quo) Endure the slings and arrows of outrageous C incompatibility, keep the cv-qualifiers as part of the function type, and defend the example above. 2. Treat cv-qualifiers on parameters analogous to "register" on parameters; they disappear when forming the type of the function, but are preserved in the type of the parameter as a local variable of the function. 3. Adopt the actual C treatment: The cv-qualifiers are part of the type of the function, but preserve a tiny bit of the C "compatible type" rules, and allow the two f's above to designate the same function, not an erroneous attempt to overload. A decision is needed here. Issue #core-243: default arguments and block scope __ _825p35a says that default arguments are not part of the function type. We interpret this to mean that, even if prototypes add defaults, the actual function referred to is the same function, however... The working paper doesn't really say anything about the behavior of a function with default arguments declared at both file and block scope. Page 142 of the ARM describes a hypothetical implementation in terms of a set of overloaded functions. But the function declarations are (as far as we can tell) block scoped, because these declarations include inline function definitions. There's no way to define these hypothetical "overloaded functions" inside block scope. So there's got to be another implementation model. Whatever it is, we don't think everybody agrees on it yet. How would people feel about saying that the use of default args on a block-scope function declaration produces undefined behavior? (I.e., your implementation can support this if you want to, but a portable program cannot use it.) Issue #core-244: default-arg and pointer-to-function __ 826 The draft is unclear whether ptr-to-fn can be declared with the default-arg syntax, and if so, how that syntax would affect type compatibility. Issue #core-245: define default argument behavior __ 826p6 The definition of default arguments still needs work. The words in the draft do not clearly specify the presumed behavior. Issue #core-246: discuss wchar_t arrays [editorial] __ 842 This section needs the similar treatment for widechar (wchar_t) arrays. Issue #core-247: clarify initialization of reference __ 843p11c Ref to T may be init by object of type ref to T . Clearer words are needed in 843 to describe exactly which initializers require conversion to temporary and which do not. Issue #core-248: initialization of reference to function __ 843p11d Should say "ref to T may be init by function of type T ". These words are not in draft yet, but they are required by 522p1 which unambiguously mandates "reference to function" type. Mar 3 16:48 1993 Issues; by Plum+Saks; WG21/N0239; X3J16/93-0032 Page 19 Issue #core-249: 843p31 duplicates 822p32 [editorial] __ 843p31 is a duplicate of 822p32. Does WG21+X3J16 want to eliminate this redundancy? Issue #core-250: 843p62 duplicates 47p12 [editorial] __ 843p62 seems to duplicate 47p12. Message c++std-core-1822 | Subject: Editorial Notes on the C++ Working Paper (Part 2) | Date: July 1992 | By: Thomas Plum and Daniel Saks Issue #core-251: is template-class-id a class-name ? __ 9p13: This says that class-name: identifier Just about as simple a piece of BNF as I've ever seen. The meaning ought to be pretty unambiguous. BUT: _142p_111 says (in English, not BNF) "Since a template-class-id is a class-name , it can be used wherever a class-name can be used." Now, we very much want this English to be true. Shouldn't 9p13 be revised? Issue #core-252: must IOT be completed in the same scope? __ 91p24 LA523 In C, a struct-or-union of incomplete type must be completed in the same scope as the incomplete-type declaration, or it remains an incomplete type. [We believe the same is intended for incompletely-defined classes in C++, but the document is not yet clear enough to tell.] Issue #core-253: 91p28 is almost-dup of 11.4p3 __ 91p28: "If a class mentioned as a friend ..." This is an almost exact dup of 11.4p3. Either say nothing, or say identically the same. (?) Issue #core-254: storage class and friends __ 92p3: The relationship between storage class and friend declarations is totally unspecified. It is possible that the draft ought to flatly prohibit storage class on friend decls, like this: Neither member nor friend declarations may specify auto, extern , or register . Furthermore, friend declarations may not specify static . On the other hand, it currently appears possible from the draft that we could declare a friend function to be static , and then provide a static (i.e., file-local) function definition. Needs clarifying. Issue #core-255: class type of non-static member must be "defined"? __ 92p51 - non-static members that are class must be of prev decl class. The terminology of 31p1 and 9p23 is not at all clear regarding the distinction between "definition" and "declaration". We believe that 92p51 is really referring to a previously "defined" class. Mar 3 16:48 1993 Issues; by Plum+Saks; WG21/N0239; X3J16/93-0032 Page 20 Issue #core-256: array type of non-static member can't be IOT? __ 92p53: "When an array is used as the type of a nonstatic member all dimensions must be specified." When "incompletely-defined type" is incorporated, this is one of the affected places. In particular, we assume that typedef int incomplete_array[]; class x { incomplete_array j; }; is meant, by these words, to be prohibited. Issue #core-257: which properties exclude unions? __ 92p71: The "higher addresses" property should say "(non-union)" classes. Obviously. But do any of the other properties of classes exclude unions? ... Issue #core-258: how does syntax of member-decl ascribe ``type''? __ 92p9: It looks like a new paragraph, e.g. 92p9, is needed to describe how the syntax of member-declaration ascribes a "type" to each member. This can probably incorporate the "declarator-unfolding" of 82p* by reference. [Any special cases??] Then, after a type ``T'' is ascribed to member mem , it needs to say that the type of mem is something like ``class cl member of type T''. Unless static, in which case simply ``T''. [Right?] Issue #core-259: "is called ..." should include "overloaded op"? __ 93p11: "... is called ... using the class member syntax" SHOULD ADD "or the overloaded operator syntax (13)". Right? Issue #core-260: invoke member of temp? what lifetime? __ 93p5 We've heard it suggested that invoking a member function is equivalent to binding a reference to its object. This implies, e.g., that it's ok to invoke a member function of a temp (cf _122p23) and has implications for the lifetime of a temp used in this way. Does this reflect common understanding? If so, add it here. Issue #core-261: clarify calling volatile member function "similarly"? __ 931p31: We assume that "similarly" means "a volatile member function may be called for volatile and non-volatile objects". Is this correct? Issue #core-262: 931p4 is almost dup of _121p2 __ 931p4 is an almost-exact dup of _121p2. (Regarding ctors and dtors for const and volatile.) Issue #core-263: can a local class have static function members? __ 94p32: It says "a local class cannot have static data members". But in view of the preceding sentence, we don't see how a local class could have static function members either. Is this an oversight, or a deep subtlety? Issue #core-264: redundant semicolon [editorial] __ 94p52 The example shows void process::reschedule() { ... }; but the semicolon is very misleading and doesn't belong here. Issue #core-265: clarify type of non-static member __ 94p6: "The type of a static member does not involve its class name ..." Mar 3 16:48 1993 Issues; by Plum+Saks; WG21/N0239; X3J16/93-0032 Page 21 Fine. But nowhere does the draft say that the type of a _non-static_ member involves its class name either. This needs to be clarified. It looks like a new paragraph, e.g. 92p9, is needed to describe how the syntax of member-declaration ascribes a "type" to each member. [See 92p9 above.] Issue #core-266: unions and access modifiers __ 95p32 - anonymous union may not have private or protected members. This seems to imply that anonymous union may have public members; and that non-anonymous union may have any access modifiers. Is this what everyone understands? Issue #core-267: clarify "no references to bit-fields" __ 96p33: "Nor are there references to bit-fields." Does this actually prohibit anything? A simple attempt to make a reference refer to a bit-field just creates a temporary: union { int bitf:2; } u; int & r = &u.bitf; Or is this a syntactic restriction that prohibits something like union { int (&rbitf):2 } u; Or is it meant to prohibit the use of typedefs to attempt it, such as union { typedef int bitf_t:2; bitf_t &rbitf; } u; The intent needs clarifying. 92/12/17: I think this point is directly at issue in Sam Kendall's proposal to unify the concept of lvalue and reference: an lvalue expression can designate a bitfield object, but the type of that object cannot be adjusted to a reference type. (or something like that) Issue #core-268: clarify restrictions on "uses" in nested class __ 97p15: "Except by using explicit pointers, references, and object names, ..." Does this mean "Except for member functions with parameters that are pointers or references to an enclosing class, ..." What does "and object names" mean? What other accesses are possible? Issue #core-269: clarify restrictions on "uses" in local class __ 98p14: The words, as written, are overly restrictive. Declarations "can use only type names, static variables, extern variables and functions, and enumerators from the enclosing scope". What about integral constants? What about string literals? Should the words say something like "An identifier can be used in declarations ... only if the the identifier is a type name, a static var ... etc". 92/12/17: This issue also applies to 97p15. See issue edit-37#18. Issue #core-270: clarify "member fns of local class must be defined ..." __ 98p22: Says "Member functions of a local class must be defined within their class definition." Does this literally mean "MUST be defined", or does it mean "may not be defined anywhere but within ..."? Issue #core-271: clarify base's non-inheritable members __ _10p1_15 should say "Unless redefined in the derived class, [or unless the members are non-inheritable,] members of a base class can be referred to as if they were members of the derived class." Surely this does not apply to ctors, dtors, or assignment. (?) Mar 3 16:48 1993 Issues; by Plum+Saks; WG21/N0239; X3J16/93-0032 Page 22 If this "clarification" reflects the committee's intent, then it follows from this that access-decls can't apply to the non-inherited members. 92/12/17: There is a serious portability problem lurking in this rather pedantic-sounding issue. Consider a base B with public constructor(s) which is a virtual private base for C, which is in turn a base for D. The constructors of D are obliged to explicitly invoke B's constructors. How does D obtain access? Some implementations appear to tacitly grant the access according to (unpublished?) special rules. Other implementations require the use of access-decls that mention B::B . The question of "how does D obtain access" should be a separate issue. [to be provided]. Issue #core-272: clarify (non-virtual) sub-objects __ _101p32 defines the behavior of _101p31 only by example. There should be a general statement of the behavior, something like: For an object O of class D, each distinct occurrence of a non-virtual base class B in the class lattice of D corresponds one-to-one with a distinct B sub-object within O. Issue #core-273: clarify (virtual) sub-objects __ _101p52 defines the behavior of _101p51 only by example. There should be a general statement of the behavior, something like: For an object O of class D, all virtual occurrences of base class B in the class lattice of D corresponds to a single B sub-object within O, and every other occurrence of a (non-virtual) base class B in the class lattice of D corresponds one-to-one with a distinct B sub-object within O. Issue #core-274: clarify "reaching the same object" __ _1011p?: Page 203 of the ARM contains a comment about "reaching the same object". There is no corresponding statement in the Working Paper. This comment should be added to the Working Paper. Issue #core-275: "qualified-id or id-expression" is redundant __ _1011p12: qualified-id is an id-expression, so qualified-id is unnecessary. Issue #core-276: define and use "family" of same-name overloaded functions __ _1011p12: Uniqueness is a property of a "family" of overloaded functions. Need to define "family". [Or "family group"?] Issue #core-277: add example to clarify "ambiguity before overloading ..."? __ _1011p15 says ambiguity resolution occurs before overloading resolution which occurs before access control. Does this Mar 3 16:48 1993 Issues; by Plum+Saks; WG21/N0239; X3J16/93-0032 Page 23 have any impact on the language other than to specify the choice of error message when more than one of these violations occur? Issue #core-278: clarify behavior of nested type __ _1011p18 says "A single function, object, type or enumerator may be reached...", yet_1011p1_11 says "a hidden function, object or enumerator may be reached..." What about a hidden type? Are nested types members of classes? Can they be inherited? The draft is unclear. Issue #core-279: clarify finding hidden type __ _1011p1_11: when using virtual base classes, a hidden function object or enumerator may be reached along a path through the DAG that doesn't pass through the hiding function object or enumerator. What about a hidden type? Issue #core-280: clarify "access rules are considered" __ _104p22: What does it mean to say the access rules are "considered"? Issue #core-281: clarify "type is considered" __ _104p23: Similar question... What does it mean to say the type is "considered"? Issue #core-282: [withdrawn. looks erroneous to me.] __ _104p42: "ptr->operator->()" should be "ptr.operator->()" because ptr is an object of class Y, not a pointer to an object of class Y. Issue #core-283: clarify nested types and access control __ _11 (Ch 11 in general): The relationship between nested types and access control is unclear. If any sentence said that the name of a nested type is a "member", then there are many explicit sentences that would govern their accessibility. (The draft is very clear, of course, that friend names are _not_ members, and _none_ of the member access rules apply to them.) Syntactically, sometimes a nested type name is declared in a member-declarator as in typedef int T; but all other nested type names are declared in a decl-specifier-seq . It would seem extremely counter-intuitive to say that access control applies to typedef names declared in a member-declarator while denying access control to types created by other syntax. Presumably, the phrase "nested type" is the intended category for descriptions of the specified behavior. Or are all "nested types" covered by the category of "members"? Issue #core-284: base access rules don't apply to non-inherited members __ _112 After much discussion, we believe that the intent is as follows: "The members whose accessibility is described in this section are only those members which are inherited from the base class; the non-inherited members such as constructors, destructors, and assignment operators are not subject to these accessibility rules." Issue #core-285: _112p14 is almost dup of _11p11? __ _112p14 says Mar 3 16:48 1993 Issues; by Plum+Saks; WG21/N0239; X3J16/93-0032 Page 24 Private members of a base class remain inaccessible even to derived classes unless friend declarations within the base class declaration are used to grant access explicitly. This sentence appears to re-state exactly the same requirement as _11p11, which says A member of a class can be private; that it, its name can be used only by member functions and friends of the class in which it is declared. If identical in intent, say what's meant, in only one place. If not identical, be clearer about the subtle implications. Issue #core-286: clarify what access control applies to __ _114p11 friend function can use private and protected member names Global note: _11p02 says that access control applies to 1. fn members, 2. data members, 3. member constants, 4. nested types. If the draft is to be interpreted that "member", in chapter 11, refers to all 4 of these, it should say so explicitly. Implementations differ. Issue #core-287: where can friend "use" member constants and types? __ _114p11: Still being debated: just what does "use" mean? a. function body of friend b. argument types of friend Some discussions have also mentioned c. return type of friend . This is not yet clear one way or the other. Issue #core-288: friend functions defined in class, and name lookup __ _114p52 - friend def'd in class is in lexical scope of class The "name lookup" question has been clarified somewhat with the new section 921 in Jun 92 draft, but it's not yet clear whether this clarifies the status of friend functions defined inside a class. Issue #core-289: clarify use of protected "member" re constants and types __ _115p12: protected non-static can be used in derived class ... only through ptr-to, ref-to, obj of derived or derived-from-derived We assume this means a "protected non-static data or fn member". Should clarify explicitly. Issue #core-290: define "constructor" and its "name" __ _121p11 says "A member function with the same name as its class is called a constructor...." But it's been mentioned that this is incorrect. Is a constructor a member function? What is its name? Stay tuned ... Issue #core-291: why must X x=1; be different from X x(1); ? __ _122: What purpose is served in allowing the semantics of X x = 1; to be different from X x(1); ? >From the standpoint of the application programmer, the fuzzy semantics are no help. Granted, that the "make a temp then copy-ctor" semantics still need to be described for function args and return values. But why require this for initialization of named objects? Issue #core-292: is temp created in scope of caller or callee? Mar 3 16:48 1993 Issues; by Plum+Saks; WG21/N0239; X3J16/93-0032 Page 25 __ _122p25: if ref bound to temp, temp cannot be destroyed until ref is Is temp created in scope of caller or callee? Should be clarified. Issue #core-293: clarify y.~Y() __ _124p22 The notation y.~Y() is explicitly approved of by the example at bottom of ARM page 279), but nothing in the draft gives this explicit approval. Implementations differ. Committee should approve it or disapprove it. Issue #core-294: prohibit pd->b::~b() ? __ _124p8: It's been suggested that the draft should say that it's illegal to try to invoke the destructor of a base class using a pointer to a derived class. E.g, class b { ... ~b() { ...} }; class d : public b { ... }; d *pd = ...; ... pd->b::~b(); // should be an error? Issue #core-295: clarify "fully qualified" __ _124p81: what does "fully" qualified mean? see comment on _124p22 Issue #core-296: clarify elimination of copy ctor __ _1261p1 says "Typically, that call of a copy constructor can be eliminated." This does not really prescribe requirements for the implementer or the user. Under what circumstances can the call be eliminated? Issue #core-297: clarify conversions and initialization __ _1262 contains no discussion about what conversions, if any, are performed in initializing bases and members. In particular, it is absolutely unclear what rules apply to initialization of pointer-to-char and array-of-char via string literals (or wide string literals). The kind of discussion that needs to be present would say something like "Let the type of identifier be Ti . If Ti has a constructor, then initialization of identifier is accomplished by invoking the constructor that best matches expression-list (13.2); if there is no unique best match, or the best match is not accessible, the initialization is invalid. If Ti has no constructor, expression-list must be (only one) expression , and initialization is accomplished by assigning expression to identifier [?? or should it be 'by explicit initialization of identifier with expression ??'] ." This attempt at wording may very well be wrong. It's just an example of what isn't said. Issue #core-298: clarify optional expression-list in mem-initializer __ _1262p17 (syntax rule) says expression-list is optional. Is there an implied rule that says that omission of expression-list is allowed only when the base or member being initialized has a default constructor? (If so, this rule needs to be stated explicitly.) Or, alternatively, is there an implied requirement that any base or member (even a basic type) can be initialized with an empty expression-list? (If so, the semantics need to be defined.) Issue #core-299: generated copy ctor, and non-class members __ _128p2 says that the generated copy ctor will take a single arg of Mar 3 16:48 1993 Issues; by Plum+Saks; WG21/N0239; X3J16/93-0032 Page 26 type const X& if "all bases and members have copy constructors accepting const arguments". It is not clear whether non-class members are presumed to have such. If they are not so presumed, how could this recursive definition get started. If they are so presumed, it should be said explicitly. Issue #core-300: coalesce all rules re default assignment __ _128p5 Paragraph 8 below gives one instance in which default asst will not be generated ("any x::operator=() that takes an argument of class X"), and one instance in which default copy ctor will not be generated. But this paragraph, paragraph 5, lists in detail all the OTHER cases in which the default asst and default ctor won't be generated. So the suggestion is to bring the items from p8 up into the list in p5. (Martin, in core-893, suggested this first, we think.) Issue #core-301: is "definedness" of default asst and ctor just optimization? __ _128p6 This paragraph discusses the cases in which the "default" (or "compiler-defined") asst and ctor will be defined, as opposed to just being declared. Is this just an optimization advice to the implementer, or is there a testable behavior that can be observed by a portable program? Issue #core-302: is _128p71 a dup of _128p33 __ _128p71 says "and the assignment operator for a class X will be defined to return a reference of type X& referring to the object assigned to". Isn't this completely redundant with _128p33 which says "The default assignment operator will return a reference to the object for which it is invoked."? Or is there a subtle difference that should be made clearer? Issue #core-303: clarify X::operator=(X&) __ _128p91 says "Assignment ... is defined in terms of X::operator=(const X&)." But _128p3 explains that asst is EITHER X::operator=(const X&) OR X::operator=(X&) . Is p91 a bit loose, or is it saying something very precise despite p3? Issue #core-304: clarify "copying ... does not change the STRUCTURE" __ _128p_101 says "Copying one object ... does not change the STRUCTURE of either object." The term "structure" does not have a relevant definition in the draft Standard. It is only the example that conveys any content. We assume that "structure" means "the specific set of virtual functions which is associated with the object itself". Issue #core-305: [withdrawn. either wrong, or obsolete.] __ _128p_102 The example invokes a.f() inside a function, but neither s::f nor ss::f are accessible. Needs a public: to work right. Issue #core-306: does generated assignment require lvalue left-hand opnd? __ _128p?? It is nowhere mentioned whether the generated assignment requires an lvalue left-hand-side operand. One might assume it doesn't, except that some popular compilers assume that it does. Issue #core-307: allow "ptr-to-ptr" conversion-type-id? __ _1232p13: conversion-type-id: type-specifier-seq ptr-operator-opt This means that, for example, it's illegal to have a conversion operator char** Mar 3 16:48 1993 Issues; by Plum+Saks; WG21/N0239; X3J16/93-0032 Page 27 It's been suggested that this was a needless restriction. Or was there a deep subtle reason? Issue #core-308: clarify overloading that differs only in ellipsis __ _132: The commentary in the ARM indicates that the invocation of f(1) is ambiguous when overloading differs only in presence/absence of ellipsis: int f(int); int f(int ...); It would seem clearer, and less dangerous, to disallow the overloading in the first place. I.e., make a rule that, if two overloaded functions differ only in presence/absence of ellipsis, that's an error. ALTERNATIVE: The (non-commentary) rules imply that this is legal, not ambiguous. We could decide that it's a non-ambiguous invocation of f(int), despite what the commentary says. Issue #core-309: clarify treatment of arg and parm of const member function __ _132p41: wouldn't it be more accurate to say that a const member function of class X treats the formal parm 'this' as 'const X * const', and it converts the extra actual arg to this type? (And ditto for volatile members.) There's no way to observe the attributes of an actual arg other than by testing the formal parm when you gain control inside the called fct. The actual arg must simply be such that it can be converted to the type of the formal parm. Issue #core-310: clarify treatment of arg and parm of const member function __ _132p42: wouldn't it be more accurate to say that a const member function of class X treats the formal parm 'this' as 'const X * const', and it converts the extra actual arg to this type? (And ditto for volatile members.) There's no way to observe the attributes of an actual arg other than by testing the formal parm when you gain control inside the called fct. The actual arg must simply be such that it can be converted to the type of the formal parm. 92/12/17: This issue is the same issue as edit-37#59, just applied to a different sentence of the WP. Issue #core-311: clarify treatment of arg and parm of const member function __ _132p43: wouldn't it be more accurate to say that a const member function of class X treats the formal parm 'this' as 'const X * const', and it converts the extra actual arg to this type? (And ditto for volatile members.) There's no way to observe the attributes of an actual arg other than by testing the formal parm when you gain control inside the called fct. The actual arg must simply be such that it can be converted to the type of the formal parm. 92/12/17: This issue is the same issue as edit-37#59, just applied to a different sentence of the WP. Issue #core-312: clarify "1st operand of ->* ... same as ... ->" __ _132p43: What exactly does it mean to say '1st operand of ->* and .* is treated the ``same'' as 1st operand of -> and ., respectively'? 92/12/17: E.g., "The rules of this paragraph"? Or something more than that? Issue #core-313: clarify "shorter sequence" rules __ _132p61b: Suppose there's a conversion from A to B and from B to C, and functions Mar 3 16:48 1993 Issues; by Plum+Saks; WG21/N0239; X3J16/93-0032 Page 28 f(B) and f(C) are under consideration, then the call f(a) (for 'a' of type A) could convert A->B->C or just A->B. _132p61 clearly states that the latter, shorter sequence wins. Does it say anything about choosing between sequences such as A->B->C and A->C? We think not. Issue #core-314: more trivial conversions? __ _132p81: What about from: to: T& const T& T& volatile T& const T& T volatile T& T T* T[] Aren't these also trivial conversions? Issue #core-315: mis-wording in "accept exactly the same set of values"? __ _132p81 says that const T& accepts the same values as T, const T, and volatile T. But, T& and volatile T& do NOT accept the same values. const T& accepts anything that T& and volatile T& accept, but not vice versa. Issue #core-316: clarify "sequences of trivial conversion" __ _132p82: sequences of trivial conversions that differ only in order are indistinguishable. Do two such sequences exist? If so, an example might clarify the topic for the average reader. If not, change this. Issue #core-317: clarify status of "A& -> const A&" conversion __ _132p91 Given types A and B with user-defined conversion from A to B and the declarations const A &r; f(B); f(A &); then what does f(r) call? Most translators prefer f(A &), and issue an error or warning for binding a non-const ref to a const ref. On what basis do they do this? Converting A&->const A& is not a standard conversion (47p) nor a trivial conversion (_132p8). It must be a holdover from early C++ translators that bound non-const refs to temps. 132p9 seems to hint at the rules, but they aren't very explicit. Issue #core-318: [withdrawn xxx] __ _13p1 says you can overload f(int) and f(int &), but doesn't say you can't overload void f(const int); void f(const int &); Allowing this overloading is questionable at best. But, inasmuch as it appears to be legal, then int &r; f(r); should call f(const int) because the trivial conversion sequence Mar 3 16:48 1993 Issues; by Plum+Saks; WG21/N0239; X3J16/93-0032 Page 29 int &->int->const int is better than int &-const int &, as stated in matching rule [1]. It this the intent? Issue #core-319: clarify "selection mechanism" __ _132p_116 says "class hierarchy acts similarly as selection mechanism for ptr to member conversions". This is a little on the vague side. Issue #core-320: clarify "standard conversions that might be involved" __ _132p_132 says "except when a conversion sequence is a subsequence of another, if user-defined conversion are needed for an argument, no account is taken of any standard conversions that might be involved." What's this "might be involved"? We take this to really mean "except ..., if user-defined conversion are needed for an argument, any standard conversions also used in converting that argument do not affect which is the better match." Issue #core-321: ok overload target "return type of user-defined operator"? __ _133p12 The last item reads "a function return type". Should this be "the return type of a function or a user-defined operator"? Issue #core-322: do overload rules apply to ptr-to-member-function? __ _133p* Is "pointer to overloaded member function" resolved similarly to "address of overloaded function"? Totally unspecified. Issue #core-323: can overloaded new/delete have default args? __ _134p51 Does this mean that overloaded operator new and/or operator delete are (unlike the other operators) allowed to have default arguments? Issue #core-324: "rules for operator=()" should be "rules for operator="? __ _134p64 says "Except for operator=() , operator functions are inherited; see 12.8 for the rules for operator=()." Almost certainly the empty parens () are editorially misleading, and not being used as the precise syntax which means "no parameters". Just say "operator=". Issue #core-325: clarify matching rules for unary ops __ _1341p13 We believe that what's meant is something like this: In each expression, each occurrence of a prefix unary operator @ applied to an expression x of class type X causes two separate searches for overloaded functions, as follows. The expression is interpreted as x.operator@() , and the scope rules for member functions determine one unique function, or a "family group" of overloaded functions all in the same class scope, or no matching function. The expression is also interpreted as ::operator@(x) , and the scope rules for non-member functions determine one unique function, or a "family group" of overloaded functions all in the same scope (either a block scope or the file scope), or no matching function. If no matching function is found, the expression is interpreted according to the requirements of built-in operators. Otherwise, among the union of the two sets of matching functions, the argument matching rules (13.2) determine which interpretation is used. Issue #core-326: clarify matching rules for binary ops __ _1342p13 (similar to 1341p13) [issue edit-37#75] Mar 3 16:48 1993 Issues; by Plum+Saks; WG21/N0239; X3J16/93-0032 Page 30 Issue #core-327: assignment is "operator=" not "operator=()"? __ _1343p11 Change "operator=()" to "operator=". [see issue edit-37#74.] Issue #core-328: [closed issue. corrected already in Jun 92 draft] __ _1346p13 The ARM lists these possibilities for what op-> returns: (a) pointer to a class; (b) object of a class for which op-> is defined; (c) reference to a class for which op-> is defined. Example: struct O { int i; } o; struct A { O* op->() {ret &o;} } a; // so a->i invokes (a.op->)() , producing (&o) // so a->i becomes (&o)->i struct B { A op->() {ret a;} } b; // so b->i invokes (b.op->)() , producing (copy of a) // (copy of a)->i invokes A::op->() , producing (&o) // so b->i becomes (&o).i The 23 Sep 91 draft changed to this: (1) pointer to a class containing a member m; (2) pointer to a class that defines op-> . All compilers I have (including a 2.1 and a 3.0) implement the ARM, not the 23 Sep draft. More troublesome is that (2) implies that the second instance of overloading can be triggered by a ``pointer-to-class'' left operand, something that, to my knowledge, has never been introduced anywhere else. Example of how this would have to work: struct O { int i; } o; struct A { O* op->() {ret &o;} } a; // so a->i invokes (a.op->)() , producing (&o) // so a->i becomes (&o)->i struct B { A* op->() {ret &a;} } b; // so b->i invokes (b.op->)() , producing (&a) // (&a)->i is supposed to somehow invoke A::op->() !!! ??? 92/05/09: Comments from Shopiro, Bjarne, et al support changing back to ARM behavior 92/06/30: Jun 92 draft is basically back to ARM, with minor revision Issue #core-329: clarify static member function op++ __ _1347p12 The behavior of a static member function op++ is not specified. It could be (a) invalid, like op() , op[] , and op-> ; or (b) defined similar to a non-member function. [ issues edit-37#80 through edit-37#114 all concern chapters 14 and 15, so were sent to Bjarne for processing as issues for the Extensions subgroup.] Issue #core-330: restore __STDC__ to old wording? __ _168p1: The old draft used to say this: "Whether __STDC__ is defined and, if so, what its value is are implementation dependent." The C Compatibility group is of two opinions here. Some favor the Mar 3 16:48 1993 Issues; by Plum+Saks; WG21/N0239; X3J16/93-0032 Page 31 current Feb 3, 1992 draft, which now says __STDC__ is 1 (like C). Others like the old words, and as a procedural note, it's not clear how many people noticed the change. It probably deserves a vote. The name __cplusplus is defined when compiling a C++ program. Issue #core-331: restore __cplusplus to old wording? __ _168p1: The old draft used to say "The name __cplusplus is defined when compiling a C++ program." We assume that this omission was an oversight. (?)