ISO/ IEC JTC1/SC22/WG21 N0805

 
Accredited Standards Committee X3       Doc No: X3J16/95-0205   WG21/N0805
Information Processing Systems          Date:   November 3, 1995
Operating under the procedures of       Project: Programming Language C++
American National Standards Institute   Ref Doc:
                                        Reply to: Josee Lajoie
                                                  (josee@vnet.ibm.com)
 
When is a function/object used?
===============================
 
556a - What does "An object/function is used..." mean?
 
  3.2[basic.def.odr] paragraphs 2 and 3 attempt to answer this
  question.  I believe the text in these paragraphs is incomplete and
  should be replaced with the following:
 
  Proposed Resolution:
  Paragraph 2 (on functions):
   "A function is used if it is called, its address is taken other
    than within the operand of a sizeof operator, it is used to form a
    pointer to member, or it is a virtual member function that is not
    pure (10.4)."
 
  Paragraph 3 (on objects):
   "An object is used if its value is used or modified or if its
    address is taken other than within the operand of a sizeof
    operator, or if it is used to form a pointer to member."
 
427a - When is a diagnostic required when a function/variable with
       static storage duration is used but not defined?
 
  When is a diagnostic required if no definition is provided for a
  function or for variable with static storage duration?
 
    int main() {
            extern int x;
            extern int f();
            return 0 ? x+f() : 0;
    }
 
  Must a disgnostic be issued if x and f are never defined?
 
  The current WP contains this sentence:
  3.2 [basic.def.odr] paragraph 2:
    "If a non-virtual function is not defined, a diagnostic is required
     only if an attempt is actually made to call that function."
  This seems to be hinting that, for cases such as the one above, a
  diagnostic is not required.
 
  [Jerry Schwarz, core-6173:]
    I think we should be talking about undefined behaviors, not
    required diagnostics.  That is, if a program references (calls it or
    takes its address) an undefined non-virtual function then the
    program has undefined behavior.
 
  [Fergus Henderson, core-6175, on Jerry's proposal:]
    I think that would be a step backwards.  If a variable or function
    is used but not defined, all existing implementations will report a
    diagnostic.  What is to be gained by allowing implementations to do
    something else (e.g. delete all the users files, etc.) instead?
 
  [Mike Ball, core-6183:]
    Then you had better not put the function definition in a shared
    library, since this isn't loaded until runtime.  Sometimes linkers
    will detect this at link time and sometimes they won't.
 
  [Sean Corfield, core-6182:]
    I'd like it worded so that an implementation can still issue a
    diagnostic here (example above) AND REFUSE TO EXECUTE THE PROGRAM.
    If 'x' and 'f' were not mentioned in the program (except in their
    declarations) I would be quite happy that no definition is required.
    But unless an implementation can refuse to execute the program, you
    are REQUIRING implementations to make the optimisation and that is
    definitely a Bad Thing(tm), IMO.  It seems the only way to allow
    that is to make the program ill-formed (under the ODR) but say no
    diagnostic is required.
 
  [Fergus Henderson, core-6174:]
    ObjectCenter reports a diagnostic only if an attempt is actually
    made to use the function or variable; in other words, link errors
    are not reported until runtime.  In an interpreted environment, this
    is quite desireable.
 
  It seems that we have two choices:
    Either the program is ill-formed or it is undefined.
    I believe that Jerry and Mike's objections against making the
    program ill-formed and preferring to leave the behavior as undefined
    are valid ones, especially in the presence of dynamic libraries.
 
  Proposed resolution:
    In such cases, the behavior of the program is undefined.
 
    Add to paragraph 2 (after the changes listed in issue 556a):
      "If a function is used but not defined (3.1) in a program, the
       program has undefined behavior."
 
    Add to paragraph 3 (after the changes listed in issue 556a):
      "If an object with static storage duration is used but not
       defined (3.1) in a program, that program has undefined behavior."
 
556b - When is a special member function is used?
 
  Sometimes, special member functions are used implicitly by the
  implementation.  I believe scattered information in the WP already
  covers this.  Is the list complete?  Should this list be included in
  subclause 3.2?
 
    Default constructors:
    12.1 paragraph 7:
      "Default constructors are called implicitly to create class
       objects of static or automatic storage duration (3.7.1, 3.7.2)
       defined without an initializer (8.5), are called to create class
       objects of dynamic storage duration (3.7.3) created by a
       new-expression in which the new-initializer is omitted (5.3.4),
       or are called when the explicit type conversion syntax (5.2.3) is
       used."
 
    Copy constructors:
      Are used for copy initialization and direct initialization
      (see 8.5), i.e.
      for initialization in argument passing, function return, throwing
      an exception (15.1), handling an exception (15.3), brace-enclosed
      initializer-list, new expression (5.3.4).
 
    Destructors:
    12.4 paragraph 9:
      "Destructors are invoked implicitly (1) for a constructed object
       with static storage duration (3.7.1) at program termination
       (3.6.3), (2) for a constructed object with automatic storage
       duration (3.7.2) when the block in which the object is created
       exits (6.7), (3) for a constructed temporary object when the
       lifetime of the temporary object ends (12.2), (4) for a
       constructed object allocated by a new-expression (5.3.4), through
       use of a delete-expression (5.3.5), (5) in several situations due
       to the handling of exceptions (15.3)."
 
    Assignment operators:
      Are used when an object of class type is assigned a value of its
      class type or a value of a class type derived from its class type
      (see 12.8).
 
427b - When is it an error if a special member function is not defined?
       What about special member functions that are implicitly-defined?
 
  The standard should indicate that if a user-declared special member
  function is used (either explicitly or implicitly), a definition for
  the special member function must appear in the program otherwise the
  program has undefined behavior.
 
  Implicitly-declared special member functions are implicitly defined
  when they are used (see 556b).
 
  Neal Gafter asks the following questions:
  Question 1:
    "The expression
       new A[20]
     generates code to call the destructor A::~A() when the constructor
     throws an exception.  Does this mean the destructor must be defined
     in order to new an array?"
 
    The WP already requires that the deallocation function be
    accessible and not ambiguous when the new expression is encountered.
    5.3.4[expr.new], paragraph 23:
      "The deallocation function to be used to free the memory must be
       accessible and not ambiguous."
 
    I believe other necessary requirements on the destructor and the
    deallocation function are missing from this paragraph:
    1) the destructor must be accessible.
    2) if the destructor is user-declared, if the program does not
       contain a definition of the destructor, the program has
       undefined behavior.
    3) if the destructor is implicitly-declared, the destructor is
       implicitly-defined at the point of the new expression.
    4) If the program does not contain a definition of the deallocation
       function used to free the memory, the program is undefined.
 
  Proposed Resolution:
    Augment 5.3.4[expr.new], paragraph 15 to say:
      "If a new expression creates an object of class type (or an array
       thereof), the constructor and destructor must be accessible and,
       the allocation function and deallocation function must be
       accessible and unambiguous for the new expression to be
       well-formed.  User-declared constructors, user-declared
       destructors, allocation functions and deallocation functions must
       be defined in the program, otherwise the program has undefined
       behavior.  Implicitly-declared constructors and
       implicitly-declared destructors are implicitly-defined (12) when
       the new expression is encountered."
 
  Question 2:
    "extern int i;
     struct A {
         ~A(); // not defined in the program
     };
     void f() throw (A*) { // assuming something in the program
         A *a = new A;     // calls f ...
         if (i)
             throw a;
     }
 
     Is the program above always ill-formed (because ~A is not
     defined) or is it only ill-formed if f throws an exception?"
 
    The WP already requires that the constructor and destructor be
    accessible when an exception is thrown:
    15.1[except.throw] paragraph 4:
      "When the thrown object is a class object, and the copy
       constructor used to initialize the temporary copy is not
       accessible, the program is ill-formed (even when the temporary
       object could otherwise be eliminated).  Similarly, if the
       destructor for that object is required but not accessible, the
       program is ill-formed (even when the temporary object could
       otherwise be eliminated)."
 
    I believe other necessary requirements on the constructor and
    destructor are missing from this paragraph:
    1) if the constructor or destructor is user-declared, if the
       program does not contain a definition of this function, the
       program has undefined behavior.
    2) if the constructor or destructor is implicitly-declared, this
       function is implicitly-defined at the point of the throw
       expression.
 
  Proposed Resolution:
    Augment 15.2[except.throw], paragraph 4 to say:
      "If the program does not define a user-declared constructor or
       destructor for a class type and an object of that class type is
       thrown by the program, the program has undefined behavior.
       Implicitly-declared constructors and implicitly-declared
       destructors are implicitly-defined (12) when an object of their
       class type is thrown."