Topic: [Defect Report] When are default arguments parsed?


Author: Nathan Sidwell <nathan@acm.org>
Date: Tue, 27 Nov 2001 17:46:53 GMT
Raw View
Hi,
The standard is not precise enough about when the default arguments of
member functions are parsed.  This leads to confusion over whether
certain
constructs are legal or not, and the validity of certain compiler
implementation algorithms.

[dcl.fct.default][8.3.6]/5 says "names in the expression are bound, and
the semantic constraints are checked, at the point where the default
argument expression appears"

However, further on at paragraph 9 in the same section there is an
example,
where the salient parts are
        int b;
        class X {
                int mem2 (int i = b); // OK use X::b
                static int b;
        };
which appears to contradict the former constraint. At the point the
default
argument expression appears in the definition of X, X::b has not been
declared, so one would expect ::b to be bound.  This of course appears
to
violate [basic.scope.class][3.3.6]/1(2) "A name N used in a class S
shall
refer to the same declaration in its context and when reevaluated in the
complete scope of S. No diagnostic is required."

Furthermore [basic.scope.class][3.3.6]/1(1) gives the scope of names
declared
in class to "consist not only of the declarative region following
the name's declarator, but also of .. default arguments ...". Thus
implying
that X::b is in scope in the default argument of X::mem2 previously.

That previous paragraph hints at an implementation technique of saving
the
token stream of a default argument expression and parsing it at the end
of
the class definition (much like the bodies of functions defined in the
class).  This is a technique employed by GCC and, from its behaviour, in
the EDG front end.  The standard leaves two things unspecified.
Firstly,
is a default argument expression permitted to call a static member
function
declared later in the class in such a way as to require evaluation of
that
function's default arguments? I.e. is the following well formed?
        class A {
                static int Foo (int i = Baz ());
                static int Baz (int i = Bar ());
                static int Bar (int i = 5);
        };

If that is well formed, at what point does the non-sensicalness of
        class B {
                static int Foo (int i = Baz ());
                static int Baz (int i = Foo());
        };
become detected? Is it when B is complete? Is it when B::Foo or B::Baz
is
called in such a way to require default argument expansion? Or is no
diagnostic required?

The other problem is with collecting the tokens that form the default
argument expression.  Default arguments which contain template-ids with
more than one parameter present a difficulty in determining when the
default argument finishes.  Consider,
        template <int A, typename B> struct T { static int i;};
        class C {
                int Foo (int i = T<1, int>::i);
        };
The default argument contains a non-parenthesized comma.  Is it required
that this comma is seen as part of the default argument expression and
not
the beginning of another of argument declaration?  To accept this as
part of the default argument would require name lookup of T (to
determine
that the '<' was part of a template argument list and not a less-than
operator) before C is complete.  Furthermore, the more pathelogical
        class D {
                int Foo (int i = T<1, int>::i);
                template T<int A, typename B> struct T {static int i;};
        };
would be very hard to accept. Even though T is declared after Foo, T is
in scope within Foo's default argument expression.

Suggested resolution:
Append the following text to [dcl.fct.default] paragraph 8.

 The default argument expression of a member function declared in
 the class definition consists of the sequence of tokens up until
 the next non-parenthesized, non-bracketed comma or close
 parenthesis.  Furthermore such default argument expressions shall
 not require evaluation of a default argument of a function
 declared later in the class.

This would make the above A, B, C & D ill formed and is in line with the
existing compiler practice that I am aware of.

nathan

--
Dr Nathan Sidwell   ::   http://www.codesourcery.com   ::   CodeSourcery
LLC
         'But that's a lie.' - 'Yes it is. What's your point?'
nathan@codesourcery.com : http://www.cs.bris.ac.uk/~nathan/ :
nathan@acm.org

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]