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."