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" );
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; }
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.
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.
Not a regression.
Sure it is a regression: gcc3.3.x compiles it just fine, and so does 3.2.x. gcc2.95 ICES, and from 3.4 onward we have the present error. W.
My last message refers to the code snippet in comment #4. W.
Subject: Bug 21903 CVSROOT: /cvs/gcc Module name: gcc Changes by: nathan@gcc.gnu.org 2005-06-06 17:29:41 Modified files: gcc/cp : ChangeLog cp-tree.def parser.c pt.c gcc/testsuite : ChangeLog Added files: gcc/testsuite/g++.dg/parse: defarg9.C Log message: cp: PR 21903 * cp-tree.def (DEFAULT_ARG): Document TREE_CHAIN use. * parser.c (cp_parser_late_parsing_default_args): Propagate parsed argument to any early instantiations. * pt.c (tsubst_arg_types): Chain early instantiation of default arg. testsuite: PR 21903 * g++.dg/parse/defarg9.C: New. Patches: http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/ChangeLog.diff?cvsroot=gcc&r1=1.4777&r2=1.4778 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/cp-tree.def.diff?cvsroot=gcc&r1=1.102&r2=1.103 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/parser.c.diff?cvsroot=gcc&r1=1.336&r2=1.337 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/pt.c.diff?cvsroot=gcc&r1=1.1001&r2=1.1002 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/ChangeLog.diff?cvsroot=gcc&r1=1.5602&r2=1.5603 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/parse/defarg9.C.diff?cvsroot=gcc&r1=NONE&r2=1.1
Fixed mainline 2005-06-06 Nathan Sidwell <nathan@codesourcery.com> PR 21903 * cp-tree.def (DEFAULT_ARG): Document TREE_CHAIN use. * parser.c (cp_parser_late_parsing_default_args): Propagate parsed argument to any early instantiations. * pt.c (tsubst_arg_types): Chain early instantiation of default arg. 2005-06-06 Nathan Sidwell <nathan@codesourcery.com> PR 21903 * g++.dg/parse/defarg9.C: New.
Subject: Bug 21903 CVSROOT: /cvs/gcc Module name: gcc Branch: gcc-3_4-branch Changes by: nathan@gcc.gnu.org 2005-06-09 07:46:23 Modified files: gcc/cp : ChangeLog cp-tree.def parser.c pt.c gcc/testsuite : ChangeLog gcc/testsuite/g++.old-deja/g++.oliva: template6.C Added files: gcc/testsuite/g++.dg/parse: local-class1.C defarg9.C gcc/testsuite/g++.dg/template: explicit6.C Log message: cp: PR c++/21903 * cp-tree.def (DEFAULT_ARG): Document TREE_CHAIN use. * parser.c (cp_parser_late_parsing_default_args): Propagate parsed argument to any early instantiations. * pt.c (tsubst_arg_types): Chain early instantiation of default arg. PR c++/19884 * pt.c (check_explicit_specialization): Make sure namespace binding lookup found an overloaded function. (lookup_template_function): Just assert FNS is an overloaded function. testsuite: PR c++/19608 * parser.c (cp_parser_late_parsing_for_member): Use current_function_decl as scope to push to and from. testsuite: PR 21903 * g++.dg/parse/defarg9.C: New. PR c++/19884 * g++.old-deja/g++.oliva/template6.C: Add another case. * g++.dg/template/explicit6.C: New. PR c++/19608 * g++.dg/parse/local-class1.C: New. Patches: http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/ChangeLog.diff?cvsroot=gcc&only_with_tag=gcc-3_4-branch&r1=1.3892.2.223&r2=1.3892.2.224 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/cp-tree.def.diff?cvsroot=gcc&only_with_tag=gcc-3_4-branch&r1=1.80&r2=1.80.10.1 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/parser.c.diff?cvsroot=gcc&only_with_tag=gcc-3_4-branch&r1=1.157.2.56&r2=1.157.2.57 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/pt.c.diff?cvsroot=gcc&only_with_tag=gcc-3_4-branch&r1=1.816.2.54&r2=1.816.2.55 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/ChangeLog.diff?cvsroot=gcc&only_with_tag=gcc-3_4-branch&r1=1.3389.2.403&r2=1.3389.2.404 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/parse/local-class1.C.diff?cvsroot=gcc&only_with_tag=gcc-3_4-branch&r1=NONE&r2=1.1.28.1 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/parse/defarg9.C.diff?cvsroot=gcc&only_with_tag=gcc-3_4-branch&r1=NONE&r2=1.1.2.1 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/template/explicit6.C.diff?cvsroot=gcc&only_with_tag=gcc-3_4-branch&r1=NONE&r2=1.1.28.1 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.old-deja/g++.oliva/template6.C.diff?cvsroot=gcc&only_with_tag=gcc-3_4-branch&r1=1.3&r2=1.3.16.1
Fixed on 3.4 2005-06-08 Nathan Sidwell <nathan@codesourcery.com> PR c++/21903 * cp-tree.def (DEFAULT_ARG): Document TREE_CHAIN use. * parser.c (cp_parser_late_parsing_default_args): Propagate parsed argument to any early instantiations. * pt.c (tsubst_arg_types): Chain early instantiation of default arg.
Postponed until 4.0.2.
applied to 4.0 branch
Subject: Bug 21903 CVSROOT: /cvs/gcc Module name: gcc Branch: gcc-4_0-branch Changes by: nathan@gcc.gnu.org 2005-07-12 11:28:03 Modified files: gcc/cp : ChangeLog class.c cp-tree.def cp-tree.h decl.c decl2.c error.c method.c parser.c pt.c semantics.c gcc/testsuite : ChangeLog gcc/testsuite/g++.dg/overload: error1.C gcc/testsuite/g++.dg/parse: crash11.C gcc/testsuite/g++.old-deja/g++.benjamin: warn02.C gcc/testsuite/g++.old-deja/g++.brendan: arm2.C gcc/testsuite/g++.old-deja/g++.other: redecl2.C redecl4.C gcc/testsuite/g++.old-deja/g++.pt: memtemp78.C Added files: gcc/testsuite/g++.dg/abi: covariant5.C gcc/testsuite/g++.dg/init: member1.C gcc/testsuite/g++.dg/other: crash-4.C gcc/testsuite/g++.dg/parse: crash26.C defarg9.C Log message: cp: PR c++/20678 * error.c (dump_expr) <COMPONENT_REF case>: Check DECL_NAME is not null. PR 21903 * cp-tree.def (DEFAULT_ARG): Document TREE_CHAIN use. * parser.c (cp_parser_late_parsing_default_args): Propagate parsed argument to any early instantiations. * pt.c (tsubst_arg_types): Chain early instantiation of default arg. PR c++/20789 * decl.c (cp_finish_decl): Clear runtime runtime initialization if in-class decl's initializer is bad. PR c++/21929 * parser.c (struct cp_parser): Document that scope could be error_mark. (cp_parser_diagnose_invalid_type_name): Cope with error_mark for scope. (cp_parser_nested_name_specifier): Return NULL_TREE on error. (cp_parser_postfix_expression): Deal with null or error_mark scope. (cp_parser_elaborated_type_specifier): Adjust cp_parser_nested_name_specifier call. PR c++/20746 * method.c (use_thunk): Protect covariant pointer return adjustments from NULL pointers. testsuite: PR c++/20678 * g++.dg/other/crash-4.C: New. PR 21903 * g++.dg/parse/defarg9.C: New. PR c++/21929 * g++.dg/parse/crash26.C: New. PR c++/20789 * g++.dg/init/member1.C: New. PR c++/20746 * g++.dg/abi/covariant5.C: New. Patches: http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/ChangeLog.diff?cvsroot=gcc&only_with_tag=gcc-4_0-branch&r1=1.4648.2.63&r2=1.4648.2.64 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/class.c.diff?cvsroot=gcc&only_with_tag=gcc-4_0-branch&r1=1.707.2.3&r2=1.707.2.4 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/cp-tree.def.diff?cvsroot=gcc&only_with_tag=gcc-4_0-branch&r1=1.94.4.2&r2=1.94.4.3 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/cp-tree.h.diff?cvsroot=gcc&only_with_tag=gcc-4_0-branch&r1=1.1106.2.8&r2=1.1106.2.9 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/decl.c.diff?cvsroot=gcc&only_with_tag=gcc-4_0-branch&r1=1.1371.2.14&r2=1.1371.2.15 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/decl2.c.diff?cvsroot=gcc&only_with_tag=gcc-4_0-branch&r1=1.770.2.2&r2=1.770.2.3 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/error.c.diff?cvsroot=gcc&only_with_tag=gcc-4_0-branch&r1=1.279.2.1&r2=1.279.2.2 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/method.c.diff?cvsroot=gcc&only_with_tag=gcc-4_0-branch&r1=1.322.4.4&r2=1.322.4.5 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/parser.c.diff?cvsroot=gcc&only_with_tag=gcc-4_0-branch&r1=1.319.2.10&r2=1.319.2.11 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/pt.c.diff?cvsroot=gcc&only_with_tag=gcc-4_0-branch&r1=1.978.2.12&r2=1.978.2.13 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/semantics.c.diff?cvsroot=gcc&only_with_tag=gcc-4_0-branch&r1=1.463.2.4&r2=1.463.2.5 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/ChangeLog.diff?cvsroot=gcc&only_with_tag=gcc-4_0-branch&r1=1.5084.2.268&r2=1.5084.2.269 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/abi/covariant5.C.diff?cvsroot=gcc&only_with_tag=gcc-4_0-branch&r1=NONE&r2=1.1.10.1 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/init/member1.C.diff?cvsroot=gcc&only_with_tag=gcc-4_0-branch&r1=NONE&r2=1.1.10.1 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/other/crash-4.C.diff?cvsroot=gcc&only_with_tag=gcc-4_0-branch&r1=NONE&r2=1.1.8.1 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/overload/error1.C.diff?cvsroot=gcc&only_with_tag=gcc-4_0-branch&r1=1.2&r2=1.2.112.1 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/parse/crash26.C.diff?cvsroot=gcc&only_with_tag=gcc-4_0-branch&r1=NONE&r2=1.1.8.1 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/parse/defarg9.C.diff?cvsroot=gcc&only_with_tag=gcc-4_0-branch&r1=NONE&r2=1.1.10.1 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/parse/crash11.C.diff?cvsroot=gcc&only_with_tag=gcc-4_0-branch&r1=1.4&r2=1.4.28.1 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.old-deja/g++.benjamin/warn02.C.diff?cvsroot=gcc&only_with_tag=gcc-4_0-branch&r1=1.4&r2=1.4.76.1 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.old-deja/g++.brendan/arm2.C.diff?cvsroot=gcc&only_with_tag=gcc-4_0-branch&r1=1.3&r2=1.3.76.1 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.old-deja/g++.other/redecl2.C.diff?cvsroot=gcc&only_with_tag=gcc-4_0-branch&r1=1.3&r2=1.3.76.1 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.old-deja/g++.other/redecl4.C.diff?cvsroot=gcc&only_with_tag=gcc-4_0-branch&r1=1.2&r2=1.2.76.1 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.old-deja/g++.pt/memtemp78.C.diff?cvsroot=gcc&only_with_tag=gcc-4_0-branch&r1=1.3&r2=1.3.76.1
*** Bug 23395 has been marked as a duplicate of this bug. ***