Compile the test program below using this command line:
g++ test.cpp
The code below fails to compile, and gives the following error message:
-bash-3.00$ g++ test.cpp
test.cpp: In member function `void Test::cell_test()':
test.cpp:36: error: the default argument for parameter 1 of `void
Test::Cell_base<Type>::set(Type, bool) [with Type = const char*]' has not yet
been parsed
class Test
{
protected:
template< typename Type > class Cell_base
{
protected:
bool m_relevance;
Type m_field;
public:
Cell_base (void) // the
constructor
: m_relevance( false ),
m_field( Type() )
{ }
// the setter
void set (Type value, bool relevance = true)
{
m_relevance = relevance;
m_field = value;
}
};
class Cell : public Cell_base< const char * >
{
};
public:
//--------------------------------------------------
// Test out the cell classes
//--------------------------------------------------
void cell_test (void)
{
Cell c;
c.set( " To be or not to be \n\n" );
}
};
//------------------------------
// Main - program entry
//------------------------------
int main (int argc, char **argv)
{
Test t;
t.cell_test();
return 0;
}
This is invalid code and the error is correct. The default argument has not been parsed at the point you
called it.
ICC and Comeau gives a slightly different error message which I think is misleading:
"ComeauTest.c", line 35: error: too few arguments in function call
c.set( " To be or not to be \n\n" );
Comment 2Wolfgang Bangerth
2005-06-03 21:51:43 UTC
Here's the same testcase again, but shorter:
-------------------------------
struct O {
template<typename T> struct B {
void set (T, bool=true);
};
struct D : public B<int> {};
};
void x ()
{
O::D d;
d.set(1);
}
-------------------------------
g/x> /home/bangerth/bin/gcc-3.4.4-pre/bin/c++ -c x.cc
x.cc: In function `void x()':
x.cc:12: error: the default argument for parameter 1 of `void O::B<T>::set(T,
bool) [with T = int]' has not yet been parsed
Even if the error is justified, I must admit that I still don't understand
what exactly is going on: everything has been parsed by the time we call
d.set!? What exactly is going on? We should be giving a better explanation,
and in addition someone might want to give me a better explanation as well.
As a different problem: in the message, the argument should be counted from
one, not zero -- I know C++ programmers like to count starting at zero,
but the second argument will usually still be referred as 'argument 2', not 1.
W.
The error comes from:
tree
convert_default_arg (tree type, tree arg, tree fn, int parmnum)
{
/* If the ARG is an unparsed default argument expression, the
conversion cannot be performed. */
if (TREE_CODE (arg) == DEFAULT_ARG)
{
error ("the default argument for parameter %d of %qD has "
"not yet been parsed",
parmnum + 1, fn);
return error_mark_node;
}
Comment 4Wolfgang Bangerth
2005-06-03 22:27:19 UTC
In private mail, I got another testcase that is even weirder:
---------------------------
struct O {
template<typename T> struct B {
void set (T, bool=true);
};
struct D : public B<int> {};
};
void x ()
{
O::B<int> d;
d.set(1);
}
----------------------------
Note that now we allocate an object of type O::B<int>, and get the same
error as before. The type O::D isn't used anywhere; however, if we comment
out the line in which it is declared, the test suddenly starts to compile.
What does confuse me, to be honest, is that icc shows the same behavior...
Nathan, Giovanni?
W.
This code is still invalid, B<int> is instantiated while in the class which means that the default
argument is not going to be parsed at all. ICC and Comeau give the same error. Now the off by one
error is easy to fix, I actually fixed it before copying where the error output was.
Comment 6Wolfgang Bangerth
2005-06-04 04:37:34 UTC
I'm sorry, but I have no idea what you mean by that. If you want to say
that O::B<int> is instantiated by O::D, which is still inside O, yes, of
course that's the case. And I'm happy if the default arguments aren't
parsed at that time. But the actual use of O::B<int> happens long after that.
I just haven't the slightest idea where to look this up in the standard...
W.
I can't find anything in the standard which says that this should be an error,
regardless of what Comeau does. This looks like a genuine bug in the parser,
see parser.c:cp_parser_class_specifier: the parsing of the body of the in-
classe defined functions and default arguments is delayed until the whole class
definition is parsed (this allows, eg., the body of in-class member functions
to refer to other member functions which appear later within the struct
definition).
There is some code which also delays inner functions until the outer function
is finished:
/* If this class is not itself within the scope of another class,
then we need to parse the bodies of all of the queued function
definitions. Note that the queued functions defined in a class
are not always processed immediately following the
class-specifier for that class. Consider:
struct A {
struct B { void f() { sizeof (A); } };
};
If `f' were processed before the processing of `A' were
completed, there would be no way to compute the size of `A'.
Note that the nesting we are interested in here is lexical --
not the semantic nesting given by TYPE_CONTEXT. In particular,
for:
struct A { struct B; };
struct A::B { void f() { } };
there is no need to delay the parsing of `A::B::f'. */
I think this logic breaks down with instantiations: probably the DEFAULT_ARG
nodes (representing an unparsed default argument) are copied from B<T> (generic
template) into B<int> (implicit specialization created by instantiation), and
never reparsed after that (in fact, I can't see how they could be put within
parser->unparser_function_queue, which is private of the parser).
I did not check whether this is a regression or not.
(In reply to comment #7)
> There is some code which also delays inner functions until the outer function
> is finished:
Of course I meant "classes": "There is some code which also delays inner
classes until the outer class is finished".
I would like to thank you folks at gcc.gnu.org for taking a serious look at
this issue.
I wanted to write here a little bit about what I do and how this matter came
to light. It is my occupation to write cross-platform applications that run on
Linux, Solaris, and Windows operating systems. When I was developing my code,
I started coding and compiling it on the Microsoft compiler first. I did not
get any compiler errors from my code and was happy that it was correct. Then
when I tried compiling it using GCC, I started getting the compile-time
errors. My first instinct was to go back to my code and fix it. I usually do
that because the Microsoft compiler isn’t as strict about the C++ language as
GCC is. But I stared at the code for about an hour and couldn’t figure out
what I was doing wrong.
Based on the error message that GCC gave me, "the default argument for
parameter 1 has not yet been parsed", I concluded that this might be a rare
case in which the GCC compiler got it wrong. I base that conclusion on the
fact that the error message from GCC implies a sense of incompleteness in the
class definition, and hence cannot generate object code. But the fact that the
Microsoft compiler can begin generating code indicates that there is enough
information there to begin instantiating the objects. I figured GCC should
also be able to do the same with what was given.
Here at AppSecInc, where I work, we also tried the same tests with the ICC
compiler and got the same results that Andrew Pinski mentioned. That actually
surprised me at first, but then I couldn’t help but draw some conclusions
about it. Intel is a hardware manufacturer, and not a compiler developer. I
can’t help but believe that Intel didn’t want to re-invent the whole wheel,
and therefore borrowed the open-source parser that the folks at GCC created.
These opinions are solely my own.
Thank you,
-Sid Sacek
Dear Giovanni Bajo,
Thank you for that detailed explanation. Based on what you said, it sounds
like a complex problem to solve; however, it may not be as difficult as it
first appears. Take the example below, which was already shown to us by
Wolfgang Bangerth. Compile it, and GCC is happy. Then remove the comment from
line 5, and GCC becomes unhappy. Mysterious! With line 5 commented out, GCC
believes that everything is complete. But add line 5 back into the equation,
and GCC believes that things are now incomplete. The Derived structure is in
itself complete too, and judging by this behavior of GCC, my approach to
solving the mystery would be to find out why a class like ‘struct Base’, which
was once complete, changes its status to incomplete by merely adding
the ‘Derived’ struct. Of course, I’m assuming that the Base struct is being
parsed before the Derived struct.
Understanding the reason why the status change occurs should help in knowing
whether this is an easy or difficult thing to change.
Regards,
-Sid Sacek
struct O {
template<typename T> struct Base {
void set (T, bool=true);
};
// struct Derived : public Base<int> {};
};
void x ()
{
O::Base<int> b;
b.set(1);
}
ug. This looks like a defect in the std. As has been pointed out, we cannot
parse the default argument until the outer class is complete -- because the
default argument of the nested class can legitimately call or access a static
member of the outer class that happens to be declared after the nested class.
However after the definition of the nested class, that template is complete
according to the language, and should therefore be instantiable. When
instantiating it, we have to instantiate the declarations of all its member
functions [14.7.1]. Aha! 'but not ... the default arguments'. Default arguments
are implicitly instantiated 'when the function is called in a context that
requires the value of that default argument'.
So, we need to remember we're instantiating a function declaration containing an
unparsed default arg -- and then DTRT when the arg gets parsed.
This isn't a regression (is it?), so won't be fixed until 4.1 is released.
Description Sid Sacek 2005-06-03 20:13:11 UTC
Compile the test program below using this command line: g++ test.cpp The code below fails to compile, and gives the following error message: -bash-3.00$ g++ test.cpp test.cpp: In member function `void Test::cell_test()': test.cpp:36: error: the default argument for parameter 1 of `void Test::Cell_base<Type>::set(Type, bool) [with Type = const char*]' has not yet been parsed class Test { protected: template< typename Type > class Cell_base { protected: bool m_relevance; Type m_field; public: Cell_base (void) // the constructor : m_relevance( false ), m_field( Type() ) { } // the setter void set (Type value, bool relevance = true) { m_relevance = relevance; m_field = value; } }; class Cell : public Cell_base< const char * > { }; public: //-------------------------------------------------- // Test out the cell classes //-------------------------------------------------- void cell_test (void) { Cell c; c.set( " To be or not to be \n\n" ); } }; //------------------------------ // Main - program entry //------------------------------ int main (int argc, char **argv) { Test t; t.cell_test(); return 0; }Comment 1 Andrew Pinski 2005-06-03 20:22:36 UTC
This is invalid code and the error is correct. The default argument has not been parsed at the point you called it. ICC and Comeau gives a slightly different error message which I think is misleading: "ComeauTest.c", line 35: error: too few arguments in function call c.set( " To be or not to be \n\n" );Comment 2 Wolfgang Bangerth 2005-06-03 21:51:43 UTC
Here's the same testcase again, but shorter: ------------------------------- struct O { template<typename T> struct B { void set (T, bool=true); }; struct D : public B<int> {}; }; void x () { O::D d; d.set(1); } ------------------------------- g/x> /home/bangerth/bin/gcc-3.4.4-pre/bin/c++ -c x.cc x.cc: In function `void x()': x.cc:12: error: the default argument for parameter 1 of `void O::B<T>::set(T, bool) [with T = int]' has not yet been parsed Even if the error is justified, I must admit that I still don't understand what exactly is going on: everything has been parsed by the time we call d.set!? What exactly is going on? We should be giving a better explanation, and in addition someone might want to give me a better explanation as well. As a different problem: in the message, the argument should be counted from one, not zero -- I know C++ programmers like to count starting at zero, but the second argument will usually still be referred as 'argument 2', not 1. W.Comment 3 Andrew Pinski 2005-06-03 22:03:39 UTC
The error comes from: tree convert_default_arg (tree type, tree arg, tree fn, int parmnum) { /* If the ARG is an unparsed default argument expression, the conversion cannot be performed. */ if (TREE_CODE (arg) == DEFAULT_ARG) { error ("the default argument for parameter %d of %qD has " "not yet been parsed", parmnum + 1, fn); return error_mark_node; }Comment 4 Wolfgang Bangerth 2005-06-03 22:27:19 UTC
In private mail, I got another testcase that is even weirder: --------------------------- struct O { template<typename T> struct B { void set (T, bool=true); }; struct D : public B<int> {}; }; void x () { O::B<int> d; d.set(1); } ---------------------------- Note that now we allocate an object of type O::B<int>, and get the same error as before. The type O::D isn't used anywhere; however, if we comment out the line in which it is declared, the test suddenly starts to compile. What does confuse me, to be honest, is that icc shows the same behavior... Nathan, Giovanni? W.Comment 5 Andrew Pinski 2005-06-03 23:08:55 UTC
Comment 6 Wolfgang Bangerth 2005-06-04 04:37:34 UTC
Comment 7 Giovanni Bajo 2005-06-04 10:46:14 UTC
I can't find anything in the standard which says that this should be an error, regardless of what Comeau does. This looks like a genuine bug in the parser, see parser.c:cp_parser_class_specifier: the parsing of the body of the in- classe defined functions and default arguments is delayed until the whole class definition is parsed (this allows, eg., the body of in-class member functions to refer to other member functions which appear later within the struct definition). There is some code which also delays inner functions until the outer function is finished: /* If this class is not itself within the scope of another class, then we need to parse the bodies of all of the queued function definitions. Note that the queued functions defined in a class are not always processed immediately following the class-specifier for that class. Consider: struct A { struct B { void f() { sizeof (A); } }; }; If `f' were processed before the processing of `A' were completed, there would be no way to compute the size of `A'. Note that the nesting we are interested in here is lexical -- not the semantic nesting given by TYPE_CONTEXT. In particular, for: struct A { struct B; }; struct A::B { void f() { } }; there is no need to delay the parsing of `A::B::f'. */ I think this logic breaks down with instantiations: probably the DEFAULT_ARG nodes (representing an unparsed default argument) are copied from B<T> (generic template) into B<int> (implicit specialization created by instantiation), and never reparsed after that (in fact, I can't see how they could be put within parser->unparser_function_queue, which is private of the parser). I did not check whether this is a regression or not.Comment 8 Giovanni Bajo 2005-06-04 10:48:17 UTC
Comment 9 Sid Sacek 2005-06-04 18:28:03 UTC
Comment 10 Sid Sacek 2005-06-04 19:17:33 UTC
Dear Giovanni Bajo, Thank you for that detailed explanation. Based on what you said, it sounds like a complex problem to solve; however, it may not be as difficult as it first appears. Take the example below, which was already shown to us by Wolfgang Bangerth. Compile it, and GCC is happy. Then remove the comment from line 5, and GCC becomes unhappy. Mysterious! With line 5 commented out, GCC believes that everything is complete. But add line 5 back into the equation, and GCC believes that things are now incomplete. The Derived structure is in itself complete too, and judging by this behavior of GCC, my approach to solving the mystery would be to find out why a class like ‘struct Base’, which was once complete, changes its status to incomplete by merely adding the ‘Derived’ struct. Of course, I’m assuming that the Base struct is being parsed before the Derived struct. Understanding the reason why the status change occurs should help in knowing whether this is an easy or difficult thing to change. Regards, -Sid Sacek struct O { template<typename T> struct Base { void set (T, bool=true); }; // struct Derived : public Base<int> {}; }; void x () { O::Base<int> b; b.set(1); }Comment 11 Nathan Sidwell 2005-06-06 09:34:54 UTC
Comment 12 Giovanni Bajo 2005-06-06 09:45:24 UTC
Comment 13 Wolfgang Bangerth 2005-06-06 14:27:52 UTC
Comment 14 Wolfgang Bangerth 2005-06-06 14:28:42 UTC
Comment 16 Nathan Sidwell 2005-06-06 17:30:47 UTC
Comment 18 Nathan Sidwell 2005-06-09 07:47:13 UTC
Comment 19 Mark Mitchell 2005-07-06 17:02:20 UTC
Comment 20 Nathan Sidwell 2005-07-12 11:27:41 UTC
Comment 22 Andrew Pinski 2005-08-15 12:00:01 UTC