diff options
-rw-r--r-- | gcc/cp/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/cp/parser.c | 42 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 3 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp1y/pr60390.C | 26 |
4 files changed, 70 insertions, 9 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a240ad9..3cf6858 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,13 @@ 2014-03-17 Adam Butcher <adam@jessamine.co.uk> + PR c++/60390 + * parser.c (cp_parser_member_declaration): Don't allow + finish_fully_implicit_template to consider friend declarations to be + class member templates. + (synthesize_implicit_template_parm): Handling winding back through class + scope to the class being defined in order to inject a template argument + list. + PR c++/60391 * parser.c (cp_parser_skip_to_end_of_block_or_statement): Unwind generic function scope as per cp_parser_skip_to_end_of_statement. diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 519e209..46e2453 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -20527,8 +20527,13 @@ cp_parser_member_declaration (cp_parser* parser) decl = grokfield (declarator, &decl_specifiers, initializer, /*init_const_expr_p=*/true, asm_specification, attributes); - if (parser->fully_implicit_function_template_p) - decl = finish_fully_implicit_template (parser, decl); + if (parser->fully_implicit_function_template_p) + { + if (friend_p) + finish_fully_implicit_template (parser, 0); + else + decl = finish_fully_implicit_template (parser, decl); + } } cp_finalize_omp_declare_simd (parser, decl); @@ -31982,13 +31987,32 @@ synthesize_implicit_template_parm (cp_parser *parser) parent_scope = scope; scope = scope->level_chain; } - if (current_class_type && !LAMBDA_TYPE_P (current_class_type) - && parser->num_classes_being_defined == 0) - while (scope->kind == sk_class) - { - parent_scope = scope; - scope = scope->level_chain; - } + if (current_class_type && !LAMBDA_TYPE_P (current_class_type)) + { + /* If not defining a class, then any class scope is a scope level in + an out-of-line member definition. In this case simply wind back + beyond the first such scope to inject the template argument list. + Otherwise wind back to the class being defined. The latter can + occur in class member friend declarations such as: + + class A { + void foo (auto); + }; + class B { + friend void A::foo (auto); + }; + + The template argument list synthesized for the friend declaration + must be injected in the scope of 'B', just beyond the scope of 'A' + introduced by 'A::'. */ + + while (scope->kind == sk_class + && !TYPE_BEING_DEFINED (scope->this_entity)) + { + parent_scope = scope; + scope = scope->level_chain; + } + } current_binding_level = scope; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index a327e94..49bc001 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,8 @@ 2014-03-17 Adam Butcher <adam@jessamine.co.uk> + PR c++/60390 + * g++.dg/cpp1y/pr60390.C: New testcase. + PR c++/60391 * g++.dg/cpp1y/pr60391.C: New testcase. diff --git a/gcc/testsuite/g++.dg/cpp1y/pr60390.C b/gcc/testsuite/g++.dg/cpp1y/pr60390.C new file mode 100644 index 0000000..5cd5539 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/pr60390.C @@ -0,0 +1,26 @@ +// PR c++/60390 +// { dg-do compile { target c++1y } } +// { dg-options "" } + +struct A +{ + void foo (auto); +}; + +class B +{ + int m; + friend void A::foo (auto); +}; + +void A::foo (auto i) +{ + B b; + b.m = i; +} + +int main () +{ + A a; + a.foo (7); +} |